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 <stdarg.h> 33 34 #include "windef.h" 35 #include "winbase.h" 36 #include "winuser.h" 37 #include "commctrl.h" 38 39 #include "comctl32.h" 40 #include "wine/debug.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(dsa); 43 44 struct _DSA 45 { 46 INT nItemCount; 47 LPVOID pData; 48 INT nMaxCount; 49 INT nItemSize; 50 INT nGrow; 51 }; 52 53 /************************************************************************** 54 * DSA_Create [COMCTL32.320] 55 * 56 * Creates a dynamic storage array 57 * 58 * PARAMS 59 * nSize [I] size of the array elements 60 * nGrow [I] number of elements by which the array grows when it is filled 61 * 62 * RETURNS 63 * Success: pointer to an array control structure. Use this like a handle. 64 * Failure: NULL 65 * 66 * NOTES 67 * The DSA_ functions can be used to create and manipulate arrays of 68 * fixed-size memory blocks. These arrays can store any kind of data 69 * (e.g. strings and icons). 70 */ 71 HDSA WINAPI DSA_Create (INT nSize, INT nGrow) 72 { 73 HDSA hdsa; 74 75 TRACE("(size=%d grow=%d)\n", nSize, nGrow); 76 77 hdsa = Alloc (sizeof(*hdsa)); 78 if (hdsa) 79 { 80 hdsa->nItemCount = 0; 81 hdsa->pData = NULL; 82 hdsa->nMaxCount = 0; 83 hdsa->nItemSize = nSize; 84 hdsa->nGrow = max(1, nGrow); 85 } 86 87 return hdsa; 88 } 89 90 91 /************************************************************************** 92 * DSA_Destroy [COMCTL32.321] 93 * 94 * Destroys a dynamic storage array 95 * 96 * PARAMS 97 * hdsa [I] pointer to the array control structure 98 * 99 * RETURNS 100 * Success: TRUE 101 * Failure: FALSE 102 */ 103 BOOL WINAPI DSA_Destroy (HDSA hdsa) 104 { 105 TRACE("(%p)\n", hdsa); 106 107 if (!hdsa) 108 return FALSE; 109 110 if (hdsa->pData && (!Free (hdsa->pData))) 111 return FALSE; 112 113 return Free (hdsa); 114 } 115 116 117 /************************************************************************** 118 * DSA_GetItem [COMCTL32.322] 119 * 120 * Copies the specified item into a caller-supplied buffer. 121 * 122 * PARAMS 123 * hdsa [I] pointer to the array control structure 124 * nIndex [I] number of the Item to get 125 * pDest [O] destination buffer. Has to be >= dwElementSize. 126 * 127 * RETURNS 128 * Success: TRUE 129 * Failure: FALSE 130 */ 131 BOOL WINAPI DSA_GetItem (HDSA hdsa, INT nIndex, LPVOID pDest) 132 { 133 LPVOID pSrc; 134 135 TRACE("(%p %d %p)\n", hdsa, nIndex, pDest); 136 137 if (!hdsa) 138 return FALSE; 139 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) 140 return FALSE; 141 142 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); 143 memmove (pDest, pSrc, hdsa->nItemSize); 144 145 return TRUE; 146 } 147 148 149 /************************************************************************** 150 * DSA_GetItemPtr [COMCTL32.323] 151 * 152 * Retrieves a pointer to the specified item. 153 * 154 * PARAMS 155 * hdsa [I] pointer to the array control structure 156 * nIndex [I] index of the desired item 157 * 158 * RETURNS 159 * Success: pointer to an item 160 * Failure: NULL 161 */ 162 LPVOID WINAPI DSA_GetItemPtr (HDSA hdsa, INT nIndex) 163 { 164 LPVOID pSrc; 165 166 TRACE("(%p %d)\n", hdsa, nIndex); 167 168 if (!hdsa) 169 return NULL; 170 if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) 171 return NULL; 172 173 pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); 174 175 TRACE("-- ret=%p\n", pSrc); 176 177 return pSrc; 178 } 179 180 181 /************************************************************************** 182 * DSA_SetItem [COMCTL32.325] 183 * 184 * Sets the contents of an item in the array. 185 * 186 * PARAMS 187 * hdsa [I] pointer to the array control structure 188 * nIndex [I] index for the item 189 * pSrc [I] pointer to the new item data 190 * 191 * RETURNS 192 * Success: TRUE 193 * Failure: FALSE 194 */ 195 BOOL WINAPI DSA_SetItem (HDSA hdsa, INT nIndex, LPVOID pSrc) 196 { 197 INT nSize, nNewItems; 198 LPVOID pDest, lpTemp; 199 200 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); 201 202 if ((!hdsa) || nIndex < 0) 203 return FALSE; 204 205 if (hdsa->nItemCount <= nIndex) { 206 /* within the old array */ 207 if (hdsa->nMaxCount > nIndex) { 208 /* within the allocated space, set a new boundary */ 209 hdsa->nItemCount = nIndex + 1; 210 } 211 else { 212 /* resize the block of memory */ 213 nNewItems = 214 hdsa->nGrow * ((((nIndex + 1) - 1) / hdsa->nGrow) + 1); 215 nSize = hdsa->nItemSize * nNewItems; 216 217 lpTemp = ReAlloc (hdsa->pData, nSize); 218 if (!lpTemp) 219 return FALSE; 220 221 hdsa->nMaxCount = nNewItems; 222 hdsa->nItemCount = nIndex + 1; 223 hdsa->pData = lpTemp; 224 } 225 } 226 227 /* put the new entry in */ 228 pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); 229 TRACE("-- move dest=%p src=%p size=%d\n", 230 pDest, pSrc, hdsa->nItemSize); 231 memmove (pDest, pSrc, hdsa->nItemSize); 232 233 return TRUE; 234 } 235 236 237 /************************************************************************** 238 * DSA_InsertItem [COMCTL32.324] 239 * 240 * Inserts an item into the array at the specified index. 241 * 242 * PARAMS 243 * hdsa [I] pointer to the array control structure 244 * nIndex [I] index for the new item 245 * pSrc [I] pointer to the element 246 * 247 * RETURNS 248 * Success: position of the new item 249 * Failure: -1 250 */ 251 INT WINAPI DSA_InsertItem (HDSA hdsa, INT nIndex, LPVOID pSrc) 252 { 253 INT nNewItems, nSize; 254 LPVOID lpTemp, lpDest; 255 256 TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); 257 258 if ((!hdsa) || nIndex < 0) 259 return -1; 260 261 /* when nIndex >= nItemCount then append */ 262 if (nIndex >= hdsa->nItemCount) 263 nIndex = hdsa->nItemCount; 264 265 /* do we need to resize ? */ 266 if (hdsa->nItemCount >= hdsa->nMaxCount) { 267 nNewItems = hdsa->nMaxCount + hdsa->nGrow; 268 nSize = hdsa->nItemSize * nNewItems; 269 270 if (nSize / hdsa->nItemSize != nNewItems) 271 return -1; 272 273 lpTemp = ReAlloc (hdsa->pData, nSize); 274 if (!lpTemp) 275 return -1; 276 277 hdsa->nMaxCount = nNewItems; 278 hdsa->pData = lpTemp; 279 } 280 281 /* do we need to move elements ? */ 282 if (nIndex < hdsa->nItemCount) { 283 lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); 284 lpDest = (char *) lpTemp + hdsa->nItemSize; 285 nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize; 286 TRACE("-- move dest=%p src=%p size=%d\n", 287 lpDest, lpTemp, nSize); 288 memmove (lpDest, lpTemp, nSize); 289 } 290 291 /* ok, we can put the new Item in */ 292 hdsa->nItemCount++; 293 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); 294 TRACE("-- move dest=%p src=%p size=%d\n", 295 lpDest, pSrc, hdsa->nItemSize); 296 memmove (lpDest, pSrc, hdsa->nItemSize); 297 298 return nIndex; 299 } 300 301 302 /************************************************************************** 303 * DSA_DeleteItem [COMCTL32.326] 304 * 305 * Deletes the specified item from the array. 306 * 307 * PARAMS 308 * hdsa [I] pointer to the array control structure 309 * nIndex [I] index for the element to delete 310 * 311 * RETURNS 312 * Success: number of the deleted element 313 * Failure: -1 314 */ 315 INT WINAPI DSA_DeleteItem (HDSA hdsa, INT nIndex) 316 { 317 LPVOID lpDest,lpSrc; 318 INT nSize; 319 320 TRACE("(%p %d)\n", hdsa, nIndex); 321 322 if (!hdsa) 323 return -1; 324 if (nIndex < 0 || nIndex >= hdsa->nItemCount) 325 return -1; 326 327 /* do we need to move ? */ 328 if (nIndex < hdsa->nItemCount - 1) { 329 lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); 330 lpSrc = (char *) lpDest + hdsa->nItemSize; 331 nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1); 332 TRACE("-- move dest=%p src=%p size=%d\n", 333 lpDest, lpSrc, nSize); 334 memmove (lpDest, lpSrc, nSize); 335 } 336 337 hdsa->nItemCount--; 338 339 /* free memory ? */ 340 if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) { 341 nSize = hdsa->nItemSize * hdsa->nItemCount; 342 343 lpDest = ReAlloc (hdsa->pData, nSize); 344 if (!lpDest) 345 return -1; 346 347 hdsa->nMaxCount = hdsa->nItemCount; 348 hdsa->pData = lpDest; 349 } 350 351 return nIndex; 352 } 353 354 355 /************************************************************************** 356 * DSA_DeleteAllItems [COMCTL32.327] 357 * 358 * Removes all items and reinitializes the array. 359 * 360 * PARAMS 361 * hdsa [I] pointer to the array control structure 362 * 363 * RETURNS 364 * Success: TRUE 365 * Failure: FALSE 366 */ 367 BOOL WINAPI DSA_DeleteAllItems (HDSA hdsa) 368 { 369 TRACE("(%p)\n", hdsa); 370 371 if (!hdsa) 372 return FALSE; 373 if (hdsa->pData && (!Free (hdsa->pData))) 374 return FALSE; 375 376 hdsa->nItemCount = 0; 377 hdsa->pData = NULL; 378 hdsa->nMaxCount = 0; 379 380 return TRUE; 381 } 382 383 384 /************************************************************************** 385 * DSA_EnumCallback [COMCTL32.387] 386 * 387 * Enumerates all items in a dynamic storage array. 388 * 389 * PARAMS 390 * hdsa [I] handle to the dynamic storage array 391 * enumProc [I] 392 * lParam [I] 393 * 394 * RETURNS 395 * none 396 */ 397 VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, 398 LPVOID lParam) 399 { 400 INT i; 401 402 TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); 403 404 if (!hdsa) 405 return; 406 if (hdsa->nItemCount <= 0) 407 return; 408 409 for (i = 0; i < hdsa->nItemCount; i++) { 410 LPVOID lpItem = DSA_GetItemPtr (hdsa, i); 411 if ((enumProc)(lpItem, lParam) == 0) 412 return; 413 } 414 415 return; 416 } 417 418 419 /************************************************************************** 420 * DSA_DestroyCallback [COMCTL32.388] 421 * 422 * Enumerates all items in a dynamic storage array and destroys it. 423 * 424 * PARAMS 425 * hdsa [I] handle to the dynamic storage array 426 * enumProc [I] 427 * lParam [I] 428 * 429 * RETURNS 430 * none 431 */ 432 void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, 433 LPVOID lParam) 434 { 435 TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); 436 437 DSA_EnumCallback (hdsa, enumProc, lParam); 438 DSA_Destroy (hdsa); 439 } 440 441 /************************************************************************** 442 * DSA_Clone [COMCTL32.@] 443 * 444 * Creates a copy of a dsa 445 * 446 * PARAMS 447 * hdsa [I] handle to the dynamic storage array 448 * 449 * RETURNS 450 * Cloned dsa 451 */ 452 HDSA WINAPI DSA_Clone(HDSA hdsa) 453 { 454 HDSA dest; 455 INT i; 456 457 TRACE("(%p)\n", hdsa); 458 459 if (!hdsa) 460 return NULL; 461 462 dest = DSA_Create (hdsa->nItemSize, hdsa->nGrow); 463 if (!dest) 464 return NULL; 465 466 for (i = 0; i < hdsa->nItemCount; i++) { 467 void *ptr = DSA_GetItemPtr (hdsa, i); 468 if (DSA_InsertItem (dest, DA_LAST, ptr) == -1) { 469 DSA_Destroy (dest); 470 return NULL; 471 } 472 } 473 474 return dest; 475 } 476 477 /************************************************************************** 478 * DSA_GetSize [COMCTL32.@] 479 * 480 * Returns allocated memory size for this array 481 * 482 * PARAMS 483 * hdsa [I] handle to the dynamic storage array 484 * 485 * RETURNS 486 * Size 487 */ 488 ULONGLONG WINAPI DSA_GetSize(HDSA hdsa) 489 { 490 TRACE("(%p)\n", hdsa); 491 492 if (!hdsa) return 0; 493 494 return sizeof(*hdsa) + (ULONGLONG)hdsa->nMaxCount*hdsa->nItemSize; 495 } 496