Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

898 lines
26 KiB

  1. //
  2. // RANGE.CPP
  3. //
  4. // 2-20-96: (EricAn)
  5. // Hacked from the Route66 source tree, eliminated stuff we don't use.
  6. // Original copyright below - where did this thing come from?
  7. //
  8. // -*- C -*-
  9. //
  10. // Copyright 1992 Software Innovations, Inc.
  11. //
  12. // $Source: D:\CLASS\SOURCE\range.c-v $
  13. // $Author: martin $
  14. // $Date: 92/07/15 05:09:24 $
  15. // $Revision: 1.1 $
  16. //
  17. //
  18. #include "pch.hxx"
  19. #include "range.h"
  20. #include "dllmain.h"
  21. #include <shlwapi.h>
  22. // QUANTUM defines the number of m_rangeTable cells to be allocated at
  23. // one time. Whenever the m_rangeTable becomes full, it is expanded
  24. // by QUANTUM range cells. m_rangeTable's never shrink.
  25. const int QUANTUM = 64;
  26. inline int inRange(RangeType r, ULONG x) { return ((x>=r.low) && (x<=r.high)); };
  27. CRangeList::CRangeList()
  28. {
  29. DllAddRef();
  30. m_numRanges = 0;
  31. m_rangeTableSize = 0;
  32. m_rangeTable = NULL;
  33. m_lRefCount = 1;
  34. }
  35. CRangeList::~CRangeList()
  36. {
  37. Assert(0 == m_lRefCount);
  38. if (m_rangeTable)
  39. MemFree(m_rangeTable);
  40. DllRelease();
  41. }
  42. HRESULT STDMETHODCALLTYPE CRangeList::QueryInterface(REFIID iid, void **ppvObject)
  43. {
  44. HRESULT hrResult;
  45. Assert(m_lRefCount > 0);
  46. Assert(NULL != ppvObject);
  47. // Init variables, check the arguments
  48. hrResult = E_NOINTERFACE;
  49. if (NULL == ppvObject)
  50. goto exit;
  51. *ppvObject = NULL;
  52. // Find a ptr to the interface
  53. if (IID_IUnknown == iid)
  54. *ppvObject = (IUnknown *) this;
  55. if (IID_IRangeList == iid)
  56. *ppvObject = (IRangeList *) this;
  57. // If we returned an interface, AddRef it
  58. if (NULL != *ppvObject) {
  59. ((IUnknown *)*ppvObject)->AddRef();
  60. hrResult = S_OK;
  61. }
  62. exit:
  63. return hrResult;
  64. } // QueryInterface
  65. //***************************************************************************
  66. // Function: AddRef
  67. //
  68. // Purpose:
  69. // This function should be called whenever someone makes a copy of a
  70. // pointer to this object. It bumps the reference count so that we know
  71. // there is one more pointer to this object, and thus we need one more
  72. // release before we delete ourselves.
  73. //
  74. // Returns:
  75. // A ULONG representing the current reference count. Although technically
  76. // our reference count is signed, we should never return a negative number,
  77. // anyways.
  78. //***************************************************************************
  79. ULONG STDMETHODCALLTYPE CRangeList::AddRef(void)
  80. {
  81. Assert(m_lRefCount > 0);
  82. m_lRefCount += 1;
  83. DOUT ("CRangeList::AddRef, returned Ref Count=%ld", m_lRefCount);
  84. return m_lRefCount;
  85. } // AddRef
  86. //***************************************************************************
  87. // Function: Release
  88. //
  89. // Purpose:
  90. // This function should be called when a pointer to this object is to
  91. // go out of commission. It knocks the reference count down by one, and
  92. // automatically deletes the object if we see that nobody has a pointer
  93. // to this object.
  94. //
  95. // Returns:
  96. // A ULONG representing the current reference count. Although technically
  97. // our reference count is signed, we should never return a negative number,
  98. // anyways.
  99. //***************************************************************************
  100. ULONG STDMETHODCALLTYPE CRangeList::Release(void)
  101. {
  102. Assert(m_lRefCount > 0);
  103. m_lRefCount -= 1;
  104. DOUT("CRangeList::Release, returned Ref Count = %ld", m_lRefCount);
  105. if (0 == m_lRefCount) {
  106. delete this;
  107. return 0;
  108. }
  109. else
  110. return m_lRefCount;
  111. } // Release
  112. HRESULT STDMETHODCALLTYPE CRangeList::IsInRange(const ULONG value)
  113. {
  114. Assert(m_lRefCount > 0);
  115. for (int i=0; i<m_numRanges; i++)
  116. if (inRange(m_rangeTable[i], value))
  117. return S_OK;
  118. return S_FALSE;
  119. }
  120. HRESULT STDMETHODCALLTYPE CRangeList::MinOfRange(const ULONG value,
  121. ULONG *pulMinOfRange)
  122. {
  123. Assert(m_lRefCount > 0);
  124. Assert(NULL != pulMinOfRange);
  125. *pulMinOfRange = RL_RANGE_ERROR;
  126. if (RL_RANGE_ERROR == value)
  127. return S_OK; // No need to loop through the ranges
  128. for (register int i=0; i<m_numRanges; i++) {
  129. if (inRange(m_rangeTable[i], value)) {
  130. *pulMinOfRange = m_rangeTable[i].low;
  131. break;
  132. } // if
  133. } // for
  134. return S_OK;
  135. }
  136. HRESULT STDMETHODCALLTYPE CRangeList::MaxOfRange(const ULONG value,
  137. ULONG *pulMaxOfRange)
  138. {
  139. Assert(m_lRefCount > 0);
  140. Assert(NULL != pulMaxOfRange);
  141. *pulMaxOfRange = RL_RANGE_ERROR;
  142. if (RL_RANGE_ERROR == value)
  143. return S_OK; // No need to loop through the ranges
  144. for (register int i=0; i<m_numRanges; i++) {
  145. if (inRange(m_rangeTable[i], value)) {
  146. *pulMaxOfRange = m_rangeTable[i].high;
  147. break;
  148. } // if
  149. } // for
  150. return S_OK;
  151. }
  152. HRESULT STDMETHODCALLTYPE CRangeList::Max(ULONG *pulMax)
  153. {
  154. Assert(m_lRefCount > 0);
  155. Assert(NULL != pulMax);
  156. if (m_numRanges==0)
  157. *pulMax = RL_RANGE_ERROR;
  158. else
  159. *pulMax = m_rangeTable[m_numRanges-1].high;
  160. return S_OK;
  161. }
  162. HRESULT STDMETHODCALLTYPE CRangeList::Min(ULONG *pulMin)
  163. {
  164. Assert(m_lRefCount > 0);
  165. Assert(NULL != pulMin);
  166. if (m_numRanges==0)
  167. *pulMin = RL_RANGE_ERROR;
  168. else
  169. *pulMin = m_rangeTable[0].low;
  170. return S_OK;
  171. }
  172. HRESULT STDMETHODCALLTYPE CRangeList::Save(LPBYTE *ppb, ULONG *pcb)
  173. {
  174. Assert(m_lRefCount > 0);
  175. Assert(ppb);
  176. Assert(pcb);
  177. *pcb = m_numRanges * sizeof(RangeType);
  178. if (*pcb)
  179. {
  180. if (!MemAlloc((LPVOID*)ppb, *pcb))
  181. return E_OUTOFMEMORY;
  182. CopyMemory(*ppb, m_rangeTable, *pcb);
  183. }
  184. else
  185. *ppb = NULL;
  186. return S_OK;
  187. }
  188. HRESULT STDMETHODCALLTYPE CRangeList::Load(LPBYTE pb, const ULONG cb)
  189. {
  190. Assert(m_lRefCount > 0);
  191. m_numRanges = m_rangeTableSize = cb / sizeof(RangeType);
  192. if (m_rangeTable)
  193. MemFree(m_rangeTable);
  194. m_rangeTable = (RangeType *)pb;
  195. return S_OK;
  196. }
  197. HRESULT STDMETHODCALLTYPE CRangeList::AddSingleValue(const ULONG value)
  198. {
  199. Assert(m_lRefCount > 0);
  200. RangeType r = { value, value };
  201. return AddRangeType(r);
  202. }
  203. HRESULT STDMETHODCALLTYPE CRangeList::AddRange(const ULONG low, const ULONG high)
  204. {
  205. Assert(m_lRefCount > 0);
  206. RangeType r = { low, high };
  207. return AddRangeType(r);
  208. }
  209. HRESULT STDMETHODCALLTYPE CRangeList::AddRangeList(const IRangeList *prl)
  210. {
  211. Assert(m_lRefCount > 0);
  212. AssertSz(FALSE, "Not implemented, probably never will be");
  213. return E_NOTIMPL;
  214. }
  215. HRESULT CRangeList::AddRangeType(const RangeType range)
  216. {
  217. int possibleLoc;
  218. int insertPosition;
  219. Assert(m_lRefCount > 0);
  220. if (range.low > range.high)
  221. {
  222. DOUTL(2, "Empty range passed to AddRange()");
  223. return E_INVALIDARG;
  224. }
  225. if (m_numRanges==0)
  226. {
  227. if (m_rangeTableSize == 0)
  228. if (!Expand())
  229. return E_OUTOFMEMORY;
  230. m_numRanges = 1;
  231. CopyMemory(&m_rangeTable[0], &range, sizeof(RangeType));
  232. }
  233. else
  234. {
  235. possibleLoc = BinarySearch(range.low);
  236. if (!((possibleLoc > -1) &&
  237. (inRange(m_rangeTable[possibleLoc], range.low)) &&
  238. (inRange(m_rangeTable[possibleLoc], range.high))))
  239. {
  240. insertPosition = possibleLoc + 1;
  241. if (m_numRanges == m_rangeTableSize)
  242. if (!Expand())
  243. return E_OUTOFMEMORY;
  244. ShiftRight(insertPosition, 1);
  245. CopyMemory(&m_rangeTable[insertPosition], &range, sizeof(RangeType));
  246. if (insertPosition > 0)
  247. SubsumeDown(insertPosition);
  248. if (insertPosition < m_numRanges)
  249. SubsumeUpwards(insertPosition);
  250. }
  251. }
  252. return S_OK;
  253. }
  254. HRESULT STDMETHODCALLTYPE CRangeList::DeleteSingleValue(const ULONG value)
  255. {
  256. Assert(m_lRefCount > 0);
  257. RangeType r = { value, value };
  258. return DeleteRangeType(r);
  259. }
  260. HRESULT STDMETHODCALLTYPE CRangeList::DeleteRange(const ULONG low, const ULONG high)
  261. {
  262. Assert(m_lRefCount > 0);
  263. RangeType r = { low, high };
  264. return DeleteRangeType(r);
  265. }
  266. HRESULT STDMETHODCALLTYPE CRangeList::DeleteRangeList(const IRangeList *prl)
  267. {
  268. Assert(m_lRefCount > 0);
  269. AssertSz(FALSE, "Not implemented, probably never will be");
  270. return E_NOTIMPL;
  271. }
  272. HRESULT CRangeList::DeleteRangeType(const RangeType range)
  273. {
  274. int lowEndChange;
  275. int highEndChange;
  276. Assert(m_lRefCount > 0);
  277. if (range.low > range.high)
  278. {
  279. DOUTL(2, "Empty range passed to DeleteRange()");
  280. return E_INVALIDARG;
  281. }
  282. lowEndChange = BinarySearch(range.low);
  283. highEndChange = BinarySearch(range.high);
  284. if ((lowEndChange != -1) && (highEndChange == lowEndChange))
  285. {
  286. if (inRange(m_rangeTable[lowEndChange], range.low))
  287. {
  288. if (inRange(m_rangeTable[lowEndChange], range.high))
  289. {
  290. if ((m_rangeTable[lowEndChange].low == range.low) &&
  291. (m_rangeTable[lowEndChange].high == range.high))
  292. {
  293. if (lowEndChange == (m_numRanges-1))
  294. {
  295. m_numRanges--;
  296. }
  297. else
  298. {
  299. ShiftLeft(lowEndChange + 1, 1);
  300. }
  301. }
  302. else
  303. {
  304. if (m_rangeTable[lowEndChange].low == range.low)
  305. {
  306. m_rangeTable[lowEndChange].low = range.high + 1;
  307. }
  308. else
  309. {
  310. if (m_rangeTable[lowEndChange].high == range.high)
  311. {
  312. Assert(range.low > 0);
  313. m_rangeTable[lowEndChange].high = range.low - 1;
  314. }
  315. else
  316. {
  317. // the range to be deleted is properly contained in
  318. // m_rangeTable[lowEndChange]
  319. if (m_numRanges == m_rangeTableSize)
  320. if (!Expand())
  321. return E_OUTOFMEMORY;
  322. ShiftRight(lowEndChange + 1, 1);
  323. m_rangeTable[lowEndChange + 1].low = range.high + 1;
  324. m_rangeTable[lowEndChange + 1].high = m_rangeTable[lowEndChange].high;
  325. Assert(range.low > 0);
  326. m_rangeTable[lowEndChange].high = range.low - 1;
  327. }
  328. }
  329. }
  330. }
  331. else
  332. {
  333. // range.low is in m_rangeTable[lowEndChange], but range.high
  334. // is not
  335. if (m_rangeTable[lowEndChange].low == range.low)
  336. {
  337. ShiftLeft(lowEndChange + 1, 1);
  338. }
  339. else
  340. {
  341. Assert(range.low > 0);
  342. m_rangeTable[lowEndChange].high = range.low - 1;
  343. }
  344. }
  345. } // of the cases where range.low actually in m_rangeTable[lowEndChange]
  346. }
  347. else
  348. { // of the cases where highEndChange == lowEndChange
  349. if (lowEndChange != -1)
  350. {
  351. if (inRange(m_rangeTable[lowEndChange], range.low))
  352. {
  353. if (range.low == m_rangeTable[lowEndChange].low)
  354. {
  355. lowEndChange = lowEndChange - 1;
  356. }
  357. else
  358. {
  359. Assert(range.low > 0);
  360. m_rangeTable[lowEndChange].high = range.low - 1;
  361. }
  362. }
  363. }
  364. if (highEndChange != -1)
  365. {
  366. if (inRange(m_rangeTable[highEndChange], range.high))
  367. {
  368. if (range.high == m_rangeTable[highEndChange].high)
  369. {
  370. highEndChange = highEndChange + 1;
  371. }
  372. else
  373. {
  374. m_rangeTable[highEndChange].low = range.high + 1;
  375. }
  376. }
  377. else
  378. {
  379. highEndChange++;
  380. }
  381. }
  382. if (!(lowEndChange > highEndChange))
  383. {
  384. // (0 <= lowEndChange < m_numRanges => m_rangeTable[lowEndChange] has received
  385. // any requisite adjustments and is to be kept)
  386. // and (0 <= highEndChange < m_numRanges => m_rangeTable[highEndChange]
  387. // has received any requistie adjs. and is a keeper)
  388. // and "forall" i [ lowEndChange < i < highEndChange =>
  389. // m_rangeTable[i] is to be overwritten]
  390. if (highEndChange >= m_numRanges)
  391. {
  392. m_numRanges = lowEndChange + 1;
  393. }
  394. else
  395. {
  396. if ((highEndChange - lowEndChange - 1) > 0)
  397. {
  398. ShiftLeft(highEndChange, (highEndChange-lowEndChange-1));
  399. }
  400. }
  401. } // else there's a problem with this code...
  402. }
  403. return S_OK;
  404. }
  405. HRESULT STDMETHODCALLTYPE CRangeList::Next(const ULONG current, ULONG *pulNext)
  406. {
  407. int loc;
  408. Assert(m_lRefCount > 0);
  409. Assert(NULL != pulNext);
  410. if (m_numRanges == 0)
  411. {
  412. *pulNext = RL_RANGE_ERROR;
  413. return S_OK;
  414. }
  415. if ((loc = BinarySearch(current)) == -1)
  416. {
  417. *pulNext = m_rangeTable[0].low;
  418. return S_OK;
  419. }
  420. else if (loc == (m_numRanges-1))
  421. {
  422. if (inRange(m_rangeTable[m_numRanges-1], current))
  423. {
  424. if (inRange(m_rangeTable[m_numRanges-1], current + 1))
  425. {
  426. *pulNext = current + 1;
  427. return S_OK;
  428. }
  429. else
  430. {
  431. *pulNext = RL_RANGE_ERROR;
  432. return S_OK;
  433. }
  434. }
  435. else
  436. {
  437. *pulNext = RL_RANGE_ERROR;
  438. return S_OK;
  439. }
  440. }
  441. else // case where loc == m_numRanges-1
  442. {
  443. // 1 <= loc < m_numRanges
  444. if (inRange(m_rangeTable[loc], current))
  445. {
  446. if (inRange(m_rangeTable[loc], current + 1))
  447. {
  448. *pulNext = current + 1;
  449. return S_OK;
  450. }
  451. else
  452. {
  453. *pulNext = m_rangeTable[loc + 1].low;
  454. return S_OK;
  455. }
  456. }
  457. else
  458. {
  459. *pulNext = m_rangeTable[loc + 1].low;
  460. return S_OK;
  461. }
  462. }
  463. }
  464. HRESULT STDMETHODCALLTYPE CRangeList::Prev(const ULONG current, ULONG *pulPrev)
  465. {
  466. int loc;
  467. Assert(m_lRefCount > 0);
  468. Assert(NULL != pulPrev);
  469. if (m_numRanges == 0)
  470. {
  471. *pulPrev = RL_RANGE_ERROR;
  472. return S_OK;
  473. }
  474. if ((loc = BinarySearch(current)) == -1)
  475. {
  476. *pulPrev = RL_RANGE_ERROR;
  477. return S_OK;
  478. }
  479. else if (loc == 0)
  480. {
  481. if (inRange(m_rangeTable[0], current))
  482. {
  483. if (current > 0 && inRange(m_rangeTable[0], current - 1))
  484. {
  485. *pulPrev = current - 1;
  486. return S_OK;
  487. }
  488. else
  489. {
  490. *pulPrev = RL_RANGE_ERROR;
  491. return S_OK;
  492. }
  493. }
  494. else
  495. {
  496. *pulPrev = m_rangeTable[0].high;
  497. return S_OK;
  498. }
  499. }
  500. else
  501. {
  502. // 1 < loc <= m_numRanges
  503. if (inRange(m_rangeTable[loc], current))
  504. {
  505. if (current > 0 && inRange(m_rangeTable[loc], current - 1))
  506. {
  507. *pulPrev = current - 1;
  508. return S_OK;
  509. }
  510. else
  511. {
  512. *pulPrev = m_rangeTable[loc-1].high;
  513. return S_OK;
  514. }
  515. }
  516. else
  517. {
  518. *pulPrev = m_rangeTable[loc].high;
  519. return S_OK;
  520. }
  521. }
  522. }
  523. HRESULT STDMETHODCALLTYPE CRangeList::Cardinality(ULONG *pulCardinality)
  524. {
  525. ULONG card = 0;
  526. Assert(m_lRefCount > 0);
  527. Assert(NULL != pulCardinality);
  528. for (int i=0 ; i<m_numRanges ; i++)
  529. card += (m_rangeTable[i].high - m_rangeTable[i].low + 1);
  530. *pulCardinality = card;
  531. return S_OK;
  532. }
  533. HRESULT STDMETHODCALLTYPE CRangeList::CardinalityFrom(const ULONG ulStartPoint,
  534. ULONG *pulCardinalityFrom)
  535. {
  536. ULONG ulNumMsgsInRange;
  537. int i;
  538. Assert(m_lRefCount > 0);
  539. Assert(NULL != pulCardinalityFrom);
  540. // Initialize variables
  541. ulNumMsgsInRange = 0;
  542. *pulCardinalityFrom = 0;
  543. // Find the range where ulStartPoint lives
  544. i = BinarySearch(ulStartPoint + 1);
  545. if (-1 == i || ulStartPoint > m_rangeTable[i].high)
  546. return S_OK; // ulStartPoint + 1 is not in the range
  547. // If ulStartPoint is at start or middle of range, add incomplete range to total
  548. if (ulStartPoint >= m_rangeTable[i].low &&
  549. ulStartPoint <= m_rangeTable[i].high) {
  550. // Add incomplete range to total - Don't include ulStartPoint!
  551. ulNumMsgsInRange += m_rangeTable[i].high - ulStartPoint;
  552. i += 1;
  553. }
  554. // Add the remaining WHOLE ranges
  555. for (; i < m_numRanges; i++)
  556. ulNumMsgsInRange += m_rangeTable[i].high - m_rangeTable[i].low + 1;
  557. *pulCardinalityFrom = ulNumMsgsInRange;
  558. return S_OK;
  559. } // Cardinality (with start point arg)
  560. int CRangeList::BinarySearch(const ULONG value) const
  561. {
  562. // We are looking for `value' in the m_rangeTable. If value is in the
  563. // set of valid ranges, we return the array subscript of the range
  564. // containing `value'. If `value' is not contained in any of the
  565. // ranges then return `loc' where
  566. // (0 <= loc < m_numRanges =>
  567. // (m_rangeTable[loc].low < rangeNum)
  568. // "and" (m_rangeTable[loc + 1].low > rangeNum))
  569. // "and" (loc = m_numRanges => rangeNum > m_rangeTable[m_numRanges].low)
  570. // "and" (loc = -1 => m_numRanges = 0
  571. // "or" rangeNum < m_rangeTable[0].low) }
  572. long low, high, mid;
  573. int loc = -1;
  574. Assert(m_lRefCount > 0);
  575. if (m_numRanges == 0)
  576. return -1;
  577. if (value < m_rangeTable[0].low)
  578. return -1;
  579. low = 0;
  580. high = m_numRanges - 1;
  581. while (low <= high) {
  582. // inv: low < high - 1, and if rngNum is any where in m_rangeTable, it is in
  583. // the range from m_rangeTable[low] to m_rangeTable[high]
  584. mid = (low + high) / 2;
  585. if ((value >= m_rangeTable[mid].low) &&
  586. ((mid == (m_numRanges-1)) || (value < m_rangeTable[mid + 1].low)))
  587. {
  588. loc = mid;
  589. high = low - 1;
  590. }
  591. else
  592. {
  593. if (value > m_rangeTable[mid].low)
  594. low = mid + 1;
  595. else
  596. high = mid - 1;
  597. }
  598. }
  599. return loc;
  600. }
  601. // Expand() will grow the m_rangeTable by QUANTUM range cells.
  602. BOOL CRangeList::Expand()
  603. {
  604. RangeType *newRangeTable;
  605. Assert(m_lRefCount > 0);
  606. if (!MemAlloc((LPVOID*)&newRangeTable, (m_rangeTableSize + QUANTUM) * sizeof(RangeType)))
  607. return FALSE;
  608. m_rangeTableSize += QUANTUM;
  609. if (m_rangeTable)
  610. {
  611. if (m_numRanges > 0)
  612. CopyMemory(newRangeTable, m_rangeTable, m_numRanges * sizeof(RangeType));
  613. MemFree(m_rangeTable);
  614. }
  615. m_rangeTable = newRangeTable;
  616. return TRUE;
  617. }
  618. void CRangeList::ShiftLeft(int low, int distance)
  619. {
  620. Assert(m_lRefCount > 0);
  621. if (m_numRanges - low)
  622. MoveMemory(&m_rangeTable[low-distance], &m_rangeTable[low], (m_numRanges-low)*sizeof(RangeType));
  623. m_numRanges -= distance;
  624. }
  625. void CRangeList::ShiftRight(int low, int distance)
  626. {
  627. Assert(m_lRefCount > 0);
  628. if (m_numRanges - low)
  629. MoveMemory(&m_rangeTable[low+distance], &m_rangeTable[low], (m_numRanges-low)*sizeof(RangeType));
  630. m_numRanges += distance;
  631. }
  632. // pre: (m_rangeTable[anchorPosition] has probably just been added to m_rangeTable.)
  633. // 1 <= anchorPosition <= m_numRanges
  634. // and ( anchorPosition = 1
  635. // or (m_rangeTable[anchorPosition].low >
  636. // m_rangeTable[anchorPosition - 1].high) )
  637. // post: No overlapping or contiguous ranges from 1 to m_numRanges. }
  638. void CRangeList::SubsumeUpwards(const int anchor)
  639. {
  640. int posOfLargerLow;
  641. int copyDownDistance;
  642. int copyPos;
  643. Assert(m_lRefCount > 0);
  644. posOfLargerLow = anchor + 1;
  645. while ((posOfLargerLow < m_numRanges) &&
  646. (m_rangeTable[posOfLargerLow].low <= m_rangeTable[anchor].high + 1))
  647. posOfLargerLow++;
  648. if (posOfLargerLow == m_numRanges)
  649. {
  650. if (m_rangeTable[m_numRanges-1].high > m_rangeTable[anchor].high)
  651. m_rangeTable[anchor].high = m_rangeTable[m_numRanges-1].high;
  652. m_numRanges = anchor + 1;
  653. }
  654. else
  655. {
  656. // posOfLargerLow now indexes the first element of m_rangeTable, looking from
  657. // m_rangeTable[anchor], with .low > m_rangeTable[anchor].high + 1
  658. if (posOfLargerLow > (anchor + 1))
  659. {
  660. if (m_rangeTable[posOfLargerLow - 1].high > m_rangeTable[anchor].high)
  661. m_rangeTable[anchor].high = m_rangeTable[posOfLargerLow - 1].high;
  662. copyDownDistance = posOfLargerLow - anchor - 1;
  663. copyPos = posOfLargerLow;
  664. while (copyPos < m_numRanges)
  665. {
  666. m_rangeTable[copyPos - copyDownDistance] = m_rangeTable[copyPos];
  667. copyPos = copyPos + 1;
  668. }
  669. m_numRanges -= copyDownDistance;
  670. }
  671. }
  672. }
  673. void CRangeList::SubsumeDown(int& anchor)
  674. {
  675. int posOfSmallerHigh;
  676. int copyDownDistance;
  677. int copyPos;
  678. Assert(m_lRefCount > 0);
  679. posOfSmallerHigh = anchor - 1;
  680. while ((posOfSmallerHigh >= 0) &&
  681. (m_rangeTable[posOfSmallerHigh].high + 1 >= m_rangeTable[anchor].low))
  682. {
  683. posOfSmallerHigh--;
  684. }
  685. if (posOfSmallerHigh < 0)
  686. {
  687. if (m_rangeTable[0].low < m_rangeTable[anchor].low)
  688. m_rangeTable[anchor].low = m_rangeTable[0].low;
  689. }
  690. // posOfSmallerHigh either has value 0 or subscripts the first element of
  691. // m_rangeTable, looking down from anchor, with a .high that is
  692. // less than m_rangeTable[anchor].low - 1.
  693. if (m_rangeTable[posOfSmallerHigh + 1].low < m_rangeTable[anchor].low)
  694. m_rangeTable[anchor].low = m_rangeTable[posOfSmallerHigh + 1].low;
  695. copyDownDistance = anchor - posOfSmallerHigh - 1;
  696. if (copyDownDistance > 0)
  697. {
  698. copyPos = anchor;
  699. while (copyPos < m_numRanges)
  700. {
  701. m_rangeTable[copyPos - copyDownDistance] = m_rangeTable[copyPos];
  702. copyPos++;
  703. }
  704. m_numRanges -= copyDownDistance;
  705. anchor -= copyDownDistance;
  706. }
  707. }
  708. //***************************************************************************
  709. // Function: RangeToIMAPString
  710. //
  711. // Purpose:
  712. // This function outputs the rangelist as an IMAP message set, suitable
  713. // for use in IMAP commands.
  714. //
  715. // Arguments:
  716. // LPSTR *ppszDestination [out] - an IMAP message set string is
  717. // returned here. It is the responsibility of the caller to CoTaskMemFree
  718. // this buffer when he is done with it. Pass in NULL if not interested.
  719. // LPDWORD pdwLengthOfDestination [out] - if successful, this function
  720. // returns the length of the IMAP msg set returned via pszDestination.
  721. // Pass in NULL if not interested.
  722. //
  723. // Returns:
  724. // HRESULT indicating success or failure.
  725. //***************************************************************************
  726. HRESULT STDMETHODCALLTYPE CRangeList::RangeToIMAPString(LPSTR *ppszDestination,
  727. LPDWORD pdwLengthOfDestination)
  728. {
  729. int i;
  730. BOOL bFirstRange;
  731. CByteStream bstmIMAPString;
  732. HRESULT hrResult;
  733. Assert(m_lRefCount > 0);
  734. // Initialize return values
  735. if (ppszDestination)
  736. *ppszDestination = NULL;
  737. if (pdwLengthOfDestination)
  738. *pdwLengthOfDestination = 0;
  739. hrResult = S_OK;
  740. bFirstRange = TRUE; // Suppress leading comma for first range
  741. for (i = 0; i < m_numRanges; i += 1) {
  742. char szTemp[128];
  743. int iLengthOfTemp;
  744. // Convert current range to string form
  745. if (m_rangeTable[i].low == m_rangeTable[i].high)
  746. iLengthOfTemp = wnsprintf(szTemp + 1, ARRAYSIZE(szTemp) - 1, "%lu", m_rangeTable[i].low);
  747. else
  748. iLengthOfTemp = wnsprintf(szTemp + 1, ARRAYSIZE(szTemp) - 1, "%lu:%lu", m_rangeTable[i].low, m_rangeTable[i].high);
  749. if (FALSE == bFirstRange) {
  750. szTemp[0] = ','; // Prepend a comma
  751. iLengthOfTemp += 1; // Include leading comma
  752. }
  753. // Append new range to destination buffer (with or without leading comma)
  754. hrResult = bstmIMAPString.Write(bFirstRange ? szTemp + 1 : szTemp,
  755. iLengthOfTemp, NULL);
  756. if (FAILED(hrResult))
  757. break;
  758. bFirstRange = FALSE;
  759. } // for
  760. if (SUCCEEDED(hrResult))
  761. hrResult = bstmIMAPString.HrAcquireStringA(pdwLengthOfDestination,
  762. ppszDestination, ACQ_DISPLACE);
  763. return hrResult;
  764. } // RangeToIMAPString