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.

1597 lines
40 KiB

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