* Sync up to trunk HEAD (r62975).
[reactos.git] / dll / win32 / comctl32 / dsa.c
1 /*
2 * Dynamic structure array (DSA) implementation
3 *
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 *
22 * NOTES
23 * These functions were involuntarily documented by Microsoft in 2002 as
24 * the outcome of an anti-trust suit brought by various U.S. governments.
25 * As a result the specifications on MSDN are inaccurate, incomplete
26 * and misleading. A much more complete (unofficial) documentation is
27 * available at:
28 *
29 * http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32
30 */
31
32 #include "comctl32.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(dsa);
35
36 struct _DSA
37 {
38 INT nItemCount;
39 LPVOID pData;
40 INT nMaxCount;
41 INT nItemSize;
42 INT nGrow;
43 };
44
45 /**************************************************************************
46 * DSA_Create [COMCTL32.320]
47 *
48 * Creates a dynamic storage array
49 *
50 * PARAMS
51 * nSize [I] size of the array elements
52 * nGrow [I] number of elements by which the array grows when it is filled
53 *
54 * RETURNS
55 * Success: pointer to an array control structure. Use this like a handle.
56 * Failure: NULL
57 *
58 * NOTES
59 * The DSA_ functions can be used to create and manipulate arrays of
60 * fixed-size memory blocks. These arrays can store any kind of data
61 * (e.g. strings and icons).
62 */
63 HDSA WINAPI DSA_Create (INT nSize, INT nGrow)
64 {
65 HDSA hdsa;
66
67 TRACE("(size=%d grow=%d)\n", nSize, nGrow);
68
69 hdsa = Alloc (sizeof(*hdsa));
70 if (hdsa)
71 {
72 hdsa->nItemCount = 0;
73 hdsa->pData = NULL;
74 hdsa->nMaxCount = 0;
75 hdsa->nItemSize = nSize;
76 hdsa->nGrow = max(1, nGrow);
77 }
78
79 return hdsa;
80 }
81
82
83 /**************************************************************************
84 * DSA_Destroy [COMCTL32.321]
85 *
86 * Destroys a dynamic storage array
87 *
88 * PARAMS
89 * hdsa [I] pointer to the array control structure
90 *
91 * RETURNS
92 * Success: TRUE
93 * Failure: FALSE
94 */
95 BOOL WINAPI DSA_Destroy (HDSA hdsa)
96 {
97 TRACE("(%p)\n", hdsa);
98
99 if (!hdsa)
100 return FALSE;
101
102 if (hdsa->pData && (!Free (hdsa->pData)))
103 return FALSE;
104
105 return Free (hdsa);
106 }
107
108
109 /**************************************************************************
110 * DSA_GetItem [COMCTL32.322]
111 *
112 * Copies the specified item into a caller-supplied buffer.
113 *
114 * PARAMS
115 * hdsa [I] pointer to the array control structure
116 * nIndex [I] number of the Item to get
117 * pDest [O] destination buffer. Has to be >= dwElementSize.
118 *
119 * RETURNS
120 * Success: TRUE
121 * Failure: FALSE
122 */
123 BOOL WINAPI DSA_GetItem (HDSA hdsa, INT nIndex, LPVOID pDest)
124 {
125 LPVOID pSrc;
126
127 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);
128
129 if (!hdsa)
130 return FALSE;
131 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
132 return FALSE;
133
134 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
135 memmove (pDest, pSrc, hdsa->nItemSize);
136
137 return TRUE;
138 }
139
140
141 /**************************************************************************
142 * DSA_GetItemPtr [COMCTL32.323]
143 *
144 * Retrieves a pointer to the specified item.
145 *
146 * PARAMS
147 * hdsa [I] pointer to the array control structure
148 * nIndex [I] index of the desired item
149 *
150 * RETURNS
151 * Success: pointer to an item
152 * Failure: NULL
153 */
154 LPVOID WINAPI DSA_GetItemPtr (HDSA hdsa, INT nIndex)
155 {
156 LPVOID pSrc;
157
158 TRACE("(%p %d)\n", hdsa, nIndex);
159
160 if (!hdsa)
161 return NULL;
162 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))
163 return NULL;
164
165 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
166
167 TRACE("-- ret=%p\n", pSrc);
168
169 return pSrc;
170 }
171
172
173 /**************************************************************************
174 * DSA_SetItem [COMCTL32.325]
175 *
176 * Sets the contents of an item in the array.
177 *
178 * PARAMS
179 * hdsa [I] pointer to the array control structure
180 * nIndex [I] index for the item
181 * pSrc [I] pointer to the new item data
182 *
183 * RETURNS
184 * Success: TRUE
185 * Failure: FALSE
186 */
187 BOOL WINAPI DSA_SetItem (HDSA hdsa, INT nIndex, LPVOID pSrc)
188 {
189 INT nSize, nNewItems;
190 LPVOID pDest, lpTemp;
191
192 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
193
194 if ((!hdsa) || nIndex < 0)
195 return FALSE;
196
197 if (hdsa->nItemCount <= nIndex) {
198 /* within the old array */
199 if (hdsa->nMaxCount > nIndex) {
200 /* within the allocated space, set a new boundary */
201 hdsa->nItemCount = nIndex + 1;
202 }
203 else {
204 /* resize the block of memory */
205 nNewItems =
206 hdsa->nGrow * ((((nIndex + 1) - 1) / hdsa->nGrow) + 1);
207 nSize = hdsa->nItemSize * nNewItems;
208
209 lpTemp = ReAlloc (hdsa->pData, nSize);
210 if (!lpTemp)
211 return FALSE;
212
213 hdsa->nMaxCount = nNewItems;
214 hdsa->nItemCount = nIndex + 1;
215 hdsa->pData = lpTemp;
216 }
217 }
218
219 /* put the new entry in */
220 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
221 TRACE("-- move dest=%p src=%p size=%d\n",
222 pDest, pSrc, hdsa->nItemSize);
223 memmove (pDest, pSrc, hdsa->nItemSize);
224
225 return TRUE;
226 }
227
228
229 /**************************************************************************
230 * DSA_InsertItem [COMCTL32.324]
231 *
232 * Inserts an item into the array at the specified index.
233 *
234 * PARAMS
235 * hdsa [I] pointer to the array control structure
236 * nIndex [I] index for the new item
237 * pSrc [I] pointer to the element
238 *
239 * RETURNS
240 * Success: position of the new item
241 * Failure: -1
242 */
243 INT WINAPI DSA_InsertItem (HDSA hdsa, INT nIndex, LPVOID pSrc)
244 {
245 INT nNewItems, nSize;
246 LPVOID lpTemp, lpDest;
247
248 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);
249
250 if ((!hdsa) || nIndex < 0)
251 return -1;
252
253 /* when nIndex >= nItemCount then append */
254 if (nIndex >= hdsa->nItemCount)
255 nIndex = hdsa->nItemCount;
256
257 /* do we need to resize ? */
258 if (hdsa->nItemCount >= hdsa->nMaxCount) {
259 nNewItems = hdsa->nMaxCount + hdsa->nGrow;
260 nSize = hdsa->nItemSize * nNewItems;
261
262 lpTemp = ReAlloc (hdsa->pData, nSize);
263 if (!lpTemp)
264 return -1;
265
266 hdsa->nMaxCount = nNewItems;
267 hdsa->pData = lpTemp;
268 }
269
270 /* do we need to move elements ? */
271 if (nIndex < hdsa->nItemCount) {
272 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
273 lpDest = (char *) lpTemp + hdsa->nItemSize;
274 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;
275 TRACE("-- move dest=%p src=%p size=%d\n",
276 lpDest, lpTemp, nSize);
277 memmove (lpDest, lpTemp, nSize);
278 }
279
280 /* ok, we can put the new Item in */
281 hdsa->nItemCount++;
282 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
283 TRACE("-- move dest=%p src=%p size=%d\n",
284 lpDest, pSrc, hdsa->nItemSize);
285 memmove (lpDest, pSrc, hdsa->nItemSize);
286
287 return nIndex;
288 }
289
290
291 /**************************************************************************
292 * DSA_DeleteItem [COMCTL32.326]
293 *
294 * Deletes the specified item from the array.
295 *
296 * PARAMS
297 * hdsa [I] pointer to the array control structure
298 * nIndex [I] index for the element to delete
299 *
300 * RETURNS
301 * Success: number of the deleted element
302 * Failure: -1
303 */
304 INT WINAPI DSA_DeleteItem (HDSA hdsa, INT nIndex)
305 {
306 LPVOID lpDest,lpSrc;
307 INT nSize;
308
309 TRACE("(%p %d)\n", hdsa, nIndex);
310
311 if (!hdsa)
312 return -1;
313 if (nIndex < 0 || nIndex >= hdsa->nItemCount)
314 return -1;
315
316 /* do we need to move ? */
317 if (nIndex < hdsa->nItemCount - 1) {
318 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);
319 lpSrc = (char *) lpDest + hdsa->nItemSize;
320 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);
321 TRACE("-- move dest=%p src=%p size=%d\n",
322 lpDest, lpSrc, nSize);
323 memmove (lpDest, lpSrc, nSize);
324 }
325
326 hdsa->nItemCount--;
327
328 /* free memory ? */
329 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {
330 nSize = hdsa->nItemSize * hdsa->nItemCount;
331
332 lpDest = ReAlloc (hdsa->pData, nSize);
333 if (!lpDest)
334 return -1;
335
336 hdsa->nMaxCount = hdsa->nItemCount;
337 hdsa->pData = lpDest;
338 }
339
340 return nIndex;
341 }
342
343
344 /**************************************************************************
345 * DSA_DeleteAllItems [COMCTL32.327]
346 *
347 * Removes all items and reinitializes the array.
348 *
349 * PARAMS
350 * hdsa [I] pointer to the array control structure
351 *
352 * RETURNS
353 * Success: TRUE
354 * Failure: FALSE
355 */
356 BOOL WINAPI DSA_DeleteAllItems (HDSA hdsa)
357 {
358 TRACE("(%p)\n", hdsa);
359
360 if (!hdsa)
361 return FALSE;
362 if (hdsa->pData && (!Free (hdsa->pData)))
363 return FALSE;
364
365 hdsa->nItemCount = 0;
366 hdsa->pData = NULL;
367 hdsa->nMaxCount = 0;
368
369 return TRUE;
370 }
371
372
373 /**************************************************************************
374 * DSA_EnumCallback [COMCTL32.387]
375 *
376 * Enumerates all items in a dynamic storage array.
377 *
378 * PARAMS
379 * hdsa [I] handle to the dynamic storage array
380 * enumProc [I]
381 * lParam [I]
382 *
383 * RETURNS
384 * none
385 */
386 VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
387 LPVOID lParam)
388 {
389 INT i;
390
391 TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
392
393 if (!hdsa)
394 return;
395 if (hdsa->nItemCount <= 0)
396 return;
397
398 for (i = 0; i < hdsa->nItemCount; i++) {
399 LPVOID lpItem = DSA_GetItemPtr (hdsa, i);
400 if ((enumProc)(lpItem, lParam) == 0)
401 return;
402 }
403
404 return;
405 }
406
407
408 /**************************************************************************
409 * DSA_DestroyCallback [COMCTL32.388]
410 *
411 * Enumerates all items in a dynamic storage array and destroys it.
412 *
413 * PARAMS
414 * hdsa [I] handle to the dynamic storage array
415 * enumProc [I]
416 * lParam [I]
417 *
418 * RETURNS
419 * none
420 */
421 void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,
422 LPVOID lParam)
423 {
424 TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);
425
426 DSA_EnumCallback (hdsa, enumProc, lParam);
427 DSA_Destroy (hdsa);
428 }