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.

1520 lines
39 KiB

  1. // Dynamic Array APIs
  2. #include "ctlspriv.h"
  3. //
  4. // Heapsort is a bit slower, but it doesn't use any stack or memory...
  5. // Mergesort takes a bit of memory (O(n)) and stack (O(log(n)), but very fast...
  6. //
  7. #define MERGESORT
  8. #ifdef DEBUG
  9. #define DSA_MAGIC ('S' | ('A' << 8))
  10. #define IsDSA(pdsa) ((pdsa) && (pdsa)->magic == DSA_MAGIC)
  11. #define DPA_MAGIC ('P' | ('A' << 8))
  12. #define IsDPA(pdpa) ((pdpa) && (pdpa)->magic == DPA_MAGIC)
  13. #else
  14. #define IsDSA(pdsa)
  15. #define IsDPA(pdsa)
  16. #endif
  17. typedef struct {
  18. void FAR* FAR* pp;
  19. PFNDPACOMPARE pfnCmp;
  20. LPARAM lParam;
  21. int cp;
  22. #ifdef MERGESORT
  23. void FAR* FAR* ppT;
  24. #endif
  25. } SORTPARAMS;
  26. BOOL NEAR DPA_QuickSort(SORTPARAMS FAR* psp);
  27. BOOL NEAR DPA_QuickSort2(int i, int j, SORTPARAMS FAR* psp);
  28. BOOL NEAR DPA_HeapSort(SORTPARAMS FAR* psp);
  29. void NEAR DPA_HeapSortPushDown(int first, int last, SORTPARAMS FAR* psp);
  30. BOOL NEAR DPA_MergeSort(SORTPARAMS FAR* psp);
  31. void NEAR DPA_MergeSort2(SORTPARAMS FAR* psp, int iFirst, int cItems);
  32. //========== Dynamic structure array ====================================
  33. // Dynamic structure array
  34. typedef struct _DSA {
  35. // NOTE: The following field MUST be defined at the beginning of the
  36. // structure in order for GetItemCount() to work.
  37. //
  38. int cItem; // # of elements in dsa
  39. void FAR* aItem; // memory for elements
  40. int cItemAlloc; // # items which fit in aItem
  41. int cbItem; // size of each item
  42. int cItemGrow; // # items to grow cItemAlloc by
  43. #ifdef DEBUG
  44. UINT magic;
  45. #endif
  46. } DSA;
  47. #define DSA_PITEM(pdsa, index) ((void FAR*)(((BYTE FAR*)(pdsa)->aItem) + ((index) * (pdsa)->cbItem)))
  48. #ifdef DEBUG
  49. #define BF_ONDAVALIDATE 0x00001000
  50. void DABreakFn(void)
  51. {
  52. if (IsFlagSet(g_dwBreakFlags, BF_ONDAVALIDATE))
  53. ASSERT(0);
  54. }
  55. #define DABreak() DABreakFn()
  56. #else
  57. #define DABreak()
  58. #endif
  59. HDSA WINAPI DSA_Create(int cbItem, int cItemGrow)
  60. {
  61. HDSA pdsa = Alloc(sizeof(DSA));
  62. ASSERT(cbItem);
  63. if (pdsa)
  64. {
  65. ASSERT(pdsa->cItem == 0);
  66. ASSERT(pdsa->cItemAlloc == 0);
  67. pdsa->cbItem = cbItem;
  68. pdsa->cItemGrow = (cItemGrow == 0 ? 1 : cItemGrow);
  69. ASSERT(pdsa->aItem == NULL);
  70. #ifdef DEBUG
  71. pdsa->magic = DSA_MAGIC;
  72. #endif
  73. }
  74. return pdsa;
  75. }
  76. BOOL WINAPI DSA_Destroy(HDSA pdsa)
  77. {
  78. if (pdsa == NULL) // allow NULL for low memory cases
  79. return TRUE;
  80. // Components rely on not having to check for NULL
  81. ASSERT(IsDSA(pdsa));
  82. #ifdef DEBUG
  83. pdsa->cItem = 0;
  84. pdsa->cItemAlloc = 0;
  85. pdsa->cbItem = 0;
  86. pdsa->magic = 0;
  87. #endif
  88. if (pdsa->aItem && !Free(pdsa->aItem))
  89. return FALSE;
  90. return Free(pdsa);
  91. }
  92. void WINAPI DSA_EnumCallback(HDSA pdsa, PFNDSAENUMCALLBACK pfnCB, LPVOID pData)
  93. {
  94. int i;
  95. if (!pdsa)
  96. return;
  97. ASSERT(IsDSA(pdsa));
  98. for (i = 0; i < pdsa->cItem; i++) {
  99. if (!pfnCB(DSA_GetItemPtr(pdsa, i), pData))
  100. break;
  101. }
  102. }
  103. void WINAPI DSA_DestroyCallback(HDSA pdsa, PFNDSAENUMCALLBACK pfnCB, LPVOID pData)
  104. {
  105. DSA_EnumCallback(pdsa, pfnCB, pData);
  106. DSA_Destroy(pdsa);
  107. }
  108. BOOL WINAPI DSA_GetItem(HDSA pdsa, int index, void FAR* pitem)
  109. {
  110. ASSERT(IsDSA(pdsa));
  111. ASSERT(pitem);
  112. if (index < 0 || index >= pdsa->cItem)
  113. {
  114. #ifdef DEBUG
  115. // Don't assert if index == pdsa->cItems as some clients simply want to walk the list and no need to call getcount...
  116. if (index != pdsa->cItem)
  117. {
  118. DebugMsg(DM_ERROR, TEXT("DSA: GetItem: Invalid index: %d"), index);
  119. DABreak();
  120. }
  121. #endif
  122. return FALSE;
  123. }
  124. hmemcpy(pitem, DSA_PITEM(pdsa, index), pdsa->cbItem);
  125. return TRUE;
  126. }
  127. void FAR* WINAPI DSA_GetItemPtr(HDSA pdsa, int index)
  128. {
  129. ASSERT(IsDSA(pdsa));
  130. if (index < 0 || index >= pdsa->cItem)
  131. {
  132. DebugMsg(DM_ERROR, TEXT("DSA: GetItemPtr: Invalid index: %d"), index);
  133. // DABreak(); // caller knows
  134. return NULL;
  135. }
  136. return DSA_PITEM(pdsa, index);
  137. }
  138. BOOL WINAPI DSA_SetItem(HDSA pdsa, int index, void FAR* pitem)
  139. {
  140. ASSERT(pitem);
  141. ASSERT(IsDSA(pdsa));
  142. if (index < 0)
  143. {
  144. DebugMsg(DM_ERROR, TEXT("DSA: SetItem: Invalid index: %d"), index);
  145. DABreak();
  146. return FALSE;
  147. }
  148. if (index >= pdsa->cItem)
  149. {
  150. if (index + 1 > pdsa->cItemAlloc)
  151. {
  152. int cItemAlloc = (((index + 1) + pdsa->cItemGrow - 1) / pdsa->cItemGrow) * pdsa->cItemGrow;
  153. void FAR* aItemNew = ReAlloc(pdsa->aItem, cItemAlloc * pdsa->cbItem);
  154. if (!aItemNew)
  155. return FALSE;
  156. pdsa->aItem = aItemNew;
  157. pdsa->cItemAlloc = cItemAlloc;
  158. }
  159. pdsa->cItem = index + 1;
  160. }
  161. hmemcpy(DSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
  162. return TRUE;
  163. }
  164. int WINAPI DSA_InsertItem(HDSA pdsa, int index, void FAR* pitem)
  165. {
  166. ASSERT(pitem);
  167. ASSERT(IsDSA(pdsa));
  168. if (index < 0)
  169. {
  170. DebugMsg(DM_ERROR, TEXT("DSA: InsertItem: Invalid index: %d"), index);
  171. DABreak();
  172. return -1;
  173. }
  174. if (index > pdsa->cItem)
  175. index = pdsa->cItem;
  176. if (pdsa->cItem + 1 > pdsa->cItemAlloc)
  177. {
  178. void FAR* aItemNew = ReAlloc(pdsa->aItem,
  179. (pdsa->cItemAlloc + pdsa->cItemGrow) * pdsa->cbItem);
  180. if (!aItemNew)
  181. return -1;
  182. pdsa->aItem = aItemNew;
  183. pdsa->cItemAlloc += pdsa->cItemGrow;
  184. }
  185. if (index < pdsa->cItem)
  186. {
  187. hmemcpy(DSA_PITEM(pdsa, index + 1), DSA_PITEM(pdsa, index),
  188. (pdsa->cItem - index) * pdsa->cbItem);
  189. }
  190. pdsa->cItem++;
  191. hmemcpy(DSA_PITEM(pdsa, index), pitem, pdsa->cbItem);
  192. return index;
  193. }
  194. BOOL WINAPI DSA_DeleteItem(HDSA pdsa, int index)
  195. {
  196. ASSERT(IsDSA(pdsa));
  197. if (index < 0 || index >= pdsa->cItem)
  198. {
  199. DebugMsg(DM_ERROR, TEXT("DSA: DeleteItem: Invalid index: %d"), index);
  200. DABreak();
  201. return FALSE;
  202. }
  203. if (index < pdsa->cItem - 1)
  204. {
  205. hmemcpy(DSA_PITEM(pdsa, index), DSA_PITEM(pdsa, index + 1),
  206. (pdsa->cItem - (index + 1)) * pdsa->cbItem);
  207. }
  208. pdsa->cItem--;
  209. if (pdsa->cItemAlloc - pdsa->cItem > pdsa->cItemGrow)
  210. {
  211. void FAR* aItemNew = ReAlloc(pdsa->aItem,
  212. (pdsa->cItemAlloc - pdsa->cItemGrow) * pdsa->cbItem);
  213. if (aItemNew)
  214. pdsa->aItem = aItemNew;
  215. else
  216. {
  217. // If the shrink fails, then just continue with the old (slightly
  218. // too big) allocation. Go ahead and let cItemAlloc decrease
  219. // so we don't keep trying to realloc smaller
  220. }
  221. pdsa->cItemAlloc -= pdsa->cItemGrow;
  222. }
  223. return TRUE;
  224. }
  225. BOOL WINAPI DSA_DeleteAllItems(HDSA pdsa)
  226. {
  227. ASSERT(IsDSA(pdsa));
  228. if (pdsa->aItem && !Free(pdsa->aItem))
  229. return FALSE;
  230. pdsa->aItem = NULL;
  231. pdsa->cItem = pdsa->cItemAlloc = 0;
  232. return TRUE;
  233. }
  234. //================== Dynamic pointer array implementation ===========
  235. typedef struct _DPA {
  236. // NOTE: The following two fields MUST be defined in this order, at
  237. // the beginning of the structure in order for the macro APIs to work.
  238. //
  239. int cp;
  240. void FAR* FAR* pp;
  241. HANDLE hheap; // Heap to allocate from if NULL use shared
  242. int cpAlloc;
  243. int cpGrow;
  244. #ifdef DEBUG
  245. UINT magic;
  246. #endif
  247. } DPA;
  248. HDPA WINAPI DPA_Create(int cpGrow)
  249. {
  250. return DPA_CreateEx(cpGrow, NULL);
  251. }
  252. // Should nuke the standard DPA above...
  253. HDPA WINAPI DPA_CreateEx(int cpGrow, HANDLE hheap)
  254. {
  255. HDPA pdpa;
  256. if (hheap == NULL)
  257. {
  258. hheap = GetProcessHeap();
  259. pdpa = ALLOC_NULLHEAP(hheap, sizeof(DPA));
  260. }
  261. else
  262. pdpa = ControlAlloc(hheap, sizeof(DPA));
  263. if (pdpa)
  264. {
  265. ASSERT(pdpa->cp == 0);
  266. ASSERT(pdpa->cpAlloc == 0);
  267. pdpa->cpGrow = (cpGrow < 8 ? 8 : cpGrow);
  268. ASSERT(pdpa->pp == NULL);
  269. pdpa->hheap = hheap;
  270. #ifdef DEBUG
  271. pdpa->magic = DPA_MAGIC;
  272. #endif
  273. }
  274. return pdpa;
  275. }
  276. BOOL WINAPI DPA_Destroy(HDPA pdpa)
  277. {
  278. if (pdpa == NULL) // allow NULL for low memory cases, still assert
  279. return TRUE;
  280. ASSERT(IsDPA(pdpa));
  281. ASSERT(pdpa->hheap);
  282. #ifdef DEBUG
  283. pdpa->cp = 0;
  284. pdpa->cpAlloc = 0;
  285. pdpa->magic = 0;
  286. #endif
  287. if (pdpa->pp && !ControlFree(pdpa->hheap, pdpa->pp))
  288. return FALSE;
  289. return ControlFree(pdpa->hheap, pdpa);
  290. }
  291. HDPA WINAPI DPA_Clone(HDPA pdpa, HDPA pdpaNew)
  292. {
  293. BOOL fAlloc = FALSE;
  294. if (!pdpaNew)
  295. {
  296. pdpaNew = DPA_CreateEx(pdpa->cpGrow, pdpa->hheap);
  297. if (!pdpaNew)
  298. return NULL;
  299. fAlloc = TRUE;
  300. }
  301. if (!DPA_Grow(pdpaNew, pdpa->cpAlloc)) {
  302. if (!fAlloc)
  303. DPA_Destroy(pdpaNew);
  304. return NULL;
  305. }
  306. pdpaNew->cp = pdpa->cp;
  307. hmemcpy(pdpaNew->pp, pdpa->pp, pdpa->cp * sizeof(void FAR*));
  308. return pdpaNew;
  309. }
  310. void FAR* WINAPI DPA_GetPtr(HDPA pdpa, INT_PTR index)
  311. {
  312. ASSERT(IsDPA(pdpa));
  313. if (!pdpa || index < 0 || index >= pdpa->cp)
  314. return NULL;
  315. return pdpa->pp[index];
  316. }
  317. int WINAPI DPA_GetPtrIndex(HDPA pdpa, void FAR* p)
  318. {
  319. void FAR* FAR* pp;
  320. void FAR* FAR* ppMax;
  321. ASSERT(IsDPA(pdpa));
  322. if (pdpa && pdpa->pp)
  323. {
  324. pp = pdpa->pp;
  325. ppMax = pp + pdpa->cp;
  326. for ( ; pp < ppMax; pp++)
  327. {
  328. if (*pp == p)
  329. return (int) (pp - pdpa->pp);
  330. }
  331. }
  332. return -1;
  333. }
  334. BOOL WINAPI DPA_Grow(HDPA pdpa, int cpAlloc)
  335. {
  336. ASSERT(IsDPA(pdpa));
  337. if (!pdpa)
  338. return FALSE;
  339. if (cpAlloc > pdpa->cpAlloc)
  340. {
  341. void FAR* FAR* ppNew;
  342. cpAlloc = ((cpAlloc + pdpa->cpGrow - 1) / pdpa->cpGrow) * pdpa->cpGrow;
  343. if (pdpa->pp)
  344. ppNew = (void FAR* FAR*)ControlReAlloc(pdpa->hheap, pdpa->pp, cpAlloc * sizeof(void FAR*));
  345. else
  346. ppNew = (void FAR* FAR*)ControlAlloc(pdpa->hheap, cpAlloc * sizeof(void FAR*));
  347. if (!ppNew)
  348. return FALSE;
  349. pdpa->pp = ppNew;
  350. pdpa->cpAlloc = cpAlloc;
  351. //
  352. // Grow more agressively as we get bigger, up to a maximum of
  353. // 512 at a time. Note, we'll only hit our outer bound growth
  354. // at a time limit once we've already got that many items in the
  355. // DPA anyway...
  356. //
  357. if (pdpa->cpGrow < 256)
  358. {
  359. pdpa->cpGrow = pdpa->cpGrow << 1;
  360. }
  361. }
  362. return TRUE;
  363. }
  364. BOOL WINAPI DPA_SetPtr(HDPA pdpa, int index, void FAR* p)
  365. {
  366. ASSERT(IsDPA(pdpa));
  367. if (!pdpa)
  368. return FALSE;
  369. if (index < 0)
  370. {
  371. DebugMsg(DM_ERROR, TEXT("DPA: SetPtr: Invalid index: %d"), index);
  372. DABreak();
  373. return FALSE;
  374. }
  375. if (index >= pdpa->cp)
  376. {
  377. if (!DPA_Grow(pdpa, index + 1))
  378. return FALSE;
  379. // If we grew by more than one, must zero-init all the stuff in the middle
  380. ZeroMemory(pdpa->pp + pdpa->cp, sizeof(LPVOID) * (index - pdpa->cp));
  381. pdpa->cp = index + 1;
  382. }
  383. pdpa->pp[index] = p;
  384. return TRUE;
  385. }
  386. int WINAPI DPA_InsertPtr(HDPA pdpa, int index, void FAR* p)
  387. {
  388. ASSERT(IsDPA(pdpa));
  389. if (!pdpa)
  390. return -1;
  391. if (index < 0)
  392. {
  393. DebugMsg(DM_ERROR, TEXT("DPA: InsertPtr: Invalid index: %d"), index);
  394. DABreak();
  395. return -1;
  396. }
  397. if (index > pdpa->cp)
  398. index = pdpa->cp;
  399. // Make sure we have room for one more item
  400. //
  401. if (pdpa->cp + 1 > pdpa->cpAlloc)
  402. {
  403. if (!DPA_Grow(pdpa, pdpa->cp + 1))
  404. return -1;
  405. }
  406. // If we are inserting, we need to slide everybody up
  407. //
  408. if (index < pdpa->cp)
  409. {
  410. hmemcpy(&pdpa->pp[index + 1], &pdpa->pp[index],
  411. (pdpa->cp - index) * sizeof(void FAR*));
  412. }
  413. pdpa->pp[index] = p;
  414. pdpa->cp++;
  415. return index;
  416. }
  417. void FAR* WINAPI DPA_DeletePtr(HDPA pdpa, int index)
  418. {
  419. void FAR* p;
  420. ASSERT(IsDPA(pdpa));
  421. if (!pdpa)
  422. return FALSE;
  423. if (index < 0 || index >= pdpa->cp)
  424. {
  425. DebugMsg(DM_ERROR, TEXT("DPA: DeltePtr: Invalid index: %d"), index);
  426. DABreak();
  427. return NULL;
  428. }
  429. p = pdpa->pp[index];
  430. if (index < pdpa->cp - 1)
  431. {
  432. hmemcpy(&pdpa->pp[index], &pdpa->pp[index + 1],
  433. (pdpa->cp - (index + 1)) * sizeof(void FAR*));
  434. }
  435. pdpa->cp--;
  436. if (pdpa->cpAlloc - pdpa->cp > pdpa->cpGrow)
  437. {
  438. void FAR* FAR* ppNew;
  439. ppNew = ControlReAlloc(pdpa->hheap, pdpa->pp, (pdpa->cpAlloc - pdpa->cpGrow) * sizeof(void FAR*));
  440. if (ppNew)
  441. pdpa->pp = ppNew;
  442. else
  443. {
  444. // If the shrink fails, then just continue with the old (slightly
  445. // too big) allocation. Go ahead and let cpAlloc decrease
  446. // so we don't keep trying to realloc smaller
  447. }
  448. pdpa->cpAlloc -= pdpa->cpGrow;
  449. }
  450. return p;
  451. }
  452. BOOL WINAPI DPA_DeleteAllPtrs(HDPA pdpa)
  453. {
  454. if (!pdpa)
  455. return FALSE;
  456. ASSERT(IsDPA(pdpa));
  457. if (pdpa->pp && !ControlFree(pdpa->hheap, pdpa->pp))
  458. return FALSE;
  459. pdpa->pp = NULL;
  460. pdpa->cp = pdpa->cpAlloc = 0;
  461. return TRUE;
  462. }
  463. void WINAPI DPA_EnumCallback(HDPA pdpa, PFNDPAENUMCALLBACK pfnCB, LPVOID pData)
  464. {
  465. int i;
  466. if (!pdpa)
  467. return;
  468. ASSERT(IsDPA(pdpa));
  469. for (i = 0; i < pdpa->cp; i++) {
  470. if (!pfnCB(DPA_FastGetPtr(pdpa, i), pData))
  471. break;
  472. }
  473. }
  474. void WINAPI DPA_DestroyCallback(HDPA pdpa, PFNDPAENUMCALLBACK pfnCB, LPVOID pData)
  475. {
  476. DPA_EnumCallback(pdpa, pfnCB, pData);
  477. DPA_Destroy(pdpa);
  478. }
  479. typedef struct _DPASTREAMHEADER
  480. {
  481. DWORD cbSize; // Size of entire stream
  482. DWORD dwVersion; // For versioning
  483. int celem;
  484. } DPASTREAMHEADER;
  485. #define DPASTREAM_VERSION 1
  486. /*----------------------------------------------------------
  487. Purpose: Saves the DPA to a stream by writing out a header,
  488. and then calling the given callback to write each
  489. element.
  490. The callback can end the write early by returning
  491. something other than S_OK. Returning an error will
  492. cancel the entire write. Returning S_FALSE will
  493. stop the write.
  494. Returns: S_OK or S_FALSE for success.
  495. S_FALSE only if callback stops early
  496. errors
  497. */
  498. HRESULT
  499. WINAPI
  500. DPA_SaveStream(
  501. IN HDPA pdpa,
  502. IN PFNDPASTREAM pfn,
  503. IN IStream * pstm,
  504. IN LPVOID pvInstData)
  505. {
  506. HRESULT hres = E_INVALIDARG;
  507. if (IS_VALID_HANDLE(pdpa, DPA) &&
  508. IS_VALID_CODE_PTR(pstm, IStream *) &&
  509. IS_VALID_CODE_PTR(pfn, PFNDPASTREAM))
  510. {
  511. DPASTREAMHEADER header;
  512. LARGE_INTEGER dlibMove = { 0 };
  513. ULARGE_INTEGER ulPosBegin;
  514. // Get the current seek position, so we can update the header
  515. // once we know how much we've written
  516. hres = pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_CUR, &ulPosBegin);
  517. if (SUCCEEDED(hres))
  518. {
  519. // Write the header (we will update some of this once we're
  520. // finished)
  521. header.cbSize = 0;
  522. header.dwVersion = DPASTREAM_VERSION;
  523. header.celem = 0;
  524. // First write out the header
  525. hres = pstm->lpVtbl->Write(pstm, &header, sizeof(header), NULL);
  526. if (SUCCEEDED(hres))
  527. {
  528. DPASTREAMINFO info;
  529. int cel = DPA_GetPtrCount(pdpa);
  530. LPVOID * ppv = DPA_GetPtrPtr(pdpa);
  531. // This keeps the count of what is actually written
  532. info.iPos = 0;
  533. // Write each element
  534. for (; 0 < cel; cel--, ppv++)
  535. {
  536. info.pvItem = *ppv;
  537. hres = pfn(&info, pstm, pvInstData);
  538. // Returning S_FALSE from callback means it didn't
  539. // write anything for this element, so don't increment
  540. // the iPos (which refers to the count written).
  541. if (S_OK == hres)
  542. info.iPos++;
  543. else if (FAILED(hres))
  544. {
  545. hres = S_FALSE;
  546. break;
  547. }
  548. }
  549. if (FAILED(hres))
  550. {
  551. // Reposition pointer to beginning
  552. dlibMove.LowPart = ulPosBegin.LowPart;
  553. dlibMove.HighPart = ulPosBegin.HighPart;
  554. pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
  555. }
  556. else
  557. {
  558. ULARGE_INTEGER ulPosEnd;
  559. // Calculate how much was written
  560. hres = pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_CUR,
  561. &ulPosEnd);
  562. if (SUCCEEDED(hres))
  563. {
  564. // We only save the low part
  565. ASSERT(ulPosEnd.HighPart == ulPosBegin.HighPart);
  566. // Update the header
  567. header.celem = info.iPos;
  568. header.cbSize = ulPosEnd.LowPart - ulPosBegin.LowPart;
  569. dlibMove.LowPart = ulPosBegin.LowPart;
  570. dlibMove.HighPart = ulPosBegin.HighPart;
  571. pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
  572. pstm->lpVtbl->Write(pstm, &header, sizeof(header), NULL);
  573. // Reposition pointer
  574. dlibMove.LowPart = ulPosEnd.LowPart;
  575. dlibMove.HighPart = ulPosEnd.HighPart;
  576. pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
  577. }
  578. }
  579. }
  580. }
  581. }
  582. return hres;
  583. }
  584. /*----------------------------------------------------------
  585. Purpose: Loads the DPA from a stream by calling the given callback
  586. to read each element.
  587. The callback can end the read early by returning
  588. something other than S_OK.
  589. Returns: S_OK on success
  590. S_FALSE if the callback aborted early or the stream ended
  591. abruptly. DPA is partially filled.
  592. error on anything else
  593. */
  594. HRESULT
  595. WINAPI
  596. DPA_LoadStream(
  597. OUT HDPA * ppdpa,
  598. IN PFNDPASTREAM pfn,
  599. IN IStream * pstm,
  600. IN LPVOID pvInstData)
  601. {
  602. HRESULT hres = E_INVALIDARG;
  603. if (IS_VALID_WRITE_PTR(ppdpa, HDPA) &&
  604. IS_VALID_CODE_PTR(pstm, IStream *) &&
  605. IS_VALID_CODE_PTR(pfn, PFNDPASTREAM))
  606. {
  607. DPASTREAMHEADER header;
  608. LARGE_INTEGER dlibMove = { 0 };
  609. ULARGE_INTEGER ulPosBegin;
  610. ULONG cbRead;
  611. *ppdpa = NULL;
  612. // Get the current seek position so we can position pointer
  613. // correctly upon error.
  614. hres = pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_CUR, &ulPosBegin);
  615. if (SUCCEEDED(hres))
  616. {
  617. // Read the header
  618. hres = pstm->lpVtbl->Read(pstm, &header, sizeof(header), &cbRead);
  619. if (SUCCEEDED(hres))
  620. {
  621. if (sizeof(header) > cbRead ||
  622. sizeof(header) > header.cbSize ||
  623. DPASTREAM_VERSION != header.dwVersion)
  624. {
  625. hres = E_FAIL;
  626. }
  627. else
  628. {
  629. // Create the list
  630. HDPA pdpa = DPA_Create(header.celem);
  631. if ( !pdpa || !DPA_Grow(pdpa, header.celem))
  632. hres = E_OUTOFMEMORY;
  633. else
  634. {
  635. // Read each element
  636. DPASTREAMINFO info;
  637. LPVOID * ppv = DPA_GetPtrPtr(pdpa);
  638. for (info.iPos = 0; info.iPos < header.celem; )
  639. {
  640. info.pvItem = NULL;
  641. hres = pfn(&info, pstm, pvInstData);
  642. // Returning S_FALSE from the callback means
  643. // it skipped this stream element.
  644. // Don't increment iPos (which refers to the
  645. // count read).
  646. if (S_OK == hres)
  647. {
  648. *ppv = info.pvItem;
  649. info.iPos++;
  650. ppv++;
  651. }
  652. else if (FAILED(hres))
  653. {
  654. hres = S_FALSE;
  655. break;
  656. }
  657. }
  658. pdpa->cp = info.iPos;
  659. *ppdpa = pdpa;
  660. }
  661. }
  662. // Reposition pointer if we failed
  663. if (S_OK != hres)
  664. {
  665. if (S_FALSE == hres)
  666. {
  667. // Position pointer to the end
  668. dlibMove.LowPart = ulPosBegin.LowPart + header.cbSize;
  669. }
  670. else
  671. {
  672. // Position pointer to beginning
  673. dlibMove.LowPart = ulPosBegin.LowPart;
  674. }
  675. dlibMove.HighPart = ulPosBegin.HighPart;
  676. pstm->lpVtbl->Seek(pstm, dlibMove, STREAM_SEEK_SET, NULL);
  677. }
  678. }
  679. }
  680. ASSERT(SUCCEEDED(hres) && *ppdpa ||
  681. FAILED(hres) && NULL == *ppdpa);
  682. }
  683. return hres;
  684. }
  685. /*----------------------------------------------------------
  686. Purpose: Merge two DPAs. This takes two arrays and merges the
  687. source array into the destination.
  688. Merge options:
  689. DPAM_SORTED The arrays are already sorted; don't sort
  690. DPAM_UNION The resulting array is the union of all elements
  691. in both arrays.
  692. DPAM_INTERSECT Only elements in the source array that intersect
  693. with the dest array are merged.
  694. DPAM_NORMAL Like DPAM_INTERSECT except the dest array
  695. also maintains its original, additional elements.
  696. Returns: S_OK for success.
  697. errors if merge fails
  698. Cond: --
  699. */
  700. BOOL
  701. WINAPI
  702. DPA_Merge(
  703. IN HDPA pdpaDest,
  704. IN HDPA pdpaSrc,
  705. IN DWORD dwFlags,
  706. IN PFNDPACOMPARE pfnCompare,
  707. IN PFNDPAMERGE pfnMerge,
  708. IN LPARAM lParam)
  709. {
  710. BOOL bRet = FALSE;
  711. if (IS_VALID_HANDLE(pdpaSrc, DPA) &&
  712. IS_VALID_HANDLE(pdpaDest, DPA) &&
  713. IS_VALID_CODE_PTR(pfnCompare, PFNDPACOMPARE) &&
  714. IS_VALID_CODE_PTR(pfnMerge, PFNDPAMERGE))
  715. {
  716. int iSrc;
  717. int iDest;
  718. int nCmp;
  719. LPVOID * ppvSrc;
  720. LPVOID * ppvDest;
  721. bRet = TRUE;
  722. // Are the arrays already sorted?
  723. if ( !(dwFlags & DPAM_SORTED) )
  724. {
  725. // No; sort them
  726. DPA_Sort(pdpaSrc, pfnCompare, lParam);
  727. DPA_Sort(pdpaDest, pfnCompare, lParam);
  728. }
  729. // This merges in-place. The size of the resulting DPA
  730. // depends on the options:
  731. //
  732. // DPAM_NORMAL Same size as the dest DPA before
  733. // the merge.
  734. //
  735. // DPAM_UNION Min size is the larger of the two.
  736. // Max size is the sum of the two.
  737. //
  738. // DPAM_INTERSECT Min size is zero.
  739. // Max size is the smaller of the two.
  740. //
  741. // We iterate backwards to minimize the amount of moves we
  742. // incur by calling DPA_DeletePtr.
  743. //
  744. iSrc = pdpaSrc->cp - 1;
  745. iDest = pdpaDest->cp - 1;
  746. ppvSrc = &DPA_FastGetPtr(pdpaSrc, iSrc);
  747. ppvDest = &DPA_FastGetPtr(pdpaDest, iDest);
  748. while (0 <= iSrc && 0 <= iDest)
  749. {
  750. LPVOID pv;
  751. nCmp = pfnCompare(*ppvDest, *ppvSrc, lParam);
  752. if (0 == nCmp)
  753. {
  754. // Elements match; merge them.
  755. pv = pfnMerge(DPAMM_MERGE, *ppvDest, *ppvSrc, lParam);
  756. if (NULL == pv)
  757. {
  758. bRet = FALSE;
  759. break;
  760. }
  761. *ppvDest = pv;
  762. iSrc--;
  763. ppvSrc--;
  764. iDest--;
  765. ppvDest--;
  766. }
  767. else if (0 < nCmp)
  768. {
  769. // pvSrc < pvDest. The source array doesn't have pvDest.
  770. if (dwFlags & DPAM_INTERSECT)
  771. {
  772. // Delete pvDest
  773. pfnMerge(DPAMM_DELETE, DPA_DeletePtr(pdpaDest, iDest), NULL, lParam);
  774. }
  775. else
  776. {
  777. ; // Keep it (do nothing)
  778. }
  779. // Move onto the next element in the dest array
  780. iDest--;
  781. ppvDest--;
  782. }
  783. else
  784. {
  785. // pvSrc > pvDest. The dest array doesn't have pvSrc.
  786. if (dwFlags & DPAM_UNION)
  787. {
  788. // Add pvSrc
  789. pv = pfnMerge(DPAMM_INSERT, *ppvSrc, NULL, lParam);
  790. if (NULL == pv)
  791. {
  792. bRet = FALSE;
  793. break;
  794. }
  795. DPA_InsertPtr(pdpaDest, iDest+1, pv);
  796. // DPA_InsertPtr may end up reallocating the pointer array
  797. // thus making ppvDest invalid
  798. ppvDest = &DPA_FastGetPtr(pdpaDest, iDest);
  799. }
  800. else
  801. {
  802. ; // Skip it (do nothing)
  803. }
  804. // Move onto the next element in the source array
  805. iSrc--;
  806. ppvSrc--;
  807. }
  808. }
  809. // there are some items left in src
  810. if ((dwFlags & DPAM_UNION) && 0 <= iSrc)
  811. {
  812. for (; 0 <= iSrc; iSrc--, ppvSrc--)
  813. {
  814. LPVOID pv = pfnMerge(DPAMM_INSERT, *ppvSrc, NULL, lParam);
  815. if (NULL == pv)
  816. {
  817. bRet = FALSE;
  818. break;
  819. }
  820. DPA_InsertPtr(pdpaDest, 0, pv);
  821. }
  822. }
  823. }
  824. return bRet;
  825. }
  826. BOOL WINAPI DPA_Sort(HDPA pdpa, PFNDPACOMPARE pfnCmp, LPARAM lParam)
  827. {
  828. SORTPARAMS sp;
  829. sp.cp = pdpa->cp;
  830. sp.pp = pdpa->pp;
  831. sp.pfnCmp = pfnCmp;
  832. sp.lParam = lParam;
  833. #ifdef USEQUICKSORT
  834. return DPA_QuickSort(&sp);
  835. #endif
  836. #ifdef USEHEAPSORT
  837. return DPA_HeapSort(&sp);
  838. #endif
  839. #ifdef MERGESORT
  840. return DPA_MergeSort(&sp);
  841. #endif
  842. }
  843. #ifdef USEQUICKSORT
  844. BOOL NEAR DPA_QuickSort(SORTPARAMS FAR* psp)
  845. {
  846. return DPA_QuickSort2(0, psp->cp - 1, psp);
  847. }
  848. BOOL NEAR DPA_QuickSort2(int i, int j, SORTPARAMS FAR* psp)
  849. {
  850. void FAR* FAR* pp = psp->pp;
  851. LPARAM lParam = psp->lParam;
  852. PFNDPACOMPARE pfnCmp = psp->pfnCmp;
  853. int iPivot;
  854. void FAR* pFirst;
  855. int k;
  856. int result;
  857. iPivot = -1;
  858. pFirst = pp[i];
  859. for (k = i + 1; k <= j; k++)
  860. {
  861. result = (*pfnCmp)(pp[k], pFirst, lParam);
  862. if (result > 0)
  863. {
  864. iPivot = k;
  865. break;
  866. }
  867. else if (result < 0)
  868. {
  869. iPivot = i;
  870. break;
  871. }
  872. }
  873. if (iPivot != -1)
  874. {
  875. int l = i;
  876. int r = j;
  877. void FAR* pivot = pp[iPivot];
  878. do
  879. {
  880. void FAR* p;
  881. p = pp[l];
  882. pp[l] = pp[r];
  883. pp[r] = p;
  884. while ((*pfnCmp)(pp[l], pivot, lParam) < 0)
  885. l++;
  886. while ((*pfnCmp)(pp[r], pivot, lParam) >= 0)
  887. r--;
  888. } while (l <= r);
  889. if (l - 1 > i)
  890. DPA_QuickSort2(i, l - 1, psp);
  891. if (j > l)
  892. DPA_QuickSort2(l, j, psp);
  893. }
  894. return TRUE;
  895. }
  896. #endif // USEQUICKSORT
  897. #ifdef USEHEAPSORT
  898. void NEAR DPA_HeapSortPushDown(int first, int last, SORTPARAMS FAR* psp)
  899. {
  900. void FAR* FAR* pp = psp->pp;
  901. LPARAM lParam = psp->lParam;
  902. PFNDPACOMPARE pfnCmp = psp->pfnCmp;
  903. int r;
  904. int r2;
  905. void FAR* p;
  906. r = first;
  907. while (r <= last / 2)
  908. {
  909. int wRTo2R;
  910. r2 = r * 2;
  911. wRTo2R = (*pfnCmp)(pp[r-1], pp[r2-1], lParam);
  912. if (r2 == last)
  913. {
  914. if (wRTo2R < 0)
  915. {
  916. p = pp[r-1]; pp[r-1] = pp[r2-1]; pp[r2-1] = p;
  917. }
  918. break;
  919. }
  920. else
  921. {
  922. int wR2toR21 = (*pfnCmp)(pp[r2-1], pp[r2+1-1], lParam);
  923. if (wRTo2R < 0 && wR2toR21 >= 0)
  924. {
  925. p = pp[r-1]; pp[r-1] = pp[r2-1]; pp[r2-1] = p;
  926. r = r2;
  927. }
  928. else if ((*pfnCmp)(pp[r-1], pp[r2+1-1], lParam) < 0 && wR2toR21 < 0)
  929. {
  930. p = pp[r-1]; pp[r-1] = pp[r2+1-1]; pp[r2+1-1] = p;
  931. r = r2 + 1;
  932. }
  933. else
  934. {
  935. break;
  936. }
  937. }
  938. }
  939. }
  940. BOOL NEAR DPA_HeapSort(SORTPARAMS FAR* psp)
  941. {
  942. void FAR* FAR* pp = psp->pp;
  943. int c = psp->cp;
  944. int i;
  945. for (i = c / 2; i >= 1; i--)
  946. DPA_HeapSortPushDown(i, c, psp);
  947. for (i = c; i >= 2; i--)
  948. {
  949. void FAR* p = pp[0]; pp[0] = pp[i-1]; pp[i-1] = p;
  950. DPA_HeapSortPushDown(1, i - 1, psp);
  951. }
  952. return TRUE;
  953. }
  954. #endif // USEHEAPSORT
  955. #if defined(MERGESORT)
  956. #define SortCompare(psp, pp1, i1, pp2, i2) \
  957. (psp->pfnCmp(pp1[i1], pp2[i2], psp->lParam))
  958. //
  959. // This function merges two sorted lists and makes one sorted list.
  960. // psp->pp[iFirst, iFirst+cItes/2-1], psp->pp[iFirst+cItems/2, iFirst+cItems-1]
  961. //
  962. void NEAR DPA_MergeThem(SORTPARAMS FAR* psp, int iFirst, int cItems)
  963. {
  964. //
  965. // Notes:
  966. // This function is separated from DPA_MergeSort2() to avoid comsuming
  967. // stack variables. Never inline this.
  968. //
  969. int cHalf = cItems/2;
  970. int iIn1, iIn2, iOut;
  971. LPVOID * ppvSrc = &psp->pp[iFirst];
  972. // Copy the first part to temp storage so we can write directly into
  973. // the final buffer. Note that this takes at most psp->cp/2 DWORD's
  974. hmemcpy(psp->ppT, ppvSrc, cHalf*sizeof(LPVOID));
  975. for (iIn1=0, iIn2=cHalf, iOut=0;;)
  976. {
  977. if (SortCompare(psp, psp->ppT, iIn1, ppvSrc, iIn2) <= 0) {
  978. ppvSrc[iOut++] = psp->ppT[iIn1++];
  979. if (iIn1==cHalf) {
  980. // We used up the first half; the rest of the second half
  981. // should already be in place
  982. break;
  983. }
  984. } else {
  985. ppvSrc[iOut++] = ppvSrc[iIn2++];
  986. if (iIn2==cItems) {
  987. // We used up the second half; copy the rest of the first half
  988. // into place
  989. hmemcpy(&ppvSrc[iOut], &psp->ppT[iIn1], (cItems-iOut)*sizeof(LPVOID));
  990. break;
  991. }
  992. }
  993. }
  994. }
  995. //
  996. // This function sorts a give list (psp->pp[iFirst,iFirst-cItems-1]).
  997. //
  998. void NEAR DPA_MergeSort2(SORTPARAMS FAR* psp, int iFirst, int cItems)
  999. {
  1000. //
  1001. // Notes:
  1002. // This function is recursively called. Therefore, we should minimize
  1003. // the number of local variables and parameters. At this point, we
  1004. // use one local variable and three parameters.
  1005. //
  1006. int cHalf;
  1007. switch(cItems)
  1008. {
  1009. case 1:
  1010. return;
  1011. case 2:
  1012. // Swap them, if they are out of order.
  1013. if (SortCompare(psp, psp->pp, iFirst, psp->pp, iFirst+1) > 0)
  1014. {
  1015. psp->ppT[0] = psp->pp[iFirst];
  1016. psp->pp[iFirst] = psp->pp[iFirst+1];
  1017. psp->pp[iFirst+1] = psp->ppT[0];
  1018. }
  1019. break;
  1020. default:
  1021. cHalf = cItems/2;
  1022. // Sort each half
  1023. DPA_MergeSort2(psp, iFirst, cHalf);
  1024. DPA_MergeSort2(psp, iFirst+cHalf, cItems-cHalf);
  1025. // Then, merge them.
  1026. DPA_MergeThem(psp, iFirst, cItems);
  1027. break;
  1028. }
  1029. }
  1030. BOOL NEAR DPA_MergeSort(SORTPARAMS FAR* psp)
  1031. {
  1032. if (psp->cp==0)
  1033. return TRUE;
  1034. // Note that we divide by 2 below; we want to round down
  1035. psp->ppT = LocalAlloc(LPTR, psp->cp/2 * sizeof(LPVOID));
  1036. if (!psp->ppT)
  1037. return FALSE;
  1038. DPA_MergeSort2(psp, 0, psp->cp);
  1039. LocalFree(psp->ppT);
  1040. return TRUE;
  1041. }
  1042. #endif // MERGESORT
  1043. // Search function
  1044. //
  1045. int WINAPI DPA_Search(HDPA pdpa, void FAR* pFind, int iStart,
  1046. PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT options)
  1047. {
  1048. int cp = DPA_GetPtrCount(pdpa);
  1049. ASSERT(pfnCompare);
  1050. ASSERT(0 <= iStart);
  1051. // Only allow these wierd flags if the list is sorted
  1052. ASSERT((options & DPAS_SORTED) || !(options & (DPAS_INSERTBEFORE | DPAS_INSERTAFTER)));
  1053. if (!(options & DPAS_SORTED))
  1054. {
  1055. // Not sorted: do linear search.
  1056. int i;
  1057. for (i = iStart; i < cp; i++)
  1058. {
  1059. if (0 == pfnCompare(pFind, DPA_FastGetPtr(pdpa, i), lParam))
  1060. return i;
  1061. }
  1062. return -1;
  1063. }
  1064. else
  1065. {
  1066. // Search the array using binary search. If several adjacent
  1067. // elements match the target element, the index of the first
  1068. // matching element is returned.
  1069. int iRet = -1; // assume no match
  1070. BOOL bFound = FALSE;
  1071. int nCmp = 0;
  1072. int iLow = 0; // Don't bother using iStart for binary search
  1073. int iMid = 0;
  1074. int iHigh = cp - 1;
  1075. // (OK for cp == 0)
  1076. while (iLow <= iHigh)
  1077. {
  1078. iMid = (iLow + iHigh) / 2;
  1079. nCmp = pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid), lParam);
  1080. if (0 > nCmp)
  1081. iHigh = iMid - 1; // First is smaller
  1082. else if (0 < nCmp)
  1083. iLow = iMid + 1; // First is larger
  1084. else
  1085. {
  1086. // Match; search back for first match
  1087. bFound = TRUE;
  1088. while (0 < iMid)
  1089. {
  1090. if (0 != pfnCompare(pFind, DPA_FastGetPtr(pdpa, iMid-1), lParam))
  1091. break;
  1092. else
  1093. iMid--;
  1094. }
  1095. break;
  1096. }
  1097. }
  1098. if (bFound)
  1099. {
  1100. ASSERT(0 <= iMid);
  1101. iRet = iMid;
  1102. }
  1103. // Did the search fail AND
  1104. // is one of the strange search flags set?
  1105. if (!bFound && (options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)))
  1106. {
  1107. // Yes; return the index where the target should be inserted
  1108. // if not found
  1109. if (0 < nCmp) // First is larger
  1110. iRet = iLow;
  1111. else
  1112. iRet = iMid;
  1113. // (We don't distinguish between the two flags anymore)
  1114. }
  1115. else if ( !(options & (DPAS_INSERTAFTER | DPAS_INSERTBEFORE)) )
  1116. {
  1117. // Sanity check with linear search
  1118. ASSERT(DPA_Search(pdpa, pFind, iStart, pfnCompare, lParam, options & ~DPAS_SORTED) == iRet);
  1119. }
  1120. return iRet;
  1121. }
  1122. }
  1123. //===========================================================================
  1124. //
  1125. // String ptr management routines
  1126. //
  1127. // Copy as much of *psz to *pszBuf as will fit
  1128. //
  1129. // Warning: this same code is duplicated below.
  1130. //
  1131. int WINAPI Str_GetPtr(LPCTSTR pszCurrent, LPTSTR pszBuf, int cchBuf)
  1132. {
  1133. int cchToCopy;
  1134. if (!pszCurrent)
  1135. {
  1136. ASSERT(FALSE);
  1137. if (cchBuf > 0)
  1138. *pszBuf = TEXT('\0');
  1139. return 0;
  1140. }
  1141. cchToCopy = lstrlen(pszCurrent);
  1142. // if pszBuf is NULL, or they passed cchBuf = 0, return the needed buff size
  1143. if (!pszBuf || !cchBuf)
  1144. return cchToCopy + 1;
  1145. if (cchToCopy >= cchBuf)
  1146. cchToCopy = cchBuf - 1;
  1147. hmemcpy(pszBuf, pszCurrent, cchToCopy * SIZEOF(TCHAR));
  1148. pszBuf[cchToCopy] = TEXT('\0');
  1149. return cchToCopy + 1;
  1150. }
  1151. #ifdef DEBUG
  1152. //
  1153. // Str_GetPtr0 is just like Str_GetPtr except that it doesn't assert if
  1154. // pszCurrent = NULL.
  1155. //
  1156. int WINAPI Str_GetPtr0(LPCTSTR pszCurrent, LPTSTR pszBuf, int cchBuf)
  1157. {
  1158. return Str_GetPtr(pszCurrent ? pszCurrent : c_szNULL, pszBuf, cchBuf);
  1159. }
  1160. #endif
  1161. //
  1162. // If we are build Unicode, then this is the ANSI version
  1163. // of the above function.
  1164. //
  1165. int WINAPI Str_GetPtrA(LPCSTR pszCurrent, LPSTR pszBuf, int cchBuf)
  1166. {
  1167. int cchToCopy;
  1168. if (!pszCurrent)
  1169. {
  1170. ASSERT(FALSE);
  1171. if (cchBuf > 0)
  1172. *pszBuf = '\0';
  1173. return 0;
  1174. }
  1175. cchToCopy = lstrlenA(pszCurrent);
  1176. // if pszBuf is NULL, or they passed cchBuf = 0, return the needed buff size
  1177. if (!pszBuf || !cchBuf)
  1178. return cchToCopy + 1;
  1179. if (cchToCopy >= cchBuf)
  1180. cchToCopy = cchBuf - 1;
  1181. // BUGBUG: Must call TruncateString, as we may be in the middle of DBCS char
  1182. hmemcpy(pszBuf, pszCurrent, cchToCopy * SIZEOF(CHAR));
  1183. pszBuf[cchToCopy] = TEXT('\0');
  1184. return cchToCopy + 1;
  1185. }
  1186. //
  1187. // This function is not exported.
  1188. //
  1189. BOOL Str_Set(LPTSTR *ppsz, LPCTSTR psz)
  1190. {
  1191. if (!psz || (psz == LPSTR_TEXTCALLBACK))
  1192. {
  1193. if (*ppsz)
  1194. {
  1195. if (*ppsz != (LPSTR_TEXTCALLBACK))
  1196. LocalFree(*ppsz);
  1197. }
  1198. *ppsz = (LPTSTR)psz;
  1199. }
  1200. else
  1201. {
  1202. LPTSTR pszNew = *ppsz;
  1203. UINT cbNew = (lstrlen(psz) + 1) * sizeof(TCHAR);
  1204. if (pszNew == LPSTR_TEXTCALLBACK)
  1205. pszNew = NULL;
  1206. pszNew = CCLocalReAlloc(pszNew, cbNew);
  1207. if (!pszNew)
  1208. return FALSE;
  1209. StringCbCopy(pszNew, cbNew, psz);
  1210. *ppsz = pszNew;
  1211. }
  1212. return TRUE;
  1213. }
  1214. // Set *ppszCurrent to a copy of pszNew, and free the previous value, if necessary
  1215. //
  1216. // WARNING: This same code is duplicated below
  1217. //
  1218. BOOL WINAPI Str_SetPtr(LPTSTR * ppszCurrent, LPCTSTR pszNew)
  1219. {
  1220. LPTSTR pszOld;
  1221. LPTSTR pszNewCopy = NULL;
  1222. if (pszNew)
  1223. {
  1224. int cchNewCopy = lstrlen(pszNew);
  1225. // alloc a new buffer w/ room for the null terminator
  1226. pszNewCopy = (LPTSTR) Alloc((cchNewCopy + 1) * SIZEOF(TCHAR));
  1227. if (!pszNewCopy)
  1228. return FALSE;
  1229. StringCchCopy(pszNewCopy, cchNewCopy+1, pszNew);
  1230. }
  1231. pszOld = InterlockedExchangePointer((LPVOID *)ppszCurrent, pszNewCopy);
  1232. if (pszOld)
  1233. Free(pszOld);
  1234. return TRUE;
  1235. }
  1236. BOOL WINAPI Str_SetPtrA(LPSTR * ppszCurrent, LPCSTR pszNew)
  1237. {
  1238. LPSTR pszOld;
  1239. LPSTR pszNewCopy = NULL;
  1240. if (pszNew)
  1241. {
  1242. int cchNewCopy = lstrlenA(pszNew);
  1243. // alloc a new buffer w/ room for the null terminator
  1244. pszNewCopy = (LPSTR) Alloc((cchNewCopy + 1) * SIZEOF(CHAR));
  1245. if (!pszNewCopy)
  1246. return FALSE;
  1247. StringCchCopyA(pszNewCopy, cchNewCopy+1, pszNew);
  1248. }
  1249. pszOld = InterlockedExchangePointer((LPVOID *)ppszCurrent, pszNewCopy);
  1250. if (pszOld)
  1251. Free(pszOld);
  1252. return TRUE;
  1253. }