xref: /reactos/dll/win32/comctl32/dpa.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck  * Dynamic pointer array (DPA) implementation
3*c2c66affSColin Finck  *
4*c2c66affSColin Finck  * Copyright 1998 Eric Kohl
5*c2c66affSColin Finck  *           1998 Juergen Schmied <j.schmied@metronet.de>
6*c2c66affSColin Finck  *           2000 Eric Kohl for CodeWeavers
7*c2c66affSColin Finck  *
8*c2c66affSColin Finck  * This library is free software; you can redistribute it and/or
9*c2c66affSColin Finck  * modify it under the terms of the GNU Lesser General Public
10*c2c66affSColin Finck  * License as published by the Free Software Foundation; either
11*c2c66affSColin Finck  * version 2.1 of the License, or (at your option) any later version.
12*c2c66affSColin Finck  *
13*c2c66affSColin Finck  * This library is distributed in the hope that it will be useful,
14*c2c66affSColin Finck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*c2c66affSColin Finck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16*c2c66affSColin Finck  * Lesser General Public License for more details.
17*c2c66affSColin Finck  *
18*c2c66affSColin Finck  * You should have received a copy of the GNU Lesser General Public
19*c2c66affSColin Finck  * License along with this library; if not, write to the Free Software
20*c2c66affSColin Finck  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21*c2c66affSColin Finck  *
22*c2c66affSColin Finck  * NOTES
23*c2c66affSColin Finck  *     These functions were involuntarily documented by Microsoft in 2002 as
24*c2c66affSColin Finck  *     the outcome of an anti-trust suit brought by various U.S. governments.
25*c2c66affSColin Finck  *     As a result the specifications on MSDN are inaccurate, incomplete
26*c2c66affSColin Finck  *     and misleading. A much more complete (unofficial) documentation is
27*c2c66affSColin Finck  *     available at:
28*c2c66affSColin Finck  *
29*c2c66affSColin Finck  *     http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32
30*c2c66affSColin Finck  */
31*c2c66affSColin Finck 
32*c2c66affSColin Finck #include "comctl32.h"
33*c2c66affSColin Finck 
34*c2c66affSColin Finck WINE_DEFAULT_DEBUG_CHANNEL(dpa);
35*c2c66affSColin Finck 
36*c2c66affSColin Finck typedef struct _DPA
37*c2c66affSColin Finck {
38*c2c66affSColin Finck     INT    nItemCount;
39*c2c66affSColin Finck     LPVOID   *ptrs;
40*c2c66affSColin Finck     HANDLE hHeap;
41*c2c66affSColin Finck     INT    nGrow;
42*c2c66affSColin Finck     INT    nMaxCount;
43*c2c66affSColin Finck } DPA;
44*c2c66affSColin Finck 
45*c2c66affSColin Finck typedef struct _STREAMDATA
46*c2c66affSColin Finck {
47*c2c66affSColin Finck     DWORD dwSize;
48*c2c66affSColin Finck     DWORD dwData2;
49*c2c66affSColin Finck     DWORD dwItems;
50*c2c66affSColin Finck } STREAMDATA, *PSTREAMDATA;
51*c2c66affSColin Finck 
52*c2c66affSColin Finck /**************************************************************************
53*c2c66affSColin Finck  * DPA_LoadStream [COMCTL32.9]
54*c2c66affSColin Finck  *
55*c2c66affSColin Finck  * Loads a dynamic pointer array from a stream
56*c2c66affSColin Finck  *
57*c2c66affSColin Finck  * PARAMS
58*c2c66affSColin Finck  *     phDpa    [O] pointer to a handle to a dynamic pointer array
59*c2c66affSColin Finck  *     loadProc [I] pointer to a callback function
60*c2c66affSColin Finck  *     pStream  [I] pointer to a stream
61*c2c66affSColin Finck  *     pData    [I] pointer to callback data
62*c2c66affSColin Finck  *
63*c2c66affSColin Finck  * RETURNS
64*c2c66affSColin Finck  *     Success: S_OK, S_FALSE - partial success
65*c2c66affSColin Finck  *     Failure: HRESULT error code
66*c2c66affSColin Finck  *
67*c2c66affSColin Finck  * NOTES
68*c2c66affSColin Finck  *     No more information available yet!
69*c2c66affSColin Finck  */
70*c2c66affSColin Finck HRESULT WINAPI DPA_LoadStream (HDPA *phDpa, PFNDPASTREAM loadProc,
71*c2c66affSColin Finck                                IStream *pStream, LPVOID pData)
72*c2c66affSColin Finck {
73*c2c66affSColin Finck     HRESULT errCode;
74*c2c66affSColin Finck     LARGE_INTEGER position;
75*c2c66affSColin Finck     ULARGE_INTEGER initial_pos;
76*c2c66affSColin Finck     STREAMDATA  streamData;
77*c2c66affSColin Finck     DPASTREAMINFO streamInfo;
78*c2c66affSColin Finck     ULONG ulRead;
79*c2c66affSColin Finck     HDPA hDpa;
80*c2c66affSColin Finck     PVOID *ptr;
81*c2c66affSColin Finck 
82*c2c66affSColin Finck     TRACE ("phDpa=%p loadProc=%p pStream=%p pData=%p\n",
83*c2c66affSColin Finck            phDpa, loadProc, pStream, pData);
84*c2c66affSColin Finck 
85*c2c66affSColin Finck     if (!phDpa || !loadProc || !pStream)
86*c2c66affSColin Finck         return E_INVALIDARG;
87*c2c66affSColin Finck 
88*c2c66affSColin Finck     *phDpa = NULL;
89*c2c66affSColin Finck 
90*c2c66affSColin Finck     position.QuadPart = 0;
91*c2c66affSColin Finck 
92*c2c66affSColin Finck     errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &initial_pos);
93*c2c66affSColin Finck     if (errCode != S_OK)
94*c2c66affSColin Finck         return errCode;
95*c2c66affSColin Finck 
96*c2c66affSColin Finck     memset(&streamData, 0, sizeof(STREAMDATA));
97*c2c66affSColin Finck     errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), &ulRead);
98*c2c66affSColin Finck     if (errCode != S_OK)
99*c2c66affSColin Finck         return errCode;
100*c2c66affSColin Finck 
101*c2c66affSColin Finck     TRACE ("dwSize=%u dwData2=%u dwItems=%u\n",
102*c2c66affSColin Finck            streamData.dwSize, streamData.dwData2, streamData.dwItems);
103*c2c66affSColin Finck 
104*c2c66affSColin Finck     if (ulRead < sizeof(STREAMDATA) ||
105*c2c66affSColin Finck         streamData.dwSize < sizeof(STREAMDATA) || streamData.dwData2 != 1) {
106*c2c66affSColin Finck         /* back to initial position */
107*c2c66affSColin Finck         position.QuadPart = initial_pos.QuadPart;
108*c2c66affSColin Finck         IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
109*c2c66affSColin Finck         return E_FAIL;
110*c2c66affSColin Finck     }
111*c2c66affSColin Finck 
112*c2c66affSColin Finck     if (streamData.dwItems > (UINT_MAX / 2 / sizeof(VOID*))) /* 536870911 */
113*c2c66affSColin Finck         return E_OUTOFMEMORY;
114*c2c66affSColin Finck 
115*c2c66affSColin Finck     /* create the dpa */
116*c2c66affSColin Finck     hDpa = DPA_Create (streamData.dwItems);
117*c2c66affSColin Finck     if (!hDpa)
118*c2c66affSColin Finck         return E_OUTOFMEMORY;
119*c2c66affSColin Finck 
120*c2c66affSColin Finck     if (!DPA_Grow (hDpa, streamData.dwItems)) {
121*c2c66affSColin Finck         DPA_Destroy (hDpa);
122*c2c66affSColin Finck         return E_OUTOFMEMORY;
123*c2c66affSColin Finck     }
124*c2c66affSColin Finck 
125*c2c66affSColin Finck     /* load data from the stream into the dpa */
126*c2c66affSColin Finck     ptr = hDpa->ptrs;
127*c2c66affSColin Finck     for (streamInfo.iPos = 0; streamInfo.iPos < streamData.dwItems; streamInfo.iPos++) {
128*c2c66affSColin Finck         errCode = (loadProc)(&streamInfo, pStream, pData);
129*c2c66affSColin Finck         if (errCode != S_OK) {
130*c2c66affSColin Finck             errCode = S_FALSE;
131*c2c66affSColin Finck             break;
132*c2c66affSColin Finck         }
133*c2c66affSColin Finck 
134*c2c66affSColin Finck         *ptr = streamInfo.pvItem;
135*c2c66affSColin Finck         ptr++;
136*c2c66affSColin Finck     }
137*c2c66affSColin Finck 
138*c2c66affSColin Finck     /* set the number of items */
139*c2c66affSColin Finck     hDpa->nItemCount = streamInfo.iPos;
140*c2c66affSColin Finck 
141*c2c66affSColin Finck     /* store the handle to the dpa */
142*c2c66affSColin Finck     *phDpa = hDpa;
143*c2c66affSColin Finck     TRACE ("new hDpa=%p, errorcode=%x\n", hDpa, errCode);
144*c2c66affSColin Finck 
145*c2c66affSColin Finck     return errCode;
146*c2c66affSColin Finck }
147*c2c66affSColin Finck 
148*c2c66affSColin Finck 
149*c2c66affSColin Finck /**************************************************************************
150*c2c66affSColin Finck  * DPA_SaveStream [COMCTL32.10]
151*c2c66affSColin Finck  *
152*c2c66affSColin Finck  * Saves a dynamic pointer array to a stream
153*c2c66affSColin Finck  *
154*c2c66affSColin Finck  * PARAMS
155*c2c66affSColin Finck  *     hDpa     [I] handle to a dynamic pointer array
156*c2c66affSColin Finck  *     saveProc [I] pointer to a callback function
157*c2c66affSColin Finck  *     pStream  [I] pointer to a stream
158*c2c66affSColin Finck  *     pData    [I] pointer to callback data
159*c2c66affSColin Finck  *
160*c2c66affSColin Finck  * RETURNS
161*c2c66affSColin Finck  *     Success: S_OK, S_FALSE - partial success
162*c2c66affSColin Finck  *     Failure: HRESULT error code
163*c2c66affSColin Finck  *
164*c2c66affSColin Finck  * NOTES
165*c2c66affSColin Finck  *     No more information available yet!
166*c2c66affSColin Finck  */
167*c2c66affSColin Finck HRESULT WINAPI DPA_SaveStream (HDPA hDpa, PFNDPASTREAM saveProc,
168*c2c66affSColin Finck                                IStream *pStream, LPVOID pData)
169*c2c66affSColin Finck {
170*c2c66affSColin Finck     LARGE_INTEGER position;
171*c2c66affSColin Finck     ULARGE_INTEGER initial_pos, curr_pos;
172*c2c66affSColin Finck     STREAMDATA  streamData;
173*c2c66affSColin Finck     DPASTREAMINFO streamInfo;
174*c2c66affSColin Finck     HRESULT hr;
175*c2c66affSColin Finck     PVOID *ptr;
176*c2c66affSColin Finck 
177*c2c66affSColin Finck     TRACE ("hDpa=%p saveProc=%p pStream=%p pData=%p\n",
178*c2c66affSColin Finck             hDpa, saveProc, pStream, pData);
179*c2c66affSColin Finck 
180*c2c66affSColin Finck     if (!hDpa || !saveProc || !pStream) return E_INVALIDARG;
181*c2c66affSColin Finck 
182*c2c66affSColin Finck     /* save initial position to write header after completion */
183*c2c66affSColin Finck     position.QuadPart = 0;
184*c2c66affSColin Finck     hr = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &initial_pos);
185*c2c66affSColin Finck     if (hr != S_OK)
186*c2c66affSColin Finck         return hr;
187*c2c66affSColin Finck 
188*c2c66affSColin Finck     /* write empty header */
189*c2c66affSColin Finck     streamData.dwSize  = sizeof(streamData);
190*c2c66affSColin Finck     streamData.dwData2 = 1;
191*c2c66affSColin Finck     streamData.dwItems = 0;
192*c2c66affSColin Finck 
193*c2c66affSColin Finck     hr = IStream_Write (pStream, &streamData, sizeof(streamData), NULL);
194*c2c66affSColin Finck     if (hr != S_OK) {
195*c2c66affSColin Finck         position.QuadPart = initial_pos.QuadPart;
196*c2c66affSColin Finck         IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
197*c2c66affSColin Finck         return hr;
198*c2c66affSColin Finck     }
199*c2c66affSColin Finck 
200*c2c66affSColin Finck     /* no items - we're done */
201*c2c66affSColin Finck     if (hDpa->nItemCount == 0) return S_OK;
202*c2c66affSColin Finck 
203*c2c66affSColin Finck     ptr = hDpa->ptrs;
204*c2c66affSColin Finck     for (streamInfo.iPos = 0; streamInfo.iPos < hDpa->nItemCount; streamInfo.iPos++) {
205*c2c66affSColin Finck         streamInfo.pvItem = *ptr;
206*c2c66affSColin Finck         hr = (saveProc)(&streamInfo, pStream, pData);
207*c2c66affSColin Finck         if (hr != S_OK) {
208*c2c66affSColin Finck             hr = S_FALSE;
209*c2c66affSColin Finck             break;
210*c2c66affSColin Finck         }
211*c2c66affSColin Finck         ptr++;
212*c2c66affSColin Finck     }
213*c2c66affSColin Finck 
214*c2c66affSColin Finck     /* write updated header */
215*c2c66affSColin Finck     position.QuadPart = 0;
216*c2c66affSColin Finck     IStream_Seek (pStream, position, STREAM_SEEK_CUR, &curr_pos);
217*c2c66affSColin Finck 
218*c2c66affSColin Finck     streamData.dwSize  = curr_pos.QuadPart - initial_pos.QuadPart;
219*c2c66affSColin Finck     streamData.dwData2 = 1;
220*c2c66affSColin Finck     streamData.dwItems = streamInfo.iPos;
221*c2c66affSColin Finck 
222*c2c66affSColin Finck     position.QuadPart = initial_pos.QuadPart;
223*c2c66affSColin Finck     IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
224*c2c66affSColin Finck     IStream_Write (pStream, &streamData, sizeof(streamData), NULL);
225*c2c66affSColin Finck 
226*c2c66affSColin Finck     position.QuadPart = curr_pos.QuadPart;
227*c2c66affSColin Finck     IStream_Seek (pStream, position, STREAM_SEEK_SET, NULL);
228*c2c66affSColin Finck 
229*c2c66affSColin Finck     return hr;
230*c2c66affSColin Finck }
231*c2c66affSColin Finck 
232*c2c66affSColin Finck 
233*c2c66affSColin Finck /**************************************************************************
234*c2c66affSColin Finck  * DPA_Merge [COMCTL32.11]
235*c2c66affSColin Finck  *
236*c2c66affSColin Finck  * Merge two dynamic pointers arrays.
237*c2c66affSColin Finck  *
238*c2c66affSColin Finck  * PARAMS
239*c2c66affSColin Finck  *     hdpa1       [I] handle to a dynamic pointer array
240*c2c66affSColin Finck  *     hdpa2       [I] handle to a dynamic pointer array
241*c2c66affSColin Finck  *     dwFlags     [I] flags
242*c2c66affSColin Finck  *     pfnCompare  [I] pointer to sort function
243*c2c66affSColin Finck  *     pfnMerge    [I] pointer to merge function
244*c2c66affSColin Finck  *     lParam      [I] application specific value
245*c2c66affSColin Finck  *
246*c2c66affSColin Finck  * RETURNS
247*c2c66affSColin Finck  *     Success: TRUE
248*c2c66affSColin Finck  *     Failure: FALSE
249*c2c66affSColin Finck  *
250*c2c66affSColin Finck  * NOTES
251*c2c66affSColin Finck  *     No more information available yet!
252*c2c66affSColin Finck  */
253*c2c66affSColin Finck BOOL WINAPI DPA_Merge (HDPA hdpa1, HDPA hdpa2, DWORD dwFlags,
254*c2c66affSColin Finck                        PFNDPACOMPARE pfnCompare, PFNDPAMERGE pfnMerge,
255*c2c66affSColin Finck                        LPARAM lParam)
256*c2c66affSColin Finck {
257*c2c66affSColin Finck     INT nCount;
258*c2c66affSColin Finck     LPVOID *pWork1, *pWork2;
259*c2c66affSColin Finck     INT nResult, i;
260*c2c66affSColin Finck     INT nIndex;
261*c2c66affSColin Finck 
262*c2c66affSColin Finck     TRACE("(%p %p %08x %p %p %08lx)\n",
263*c2c66affSColin Finck            hdpa1, hdpa2, dwFlags, pfnCompare, pfnMerge, lParam);
264*c2c66affSColin Finck 
265*c2c66affSColin Finck     if (IsBadWritePtr (hdpa1, sizeof(*hdpa1)))
266*c2c66affSColin Finck         return FALSE;
267*c2c66affSColin Finck 
268*c2c66affSColin Finck     if (IsBadWritePtr (hdpa2, sizeof(*hdpa2)))
269*c2c66affSColin Finck         return FALSE;
270*c2c66affSColin Finck 
271*c2c66affSColin Finck     if (IsBadCodePtr ((FARPROC)pfnCompare))
272*c2c66affSColin Finck         return FALSE;
273*c2c66affSColin Finck 
274*c2c66affSColin Finck     if (IsBadCodePtr ((FARPROC)pfnMerge))
275*c2c66affSColin Finck         return FALSE;
276*c2c66affSColin Finck 
277*c2c66affSColin Finck     if (!(dwFlags & DPAM_SORTED)) {
278*c2c66affSColin Finck         TRACE("sorting dpa's.\n");
279*c2c66affSColin Finck         if (hdpa1->nItemCount > 0)
280*c2c66affSColin Finck         DPA_Sort (hdpa1, pfnCompare, lParam);
281*c2c66affSColin Finck         TRACE ("dpa 1 sorted.\n");
282*c2c66affSColin Finck         if (hdpa2->nItemCount > 0)
283*c2c66affSColin Finck         DPA_Sort (hdpa2, pfnCompare, lParam);
284*c2c66affSColin Finck         TRACE ("dpa 2 sorted.\n");
285*c2c66affSColin Finck     }
286*c2c66affSColin Finck 
287*c2c66affSColin Finck     if (hdpa2->nItemCount < 1)
288*c2c66affSColin Finck         return TRUE;
289*c2c66affSColin Finck 
290*c2c66affSColin Finck     TRACE("hdpa1->nItemCount=%d hdpa2->nItemCount=%d\n",
291*c2c66affSColin Finck            hdpa1->nItemCount, hdpa2->nItemCount);
292*c2c66affSColin Finck 
293*c2c66affSColin Finck 
294*c2c66affSColin Finck     nIndex = hdpa1->nItemCount - 1;
295*c2c66affSColin Finck     nCount = hdpa2->nItemCount - 1;
296*c2c66affSColin Finck 
297*c2c66affSColin Finck     do
298*c2c66affSColin Finck     {
299*c2c66affSColin Finck         pWork1 = &hdpa1->ptrs[nIndex];
300*c2c66affSColin Finck         pWork2 = &hdpa2->ptrs[nCount];
301*c2c66affSColin Finck 
302*c2c66affSColin Finck         if (nIndex < 0) {
303*c2c66affSColin Finck             if ((nCount >= 0) && (dwFlags & DPAM_UNION)) {
304*c2c66affSColin Finck                 /* Now insert the remaining new items into DPA 1 */
305*c2c66affSColin Finck                 TRACE("%d items to be inserted at start of DPA 1\n",
306*c2c66affSColin Finck                       nCount+1);
307*c2c66affSColin Finck                 for (i=nCount; i>=0; i--) {
308*c2c66affSColin Finck                     PVOID ptr;
309*c2c66affSColin Finck 
310*c2c66affSColin Finck                     ptr = (pfnMerge)(DPAMM_INSERT, *pWork2, NULL, lParam);
311*c2c66affSColin Finck                     if (!ptr)
312*c2c66affSColin Finck                         return FALSE;
313*c2c66affSColin Finck                     DPA_InsertPtr (hdpa1, 0, ptr);
314*c2c66affSColin Finck                     pWork2--;
315*c2c66affSColin Finck                 }
316*c2c66affSColin Finck             }
317*c2c66affSColin Finck             break;
318*c2c66affSColin Finck         }
319*c2c66affSColin Finck         nResult = (pfnCompare)(*pWork1, *pWork2, lParam);
320*c2c66affSColin Finck         TRACE("compare result=%d, dpa1.cnt=%d, dpa2.cnt=%d\n",
321*c2c66affSColin Finck               nResult, nIndex, nCount);
322*c2c66affSColin Finck 
323*c2c66affSColin Finck         if (nResult == 0)
324*c2c66affSColin Finck         {
325*c2c66affSColin Finck             PVOID ptr;
326*c2c66affSColin Finck 
327*c2c66affSColin Finck             ptr = (pfnMerge)(DPAMM_MERGE, *pWork1, *pWork2, lParam);
328*c2c66affSColin Finck             if (!ptr)
329*c2c66affSColin Finck                 return FALSE;
330*c2c66affSColin Finck 
331*c2c66affSColin Finck             nCount--;
332*c2c66affSColin Finck             *pWork1 = ptr;
333*c2c66affSColin Finck             nIndex--;
334*c2c66affSColin Finck         }
335*c2c66affSColin Finck         else if (nResult > 0)
336*c2c66affSColin Finck         {
337*c2c66affSColin Finck             /* item in DPA 1 missing from DPA 2 */
338*c2c66affSColin Finck             if (dwFlags & DPAM_INTERSECT)
339*c2c66affSColin Finck             {
340*c2c66affSColin Finck                 /* Now delete the extra item in DPA1 */
341*c2c66affSColin Finck                 PVOID ptr;
342*c2c66affSColin Finck 
343*c2c66affSColin Finck                 ptr = DPA_DeletePtr (hdpa1, nIndex);
344*c2c66affSColin Finck 
345*c2c66affSColin Finck                 (pfnMerge)(DPAMM_DELETE, ptr, NULL, lParam);
346*c2c66affSColin Finck             }
347*c2c66affSColin Finck             nIndex--;
348*c2c66affSColin Finck         }
349*c2c66affSColin Finck         else
350*c2c66affSColin Finck         {
351*c2c66affSColin Finck             /* new item in DPA 2 */
352*c2c66affSColin Finck             if (dwFlags & DPAM_UNION)
353*c2c66affSColin Finck             {
354*c2c66affSColin Finck                 /* Now insert the new item in DPA 1 */
355*c2c66affSColin Finck                 PVOID ptr;
356*c2c66affSColin Finck 
357*c2c66affSColin Finck                 ptr = (pfnMerge)(DPAMM_INSERT, *pWork2, NULL, lParam);
358*c2c66affSColin Finck                 if (!ptr)
359*c2c66affSColin Finck                     return FALSE;
360*c2c66affSColin Finck                 DPA_InsertPtr (hdpa1, nIndex+1, ptr);
361*c2c66affSColin Finck             }
362*c2c66affSColin Finck             nCount--;
363*c2c66affSColin Finck         }
364*c2c66affSColin Finck 
365*c2c66affSColin Finck     }
366*c2c66affSColin Finck     while (nCount >= 0);
367*c2c66affSColin Finck 
368*c2c66affSColin Finck     return TRUE;
369*c2c66affSColin Finck }
370*c2c66affSColin Finck 
371*c2c66affSColin Finck 
372*c2c66affSColin Finck /**************************************************************************
373*c2c66affSColin Finck  * DPA_Destroy [COMCTL32.329]
374*c2c66affSColin Finck  *
375*c2c66affSColin Finck  * Destroys a dynamic pointer array
376*c2c66affSColin Finck  *
377*c2c66affSColin Finck  * PARAMS
378*c2c66affSColin Finck  *     hdpa [I] handle (pointer) to the pointer array
379*c2c66affSColin Finck  *
380*c2c66affSColin Finck  * RETURNS
381*c2c66affSColin Finck  *     Success: TRUE
382*c2c66affSColin Finck  *     Failure: FALSE
383*c2c66affSColin Finck  */
384*c2c66affSColin Finck BOOL WINAPI DPA_Destroy (HDPA hdpa)
385*c2c66affSColin Finck {
386*c2c66affSColin Finck     TRACE("(%p)\n", hdpa);
387*c2c66affSColin Finck 
388*c2c66affSColin Finck     if (!hdpa)
389*c2c66affSColin Finck         return FALSE;
390*c2c66affSColin Finck 
391*c2c66affSColin Finck     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
392*c2c66affSColin Finck         return FALSE;
393*c2c66affSColin Finck 
394*c2c66affSColin Finck     return HeapFree (hdpa->hHeap, 0, hdpa);
395*c2c66affSColin Finck }
396*c2c66affSColin Finck 
397*c2c66affSColin Finck 
398*c2c66affSColin Finck /**************************************************************************
399*c2c66affSColin Finck  * DPA_Grow [COMCTL32.330]
400*c2c66affSColin Finck  *
401*c2c66affSColin Finck  * Sets the growth amount.
402*c2c66affSColin Finck  *
403*c2c66affSColin Finck  * PARAMS
404*c2c66affSColin Finck  *     hdpa  [I] handle (pointer) to the existing (source) pointer array
405*c2c66affSColin Finck  *     nGrow [I] number of items by which the array grows when it's too small
406*c2c66affSColin Finck  *
407*c2c66affSColin Finck  * RETURNS
408*c2c66affSColin Finck  *     Success: TRUE
409*c2c66affSColin Finck  *     Failure: FALSE
410*c2c66affSColin Finck  */
411*c2c66affSColin Finck BOOL WINAPI DPA_Grow (HDPA hdpa, INT nGrow)
412*c2c66affSColin Finck {
413*c2c66affSColin Finck     INT items;
414*c2c66affSColin Finck     TRACE("(%p %d)\n", hdpa, nGrow);
415*c2c66affSColin Finck 
416*c2c66affSColin Finck     if (!hdpa)
417*c2c66affSColin Finck         return FALSE;
418*c2c66affSColin Finck 
419*c2c66affSColin Finck     nGrow = max( 8, nGrow );
420*c2c66affSColin Finck     items = nGrow * (((hdpa->nMaxCount - 1) / nGrow) + 1);
421*c2c66affSColin Finck     if (items > hdpa->nMaxCount)
422*c2c66affSColin Finck     {
423*c2c66affSColin Finck         void *ptr;
424*c2c66affSColin Finck 
425*c2c66affSColin Finck         if (hdpa->ptrs)
426*c2c66affSColin Finck             ptr = HeapReAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, items * sizeof(LPVOID) );
427*c2c66affSColin Finck         else
428*c2c66affSColin Finck             ptr = HeapAlloc( hdpa->hHeap, HEAP_ZERO_MEMORY, items * sizeof(LPVOID) );
429*c2c66affSColin Finck         if (!ptr) return FALSE;
430*c2c66affSColin Finck         hdpa->nMaxCount = items;
431*c2c66affSColin Finck         hdpa->ptrs = ptr;
432*c2c66affSColin Finck     }
433*c2c66affSColin Finck     hdpa->nGrow = nGrow;
434*c2c66affSColin Finck 
435*c2c66affSColin Finck     return TRUE;
436*c2c66affSColin Finck }
437*c2c66affSColin Finck 
438*c2c66affSColin Finck 
439*c2c66affSColin Finck /**************************************************************************
440*c2c66affSColin Finck  * DPA_Clone [COMCTL32.331]
441*c2c66affSColin Finck  *
442*c2c66affSColin Finck  * Copies a pointer array to another one or creates a copy
443*c2c66affSColin Finck  *
444*c2c66affSColin Finck  * PARAMS
445*c2c66affSColin Finck  *     hdpa    [I] handle (pointer) to the existing (source) pointer array
446*c2c66affSColin Finck  *     hdpaNew [O] handle (pointer) to the destination pointer array
447*c2c66affSColin Finck  *
448*c2c66affSColin Finck  * RETURNS
449*c2c66affSColin Finck  *     Success: pointer to the destination pointer array.
450*c2c66affSColin Finck  *     Failure: NULL
451*c2c66affSColin Finck  *
452*c2c66affSColin Finck  * NOTES
453*c2c66affSColin Finck  *     - If the 'hdpaNew' is a NULL-Pointer, a copy of the source pointer
454*c2c66affSColin Finck  *       array will be created and its handle (pointer) is returned.
455*c2c66affSColin Finck  *     - If 'hdpa' is a NULL-Pointer, the original implementation crashes,
456*c2c66affSColin Finck  *       this implementation just returns NULL.
457*c2c66affSColin Finck  */
458*c2c66affSColin Finck HDPA WINAPI DPA_Clone (const HDPA hdpa, HDPA hdpaNew)
459*c2c66affSColin Finck {
460*c2c66affSColin Finck     INT nNewItems, nSize;
461*c2c66affSColin Finck     HDPA hdpaTemp;
462*c2c66affSColin Finck 
463*c2c66affSColin Finck     if (!hdpa)
464*c2c66affSColin Finck         return NULL;
465*c2c66affSColin Finck 
466*c2c66affSColin Finck     TRACE("(%p %p)\n", hdpa, hdpaNew);
467*c2c66affSColin Finck 
468*c2c66affSColin Finck     if (!hdpaNew) {
469*c2c66affSColin Finck         /* create a new DPA */
470*c2c66affSColin Finck         hdpaTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
471*c2c66affSColin Finck                                     sizeof(*hdpaTemp));
472*c2c66affSColin Finck         hdpaTemp->hHeap = hdpa->hHeap;
473*c2c66affSColin Finck         hdpaTemp->nGrow = hdpa->nGrow;
474*c2c66affSColin Finck     }
475*c2c66affSColin Finck     else
476*c2c66affSColin Finck         hdpaTemp = hdpaNew;
477*c2c66affSColin Finck 
478*c2c66affSColin Finck     if (hdpaTemp->ptrs) {
479*c2c66affSColin Finck         /* remove old pointer array */
480*c2c66affSColin Finck         HeapFree (hdpaTemp->hHeap, 0, hdpaTemp->ptrs);
481*c2c66affSColin Finck         hdpaTemp->ptrs = NULL;
482*c2c66affSColin Finck         hdpaTemp->nItemCount = 0;
483*c2c66affSColin Finck         hdpaTemp->nMaxCount = 0;
484*c2c66affSColin Finck     }
485*c2c66affSColin Finck 
486*c2c66affSColin Finck     /* create a new pointer array */
487*c2c66affSColin Finck     nNewItems = hdpaTemp->nGrow *
488*c2c66affSColin Finck                 (((hdpa->nItemCount - 1) / hdpaTemp->nGrow) + 1);
489*c2c66affSColin Finck     nSize = nNewItems * sizeof(LPVOID);
490*c2c66affSColin Finck     hdpaTemp->ptrs = HeapAlloc (hdpaTemp->hHeap, HEAP_ZERO_MEMORY, nSize);
491*c2c66affSColin Finck     hdpaTemp->nMaxCount = nNewItems;
492*c2c66affSColin Finck 
493*c2c66affSColin Finck     /* clone the pointer array */
494*c2c66affSColin Finck     hdpaTemp->nItemCount = hdpa->nItemCount;
495*c2c66affSColin Finck     memmove (hdpaTemp->ptrs, hdpa->ptrs,
496*c2c66affSColin Finck              hdpaTemp->nItemCount * sizeof(LPVOID));
497*c2c66affSColin Finck 
498*c2c66affSColin Finck     return hdpaTemp;
499*c2c66affSColin Finck }
500*c2c66affSColin Finck 
501*c2c66affSColin Finck 
502*c2c66affSColin Finck /**************************************************************************
503*c2c66affSColin Finck  * DPA_GetPtr [COMCTL32.332]
504*c2c66affSColin Finck  *
505*c2c66affSColin Finck  * Retrieves a pointer from a dynamic pointer array
506*c2c66affSColin Finck  *
507*c2c66affSColin Finck  * PARAMS
508*c2c66affSColin Finck  *     hdpa   [I] handle (pointer) to the pointer array
509*c2c66affSColin Finck  *     nIndex [I] array index of the desired pointer
510*c2c66affSColin Finck  *
511*c2c66affSColin Finck  * RETURNS
512*c2c66affSColin Finck  *     Success: pointer
513*c2c66affSColin Finck  *     Failure: NULL
514*c2c66affSColin Finck  */
515*c2c66affSColin Finck LPVOID WINAPI DPA_GetPtr (HDPA hdpa, INT nIndex)
516*c2c66affSColin Finck {
517*c2c66affSColin Finck     TRACE("(%p %d)\n", hdpa, nIndex);
518*c2c66affSColin Finck 
519*c2c66affSColin Finck     if (!hdpa)
520*c2c66affSColin Finck         return NULL;
521*c2c66affSColin Finck     if (!hdpa->ptrs) {
522*c2c66affSColin Finck         WARN("no pointer array.\n");
523*c2c66affSColin Finck         return NULL;
524*c2c66affSColin Finck     }
525*c2c66affSColin Finck     if ((nIndex < 0) || (nIndex >= hdpa->nItemCount)) {
526*c2c66affSColin Finck         WARN("not enough pointers in array (%d vs %d).\n",nIndex,hdpa->nItemCount);
527*c2c66affSColin Finck         return NULL;
528*c2c66affSColin Finck     }
529*c2c66affSColin Finck 
530*c2c66affSColin Finck     TRACE("-- %p\n", hdpa->ptrs[nIndex]);
531*c2c66affSColin Finck 
532*c2c66affSColin Finck     return hdpa->ptrs[nIndex];
533*c2c66affSColin Finck }
534*c2c66affSColin Finck 
535*c2c66affSColin Finck 
536*c2c66affSColin Finck /**************************************************************************
537*c2c66affSColin Finck  * DPA_GetPtrIndex [COMCTL32.333]
538*c2c66affSColin Finck  *
539*c2c66affSColin Finck  * Retrieves the index of the specified pointer
540*c2c66affSColin Finck  *
541*c2c66affSColin Finck  * PARAMS
542*c2c66affSColin Finck  *     hdpa   [I] handle (pointer) to the pointer array
543*c2c66affSColin Finck  *     p      [I] pointer
544*c2c66affSColin Finck  *
545*c2c66affSColin Finck  * RETURNS
546*c2c66affSColin Finck  *     Success: index of the specified pointer
547*c2c66affSColin Finck  *     Failure: -1
548*c2c66affSColin Finck  */
549*c2c66affSColin Finck INT WINAPI DPA_GetPtrIndex (HDPA hdpa, LPCVOID p)
550*c2c66affSColin Finck {
551*c2c66affSColin Finck     INT i;
552*c2c66affSColin Finck 
553*c2c66affSColin Finck     if (!hdpa || !hdpa->ptrs)
554*c2c66affSColin Finck         return -1;
555*c2c66affSColin Finck 
556*c2c66affSColin Finck     for (i = 0; i < hdpa->nItemCount; i++) {
557*c2c66affSColin Finck         if (hdpa->ptrs[i] == p)
558*c2c66affSColin Finck             return i;
559*c2c66affSColin Finck     }
560*c2c66affSColin Finck 
561*c2c66affSColin Finck     return -1;
562*c2c66affSColin Finck }
563*c2c66affSColin Finck 
564*c2c66affSColin Finck 
565*c2c66affSColin Finck /**************************************************************************
566*c2c66affSColin Finck  * DPA_InsertPtr [COMCTL32.334]
567*c2c66affSColin Finck  *
568*c2c66affSColin Finck  * Inserts a pointer into a dynamic pointer array
569*c2c66affSColin Finck  *
570*c2c66affSColin Finck  * PARAMS
571*c2c66affSColin Finck  *     hdpa [I] handle (pointer) to the array
572*c2c66affSColin Finck  *     i    [I] array index
573*c2c66affSColin Finck  *     p    [I] pointer to insert
574*c2c66affSColin Finck  *
575*c2c66affSColin Finck  * RETURNS
576*c2c66affSColin Finck  *     Success: index of the inserted pointer
577*c2c66affSColin Finck  *     Failure: -1
578*c2c66affSColin Finck  */
579*c2c66affSColin Finck INT WINAPI DPA_InsertPtr (HDPA hdpa, INT i, LPVOID p)
580*c2c66affSColin Finck {
581*c2c66affSColin Finck     TRACE("(%p %d %p)\n", hdpa, i, p);
582*c2c66affSColin Finck 
583*c2c66affSColin Finck     if (!hdpa || i < 0) return -1;
584*c2c66affSColin Finck 
585*c2c66affSColin Finck     /* append item if index is out of bounds */
586*c2c66affSColin Finck     i = min(hdpa->nItemCount, i);
587*c2c66affSColin Finck 
588*c2c66affSColin Finck     /* create empty spot at the end */
589*c2c66affSColin Finck     if (!DPA_SetPtr(hdpa, hdpa->nItemCount, 0)) return -1;
590*c2c66affSColin Finck 
591*c2c66affSColin Finck     if (i != hdpa->nItemCount - 1)
592*c2c66affSColin Finck         memmove (hdpa->ptrs + i + 1, hdpa->ptrs + i,
593*c2c66affSColin Finck                  (hdpa->nItemCount - i - 1) * sizeof(LPVOID));
594*c2c66affSColin Finck 
595*c2c66affSColin Finck     hdpa->ptrs[i] = p;
596*c2c66affSColin Finck     return i;
597*c2c66affSColin Finck }
598*c2c66affSColin Finck 
599*c2c66affSColin Finck 
600*c2c66affSColin Finck /**************************************************************************
601*c2c66affSColin Finck  * DPA_SetPtr [COMCTL32.335]
602*c2c66affSColin Finck  *
603*c2c66affSColin Finck  * Sets a pointer in the pointer array
604*c2c66affSColin Finck  *
605*c2c66affSColin Finck  * PARAMS
606*c2c66affSColin Finck  *     hdpa [I] handle (pointer) to the pointer array
607*c2c66affSColin Finck  *     i    [I] index of the pointer that will be set
608*c2c66affSColin Finck  *     p    [I] pointer to be set
609*c2c66affSColin Finck  *
610*c2c66affSColin Finck  * RETURNS
611*c2c66affSColin Finck  *     Success: TRUE
612*c2c66affSColin Finck  *     Failure: FALSE
613*c2c66affSColin Finck  */
614*c2c66affSColin Finck BOOL WINAPI DPA_SetPtr (HDPA hdpa, INT i, LPVOID p)
615*c2c66affSColin Finck {
616*c2c66affSColin Finck     LPVOID *lpTemp;
617*c2c66affSColin Finck 
618*c2c66affSColin Finck     TRACE("(%p %d %p)\n", hdpa, i, p);
619*c2c66affSColin Finck 
620*c2c66affSColin Finck     if (!hdpa || i < 0)
621*c2c66affSColin Finck         return FALSE;
622*c2c66affSColin Finck 
623*c2c66affSColin Finck     if (hdpa->nItemCount <= i) {
624*c2c66affSColin Finck         /* within the old array */
625*c2c66affSColin Finck         if (hdpa->nMaxCount <= i) {
626*c2c66affSColin Finck             /* resize the block of memory */
627*c2c66affSColin Finck             INT nNewItems =
628*c2c66affSColin Finck                 hdpa->nGrow * ((((i+1) - 1) / hdpa->nGrow) + 1);
629*c2c66affSColin Finck             INT nSize = nNewItems * sizeof(LPVOID);
630*c2c66affSColin Finck 
631*c2c66affSColin Finck             if (hdpa->ptrs)
632*c2c66affSColin Finck                 lpTemp = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, hdpa->ptrs, nSize);
633*c2c66affSColin Finck             else
634*c2c66affSColin Finck                 lpTemp = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, nSize);
635*c2c66affSColin Finck 
636*c2c66affSColin Finck             if (!lpTemp)
637*c2c66affSColin Finck                 return FALSE;
638*c2c66affSColin Finck 
639*c2c66affSColin Finck             hdpa->nMaxCount = nNewItems;
640*c2c66affSColin Finck             hdpa->ptrs = lpTemp;
641*c2c66affSColin Finck         }
642*c2c66affSColin Finck         hdpa->nItemCount = i+1;
643*c2c66affSColin Finck     }
644*c2c66affSColin Finck 
645*c2c66affSColin Finck     /* put the new entry in */
646*c2c66affSColin Finck     hdpa->ptrs[i] = p;
647*c2c66affSColin Finck 
648*c2c66affSColin Finck     return TRUE;
649*c2c66affSColin Finck }
650*c2c66affSColin Finck 
651*c2c66affSColin Finck 
652*c2c66affSColin Finck /**************************************************************************
653*c2c66affSColin Finck  * DPA_DeletePtr [COMCTL32.336]
654*c2c66affSColin Finck  *
655*c2c66affSColin Finck  * Removes a pointer from the pointer array.
656*c2c66affSColin Finck  *
657*c2c66affSColin Finck  * PARAMS
658*c2c66affSColin Finck  *     hdpa [I] handle (pointer) to the pointer array
659*c2c66affSColin Finck  *     i    [I] index of the pointer that will be deleted
660*c2c66affSColin Finck  *
661*c2c66affSColin Finck  * RETURNS
662*c2c66affSColin Finck  *     Success: deleted pointer
663*c2c66affSColin Finck  *     Failure: NULL
664*c2c66affSColin Finck  */
665*c2c66affSColin Finck LPVOID WINAPI DPA_DeletePtr (HDPA hdpa, INT i)
666*c2c66affSColin Finck {
667*c2c66affSColin Finck     LPVOID *lpDest, *lpSrc, lpTemp = NULL;
668*c2c66affSColin Finck     INT  nSize;
669*c2c66affSColin Finck 
670*c2c66affSColin Finck     TRACE("(%p %d)\n", hdpa, i);
671*c2c66affSColin Finck 
672*c2c66affSColin Finck     if ((!hdpa) || i < 0 || i >= hdpa->nItemCount)
673*c2c66affSColin Finck         return NULL;
674*c2c66affSColin Finck 
675*c2c66affSColin Finck     lpTemp = hdpa->ptrs[i];
676*c2c66affSColin Finck 
677*c2c66affSColin Finck     /* do we need to move ?*/
678*c2c66affSColin Finck     if (i < hdpa->nItemCount - 1) {
679*c2c66affSColin Finck         lpDest = hdpa->ptrs + i;
680*c2c66affSColin Finck         lpSrc = lpDest + 1;
681*c2c66affSColin Finck         nSize = (hdpa->nItemCount - i - 1) * sizeof(LPVOID);
682*c2c66affSColin Finck         TRACE("-- move dest=%p src=%p size=%x\n",
683*c2c66affSColin Finck                lpDest, lpSrc, nSize);
684*c2c66affSColin Finck         memmove (lpDest, lpSrc, nSize);
685*c2c66affSColin Finck     }
686*c2c66affSColin Finck 
687*c2c66affSColin Finck     hdpa->nItemCount --;
688*c2c66affSColin Finck 
689*c2c66affSColin Finck     /* free memory ?*/
690*c2c66affSColin Finck     if ((hdpa->nMaxCount - hdpa->nItemCount) >= hdpa->nGrow) {
691*c2c66affSColin Finck         INT nNewItems = max(hdpa->nGrow * 2, hdpa->nItemCount);
692*c2c66affSColin Finck         nSize = nNewItems * sizeof(LPVOID);
693*c2c66affSColin Finck         lpDest = HeapReAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
694*c2c66affSColin Finck                                       hdpa->ptrs, nSize);
695*c2c66affSColin Finck         if (!lpDest)
696*c2c66affSColin Finck             return NULL;
697*c2c66affSColin Finck 
698*c2c66affSColin Finck         hdpa->nMaxCount = nNewItems;
699*c2c66affSColin Finck         hdpa->ptrs = lpDest;
700*c2c66affSColin Finck     }
701*c2c66affSColin Finck 
702*c2c66affSColin Finck     return lpTemp;
703*c2c66affSColin Finck }
704*c2c66affSColin Finck 
705*c2c66affSColin Finck 
706*c2c66affSColin Finck /**************************************************************************
707*c2c66affSColin Finck  * DPA_DeleteAllPtrs [COMCTL32.337]
708*c2c66affSColin Finck  *
709*c2c66affSColin Finck  * Removes all pointers and reinitializes the array.
710*c2c66affSColin Finck  *
711*c2c66affSColin Finck  * PARAMS
712*c2c66affSColin Finck  *     hdpa [I] handle (pointer) to the pointer array
713*c2c66affSColin Finck  *
714*c2c66affSColin Finck  * RETURNS
715*c2c66affSColin Finck  *     Success: TRUE
716*c2c66affSColin Finck  *     Failure: FALSE
717*c2c66affSColin Finck  */
718*c2c66affSColin Finck BOOL WINAPI DPA_DeleteAllPtrs (HDPA hdpa)
719*c2c66affSColin Finck {
720*c2c66affSColin Finck     TRACE("(%p)\n", hdpa);
721*c2c66affSColin Finck 
722*c2c66affSColin Finck     if (!hdpa)
723*c2c66affSColin Finck         return FALSE;
724*c2c66affSColin Finck 
725*c2c66affSColin Finck     if (hdpa->ptrs && (!HeapFree (hdpa->hHeap, 0, hdpa->ptrs)))
726*c2c66affSColin Finck         return FALSE;
727*c2c66affSColin Finck 
728*c2c66affSColin Finck     hdpa->nItemCount = 0;
729*c2c66affSColin Finck     hdpa->nMaxCount = hdpa->nGrow * 2;
730*c2c66affSColin Finck     hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
731*c2c66affSColin Finck                                      hdpa->nMaxCount * sizeof(LPVOID));
732*c2c66affSColin Finck 
733*c2c66affSColin Finck     return TRUE;
734*c2c66affSColin Finck }
735*c2c66affSColin Finck 
736*c2c66affSColin Finck 
737*c2c66affSColin Finck /**************************************************************************
738*c2c66affSColin Finck  * DPA_QuickSort [Internal]
739*c2c66affSColin Finck  *
740*c2c66affSColin Finck  * Ordinary quicksort (used by DPA_Sort).
741*c2c66affSColin Finck  *
742*c2c66affSColin Finck  * PARAMS
743*c2c66affSColin Finck  *     lpPtrs     [I] pointer to the pointer array
744*c2c66affSColin Finck  *     l          [I] index of the "left border" of the partition
745*c2c66affSColin Finck  *     r          [I] index of the "right border" of the partition
746*c2c66affSColin Finck  *     pfnCompare [I] pointer to the compare function
747*c2c66affSColin Finck  *     lParam     [I] user defined value (3rd parameter in compare function)
748*c2c66affSColin Finck  *
749*c2c66affSColin Finck  * RETURNS
750*c2c66affSColin Finck  *     NONE
751*c2c66affSColin Finck  */
752*c2c66affSColin Finck static VOID DPA_QuickSort (LPVOID *lpPtrs, INT l, INT r,
753*c2c66affSColin Finck                            PFNDPACOMPARE pfnCompare, LPARAM lParam)
754*c2c66affSColin Finck {
755*c2c66affSColin Finck     INT m;
756*c2c66affSColin Finck     LPVOID t;
757*c2c66affSColin Finck 
758*c2c66affSColin Finck     TRACE("l=%i r=%i\n", l, r);
759*c2c66affSColin Finck 
760*c2c66affSColin Finck     if (l==r)    /* one element is always sorted */
761*c2c66affSColin Finck         return;
762*c2c66affSColin Finck     if (r<l)     /* oops, got it in the wrong order */
763*c2c66affSColin Finck         {
764*c2c66affSColin Finck         DPA_QuickSort(lpPtrs, r, l, pfnCompare, lParam);
765*c2c66affSColin Finck         return;
766*c2c66affSColin Finck         }
767*c2c66affSColin Finck     m = (l+r)/2; /* divide by two */
768*c2c66affSColin Finck     DPA_QuickSort(lpPtrs, l, m, pfnCompare, lParam);
769*c2c66affSColin Finck     DPA_QuickSort(lpPtrs, m+1, r, pfnCompare, lParam);
770*c2c66affSColin Finck 
771*c2c66affSColin Finck     /* join the two sides */
772*c2c66affSColin Finck     while( (l<=m) && (m<r) )
773*c2c66affSColin Finck     {
774*c2c66affSColin Finck         if(pfnCompare(lpPtrs[l],lpPtrs[m+1],lParam)>0)
775*c2c66affSColin Finck         {
776*c2c66affSColin Finck             t = lpPtrs[m+1];
777*c2c66affSColin Finck             memmove(&lpPtrs[l+1],&lpPtrs[l],(m-l+1)*sizeof(lpPtrs[l]));
778*c2c66affSColin Finck             lpPtrs[l] = t;
779*c2c66affSColin Finck 
780*c2c66affSColin Finck             m++;
781*c2c66affSColin Finck         }
782*c2c66affSColin Finck         l++;
783*c2c66affSColin Finck     }
784*c2c66affSColin Finck }
785*c2c66affSColin Finck 
786*c2c66affSColin Finck 
787*c2c66affSColin Finck /**************************************************************************
788*c2c66affSColin Finck  * DPA_Sort [COMCTL32.338]
789*c2c66affSColin Finck  *
790*c2c66affSColin Finck  * Sorts a pointer array using a user defined compare function
791*c2c66affSColin Finck  *
792*c2c66affSColin Finck  * PARAMS
793*c2c66affSColin Finck  *     hdpa       [I] handle (pointer) to the pointer array
794*c2c66affSColin Finck  *     pfnCompare [I] pointer to the compare function
795*c2c66affSColin Finck  *     lParam     [I] user defined value (3rd parameter of compare function)
796*c2c66affSColin Finck  *
797*c2c66affSColin Finck  * RETURNS
798*c2c66affSColin Finck  *     Success: TRUE
799*c2c66affSColin Finck  *     Failure: FALSE
800*c2c66affSColin Finck  */
801*c2c66affSColin Finck BOOL WINAPI DPA_Sort (HDPA hdpa, PFNDPACOMPARE pfnCompare, LPARAM lParam)
802*c2c66affSColin Finck {
803*c2c66affSColin Finck     if (!hdpa || !pfnCompare)
804*c2c66affSColin Finck         return FALSE;
805*c2c66affSColin Finck 
806*c2c66affSColin Finck     TRACE("(%p %p 0x%lx)\n", hdpa, pfnCompare, lParam);
807*c2c66affSColin Finck 
808*c2c66affSColin Finck     if ((hdpa->nItemCount > 1) && (hdpa->ptrs))
809*c2c66affSColin Finck         DPA_QuickSort (hdpa->ptrs, 0, hdpa->nItemCount - 1,
810*c2c66affSColin Finck                        pfnCompare, lParam);
811*c2c66affSColin Finck 
812*c2c66affSColin Finck     return TRUE;
813*c2c66affSColin Finck }
814*c2c66affSColin Finck 
815*c2c66affSColin Finck 
816*c2c66affSColin Finck /**************************************************************************
817*c2c66affSColin Finck  * DPA_Search [COMCTL32.339]
818*c2c66affSColin Finck  *
819*c2c66affSColin Finck  * Searches a pointer array for a specified pointer
820*c2c66affSColin Finck  *
821*c2c66affSColin Finck  * PARAMS
822*c2c66affSColin Finck  *     hdpa       [I] handle (pointer) to the pointer array
823*c2c66affSColin Finck  *     pFind      [I] pointer to search for
824*c2c66affSColin Finck  *     nStart     [I] start index
825*c2c66affSColin Finck  *     pfnCompare [I] pointer to the compare function
826*c2c66affSColin Finck  *     lParam     [I] user defined value (3rd parameter of compare function)
827*c2c66affSColin Finck  *     uOptions   [I] search options
828*c2c66affSColin Finck  *
829*c2c66affSColin Finck  * RETURNS
830*c2c66affSColin Finck  *     Success: index of the pointer in the array.
831*c2c66affSColin Finck  *     Failure: -1
832*c2c66affSColin Finck  */
833*c2c66affSColin Finck INT WINAPI DPA_Search (HDPA hdpa, LPVOID pFind, INT nStart,
834*c2c66affSColin Finck                        PFNDPACOMPARE pfnCompare, LPARAM lParam, UINT uOptions)
835*c2c66affSColin Finck {
836*c2c66affSColin Finck     if (!hdpa || !pfnCompare || !pFind)
837*c2c66affSColin Finck         return -1;
838*c2c66affSColin Finck 
839*c2c66affSColin Finck     TRACE("(%p %p %d %p 0x%08lx 0x%08x)\n",
840*c2c66affSColin Finck            hdpa, pFind, nStart, pfnCompare, lParam, uOptions);
841*c2c66affSColin Finck 
842*c2c66affSColin Finck     if (uOptions & DPAS_SORTED) {
843*c2c66affSColin Finck         /* array is sorted --> use binary search */
844*c2c66affSColin Finck         INT l, r, x, n;
845*c2c66affSColin Finck         LPVOID *lpPtr;
846*c2c66affSColin Finck 
847*c2c66affSColin Finck         /* for binary search ignore start index */
848*c2c66affSColin Finck         l = 0;
849*c2c66affSColin Finck         r = hdpa->nItemCount - 1;
850*c2c66affSColin Finck         lpPtr = hdpa->ptrs;
851*c2c66affSColin Finck         while (r >= l) {
852*c2c66affSColin Finck             x = (l + r) / 2;
853*c2c66affSColin Finck             n = (pfnCompare)(pFind, lpPtr[x], lParam);
854*c2c66affSColin Finck             if (n == 0)
855*c2c66affSColin Finck                 return x;
856*c2c66affSColin Finck             else if (n < 0)
857*c2c66affSColin Finck                 r = x - 1;
858*c2c66affSColin Finck             else /* (n > 0) */
859*c2c66affSColin Finck                 l = x + 1;
860*c2c66affSColin Finck         }
861*c2c66affSColin Finck         if (uOptions & (DPAS_INSERTBEFORE|DPAS_INSERTAFTER)) return l;
862*c2c66affSColin Finck     }
863*c2c66affSColin Finck     else {
864*c2c66affSColin Finck         /* array is not sorted --> use linear search */
865*c2c66affSColin Finck         LPVOID *lpPtr;
866*c2c66affSColin Finck         INT  nIndex;
867*c2c66affSColin Finck 
868*c2c66affSColin Finck         nIndex = (nStart == -1)? 0 : nStart;
869*c2c66affSColin Finck         lpPtr = hdpa->ptrs;
870*c2c66affSColin Finck         for (; nIndex < hdpa->nItemCount; nIndex++) {
871*c2c66affSColin Finck             if ((pfnCompare)(pFind, lpPtr[nIndex], lParam) == 0)
872*c2c66affSColin Finck                 return nIndex;
873*c2c66affSColin Finck         }
874*c2c66affSColin Finck     }
875*c2c66affSColin Finck 
876*c2c66affSColin Finck     return -1;
877*c2c66affSColin Finck }
878*c2c66affSColin Finck 
879*c2c66affSColin Finck 
880*c2c66affSColin Finck /**************************************************************************
881*c2c66affSColin Finck  * DPA_CreateEx [COMCTL32.340]
882*c2c66affSColin Finck  *
883*c2c66affSColin Finck  * Creates a dynamic pointer array using the specified size and heap.
884*c2c66affSColin Finck  *
885*c2c66affSColin Finck  * PARAMS
886*c2c66affSColin Finck  *     nGrow [I] number of items by which the array grows when it is filled
887*c2c66affSColin Finck  *     hHeap [I] handle to the heap where the array is stored
888*c2c66affSColin Finck  *
889*c2c66affSColin Finck  * RETURNS
890*c2c66affSColin Finck  *     Success: handle (pointer) to the pointer array.
891*c2c66affSColin Finck  *     Failure: NULL
892*c2c66affSColin Finck  *
893*c2c66affSColin Finck  * NOTES
894*c2c66affSColin Finck  *     The DPA_ functions can be used to create and manipulate arrays of
895*c2c66affSColin Finck  *     pointers.
896*c2c66affSColin Finck  */
897*c2c66affSColin Finck HDPA WINAPI DPA_CreateEx (INT nGrow, HANDLE hHeap)
898*c2c66affSColin Finck {
899*c2c66affSColin Finck     HDPA hdpa;
900*c2c66affSColin Finck 
901*c2c66affSColin Finck     TRACE("(%d %p)\n", nGrow, hHeap);
902*c2c66affSColin Finck 
903*c2c66affSColin Finck     if (hHeap)
904*c2c66affSColin Finck         hdpa = HeapAlloc (hHeap, HEAP_ZERO_MEMORY, sizeof(*hdpa));
905*c2c66affSColin Finck     else
906*c2c66affSColin Finck         hdpa = Alloc (sizeof(*hdpa));
907*c2c66affSColin Finck 
908*c2c66affSColin Finck     if (hdpa) {
909*c2c66affSColin Finck         hdpa->nGrow = max(8, nGrow);
910*c2c66affSColin Finck         hdpa->hHeap = hHeap ? hHeap : GetProcessHeap();
911*c2c66affSColin Finck         hdpa->nMaxCount = hdpa->nGrow * 2;
912*c2c66affSColin Finck         hdpa->ptrs = HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
913*c2c66affSColin Finck                                 hdpa->nMaxCount * sizeof(LPVOID));
914*c2c66affSColin Finck     }
915*c2c66affSColin Finck 
916*c2c66affSColin Finck     TRACE("-- %p\n", hdpa);
917*c2c66affSColin Finck 
918*c2c66affSColin Finck     return hdpa;
919*c2c66affSColin Finck }
920*c2c66affSColin Finck 
921*c2c66affSColin Finck 
922*c2c66affSColin Finck /**************************************************************************
923*c2c66affSColin Finck  * DPA_Create [COMCTL32.328]
924*c2c66affSColin Finck  *
925*c2c66affSColin Finck  * Creates a dynamic pointer array.
926*c2c66affSColin Finck  *
927*c2c66affSColin Finck  * PARAMS
928*c2c66affSColin Finck  *     nGrow [I] number of items by which the array grows when it is filled
929*c2c66affSColin Finck  *
930*c2c66affSColin Finck  * RETURNS
931*c2c66affSColin Finck  *     Success: handle (pointer) to the pointer array.
932*c2c66affSColin Finck  *     Failure: NULL
933*c2c66affSColin Finck  *
934*c2c66affSColin Finck  * NOTES
935*c2c66affSColin Finck  *     The DPA_ functions can be used to create and manipulate arrays of
936*c2c66affSColin Finck  *     pointers.
937*c2c66affSColin Finck  */
938*c2c66affSColin Finck HDPA WINAPI DPA_Create (INT nGrow)
939*c2c66affSColin Finck {
940*c2c66affSColin Finck     return DPA_CreateEx( nGrow, 0 );
941*c2c66affSColin Finck }
942*c2c66affSColin Finck 
943*c2c66affSColin Finck 
944*c2c66affSColin Finck /**************************************************************************
945*c2c66affSColin Finck  * DPA_EnumCallback [COMCTL32.385]
946*c2c66affSColin Finck  *
947*c2c66affSColin Finck  * Enumerates all items in a dynamic pointer array.
948*c2c66affSColin Finck  *
949*c2c66affSColin Finck  * PARAMS
950*c2c66affSColin Finck  *     hdpa     [I] handle to the dynamic pointer array
951*c2c66affSColin Finck  *     enumProc [I]
952*c2c66affSColin Finck  *     lParam   [I]
953*c2c66affSColin Finck  *
954*c2c66affSColin Finck  * RETURNS
955*c2c66affSColin Finck  *     none
956*c2c66affSColin Finck  */
957*c2c66affSColin Finck VOID WINAPI DPA_EnumCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
958*c2c66affSColin Finck                               LPVOID lParam)
959*c2c66affSColin Finck {
960*c2c66affSColin Finck     INT i;
961*c2c66affSColin Finck 
962*c2c66affSColin Finck     TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
963*c2c66affSColin Finck 
964*c2c66affSColin Finck     if (!hdpa)
965*c2c66affSColin Finck         return;
966*c2c66affSColin Finck     if (hdpa->nItemCount <= 0)
967*c2c66affSColin Finck         return;
968*c2c66affSColin Finck 
969*c2c66affSColin Finck     for (i = 0; i < hdpa->nItemCount; i++) {
970*c2c66affSColin Finck         if ((enumProc)(hdpa->ptrs[i], lParam) == 0)
971*c2c66affSColin Finck             return;
972*c2c66affSColin Finck     }
973*c2c66affSColin Finck 
974*c2c66affSColin Finck     return;
975*c2c66affSColin Finck }
976*c2c66affSColin Finck 
977*c2c66affSColin Finck 
978*c2c66affSColin Finck /**************************************************************************
979*c2c66affSColin Finck  * DPA_DestroyCallback [COMCTL32.386]
980*c2c66affSColin Finck  *
981*c2c66affSColin Finck  * Enumerates all items in a dynamic pointer array and destroys it.
982*c2c66affSColin Finck  *
983*c2c66affSColin Finck  * PARAMS
984*c2c66affSColin Finck  *     hdpa     [I] handle to the dynamic pointer array
985*c2c66affSColin Finck  *     enumProc [I]
986*c2c66affSColin Finck  *     lParam   [I]
987*c2c66affSColin Finck  *
988*c2c66affSColin Finck  * RETURNS
989*c2c66affSColin Finck  *     none
990*c2c66affSColin Finck  */
991*c2c66affSColin Finck void WINAPI DPA_DestroyCallback (HDPA hdpa, PFNDPAENUMCALLBACK enumProc,
992*c2c66affSColin Finck                                  LPVOID lParam)
993*c2c66affSColin Finck {
994*c2c66affSColin Finck     TRACE("(%p %p %p)\n", hdpa, enumProc, lParam);
995*c2c66affSColin Finck 
996*c2c66affSColin Finck     DPA_EnumCallback (hdpa, enumProc, lParam);
997*c2c66affSColin Finck     DPA_Destroy (hdpa);
998*c2c66affSColin Finck }
999*c2c66affSColin Finck 
1000*c2c66affSColin Finck /**************************************************************************
1001*c2c66affSColin Finck  * DPA_GetSize [COMCTL32.@]
1002*c2c66affSColin Finck  *
1003*c2c66affSColin Finck  * Returns all array allocated memory size
1004*c2c66affSColin Finck  *
1005*c2c66affSColin Finck  * PARAMS
1006*c2c66affSColin Finck  *     hdpa     [I] handle to the dynamic pointer array
1007*c2c66affSColin Finck  *
1008*c2c66affSColin Finck  * RETURNS
1009*c2c66affSColin Finck  *     Size in bytes
1010*c2c66affSColin Finck  */
1011*c2c66affSColin Finck ULONGLONG WINAPI DPA_GetSize(HDPA hdpa)
1012*c2c66affSColin Finck {
1013*c2c66affSColin Finck     TRACE("(%p)\n", hdpa);
1014*c2c66affSColin Finck 
1015*c2c66affSColin Finck     if (!hdpa) return 0;
1016*c2c66affSColin Finck 
1017*c2c66affSColin Finck     return sizeof(DPA) + hdpa->nMaxCount*sizeof(PVOID);
1018*c2c66affSColin Finck }
1019