/*1* Dynamic structure array (DSA) implementation2*3* Copyright 1998 Eric Kohl4* 1998 Juergen Schmied <[email protected]>5* 2000 Eric Kohl for CodeWeavers6*7* This library is free software; you can redistribute it and/or8* modify it under the terms of the GNU Lesser General Public9* License as published by the Free Software Foundation; either10* version 2.1 of the License, or (at your option) any later version.11*12* This library is distributed in the hope that it will be useful,13* but WITHOUT ANY WARRANTY; without even the implied warranty of14* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU15* Lesser General Public License for more details.16*17* You should have received a copy of the GNU Lesser General Public18* License along with this library; if not, write to the Free Software19* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA20*21* NOTES22* These functions were involuntarily documented by Microsoft in 2002 as23* the outcome of an anti-trust suit brought by various U.S. governments.24* As a result the specifications on MSDN are inaccurate, incomplete25* and misleading. A much more complete (unofficial) documentation is26* available at:27*28* http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl3229*/3031#include <stdarg.h>3233#include "windef.h"34#include "winbase.h"35#include "winuser.h"36#include "commctrl.h"3738#include "comctl32.h"39#include "wine/debug.h"4041WINE_DEFAULT_DEBUG_CHANNEL(dsa);4243struct _DSA44{45INT nItemCount;46LPVOID pData;47INT nMaxCount;48INT nItemSize;49INT nGrow;50};5152/**************************************************************************53* DSA_Create [COMCTL32.320]54*55* Creates a dynamic storage array56*57* PARAMS58* nSize [I] size of the array elements59* nGrow [I] number of elements by which the array grows when it is filled60*61* RETURNS62* Success: pointer to an array control structure. Use this like a handle.63* Failure: NULL64*65* NOTES66* The DSA_ functions can be used to create and manipulate arrays of67* fixed-size memory blocks. These arrays can store any kind of data68* (e.g. strings and icons).69*/70HDSA WINAPI DSA_Create (INT nSize, INT nGrow)71{72HDSA hdsa;7374TRACE("(size=%d grow=%d)\n", nSize, nGrow);7576hdsa = Alloc (sizeof(*hdsa));77if (hdsa)78{79hdsa->nItemCount = 0;80hdsa->pData = NULL;81hdsa->nMaxCount = 0;82hdsa->nItemSize = nSize;83hdsa->nGrow = max(1, nGrow);84}8586return hdsa;87}888990/**************************************************************************91* DSA_Destroy [COMCTL32.321]92*93* Destroys a dynamic storage array94*95* PARAMS96* hdsa [I] pointer to the array control structure97*98* RETURNS99* Success: TRUE100* Failure: FALSE101*/102BOOL WINAPI DSA_Destroy (HDSA hdsa)103{104TRACE("(%p)\n", hdsa);105106if (!hdsa)107return FALSE;108109if (hdsa->pData && (!Free (hdsa->pData)))110return FALSE;111112return Free (hdsa);113}114115116/**************************************************************************117* DSA_GetItem [COMCTL32.322]118*119* Copies the specified item into a caller-supplied buffer.120*121* PARAMS122* hdsa [I] pointer to the array control structure123* nIndex [I] number of the Item to get124* pDest [O] destination buffer. Has to be >= dwElementSize.125*126* RETURNS127* Success: TRUE128* Failure: FALSE129*/130BOOL WINAPI DSA_GetItem (HDSA hdsa, INT nIndex, LPVOID pDest)131{132LPVOID pSrc;133134TRACE("(%p %d %p)\n", hdsa, nIndex, pDest);135136if (!hdsa)137return FALSE;138if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))139return FALSE;140141pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);142memmove (pDest, pSrc, hdsa->nItemSize);143144return TRUE;145}146147148/**************************************************************************149* DSA_GetItemPtr [COMCTL32.323]150*151* Retrieves a pointer to the specified item.152*153* PARAMS154* hdsa [I] pointer to the array control structure155* nIndex [I] index of the desired item156*157* RETURNS158* Success: pointer to an item159* Failure: NULL160*/161LPVOID WINAPI DSA_GetItemPtr (HDSA hdsa, INT nIndex)162{163LPVOID pSrc;164165TRACE("(%p %d)\n", hdsa, nIndex);166167if (!hdsa)168return NULL;169if ((nIndex < 0) || (nIndex >= hdsa->nItemCount))170return NULL;171172pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);173174TRACE("-- ret=%p\n", pSrc);175176return pSrc;177}178179180/**************************************************************************181* DSA_SetItem [COMCTL32.325]182*183* Sets the contents of an item in the array.184*185* PARAMS186* hdsa [I] pointer to the array control structure187* nIndex [I] index for the item188* pSrc [I] pointer to the new item data189*190* RETURNS191* Success: TRUE192* Failure: FALSE193*/194BOOL WINAPI DSA_SetItem (HDSA hdsa, INT nIndex, LPVOID pSrc)195{196INT nSize, nNewItems;197LPVOID pDest, lpTemp;198199TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);200201if ((!hdsa) || nIndex < 0)202return FALSE;203204if (hdsa->nItemCount <= nIndex) {205/* within the old array */206if (hdsa->nMaxCount > nIndex) {207/* within the allocated space, set a new boundary */208hdsa->nItemCount = nIndex + 1;209}210else {211/* resize the block of memory */212nNewItems =213hdsa->nGrow * ((((nIndex + 1) - 1) / hdsa->nGrow) + 1);214nSize = hdsa->nItemSize * nNewItems;215216lpTemp = ReAlloc (hdsa->pData, nSize);217if (!lpTemp)218return FALSE;219220hdsa->nMaxCount = nNewItems;221hdsa->nItemCount = nIndex + 1;222hdsa->pData = lpTemp;223}224}225226/* put the new entry in */227pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);228TRACE("-- move dest=%p src=%p size=%d\n",229pDest, pSrc, hdsa->nItemSize);230memmove (pDest, pSrc, hdsa->nItemSize);231232return TRUE;233}234235236/**************************************************************************237* DSA_InsertItem [COMCTL32.324]238*239* Inserts an item into the array at the specified index.240*241* PARAMS242* hdsa [I] pointer to the array control structure243* nIndex [I] index for the new item244* pSrc [I] pointer to the element245*246* RETURNS247* Success: position of the new item248* Failure: -1249*/250INT WINAPI DSA_InsertItem (HDSA hdsa, INT nIndex, LPVOID pSrc)251{252INT nNewItems, nSize;253LPVOID lpTemp, lpDest;254255TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc);256257if ((!hdsa) || nIndex < 0)258return -1;259260/* when nIndex >= nItemCount then append */261if (nIndex >= hdsa->nItemCount)262nIndex = hdsa->nItemCount;263264/* do we need to resize ? */265if (hdsa->nItemCount >= hdsa->nMaxCount) {266nNewItems = hdsa->nMaxCount + hdsa->nGrow;267nSize = hdsa->nItemSize * nNewItems;268269if (nSize / hdsa->nItemSize != nNewItems)270return -1;271272lpTemp = ReAlloc (hdsa->pData, nSize);273if (!lpTemp)274return -1;275276hdsa->nMaxCount = nNewItems;277hdsa->pData = lpTemp;278}279280/* do we need to move elements ? */281if (nIndex < hdsa->nItemCount) {282lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);283lpDest = (char *) lpTemp + hdsa->nItemSize;284nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize;285TRACE("-- move dest=%p src=%p size=%d\n",286lpDest, lpTemp, nSize);287memmove (lpDest, lpTemp, nSize);288}289290/* ok, we can put the new Item in */291hdsa->nItemCount++;292lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);293TRACE("-- move dest=%p src=%p size=%d\n",294lpDest, pSrc, hdsa->nItemSize);295memmove (lpDest, pSrc, hdsa->nItemSize);296297return nIndex;298}299300301/**************************************************************************302* DSA_DeleteItem [COMCTL32.326]303*304* Deletes the specified item from the array.305*306* PARAMS307* hdsa [I] pointer to the array control structure308* nIndex [I] index for the element to delete309*310* RETURNS311* Success: number of the deleted element312* Failure: -1313*/314INT WINAPI DSA_DeleteItem (HDSA hdsa, INT nIndex)315{316LPVOID lpDest,lpSrc;317INT nSize;318319TRACE("(%p %d)\n", hdsa, nIndex);320321if (!hdsa)322return -1;323if (nIndex < 0 || nIndex >= hdsa->nItemCount)324return -1;325326/* do we need to move ? */327if (nIndex < hdsa->nItemCount - 1) {328lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex);329lpSrc = (char *) lpDest + hdsa->nItemSize;330nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1);331TRACE("-- move dest=%p src=%p size=%d\n",332lpDest, lpSrc, nSize);333memmove (lpDest, lpSrc, nSize);334}335336hdsa->nItemCount--;337338/* free memory ? */339if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) {340nSize = hdsa->nItemSize * hdsa->nItemCount;341342lpDest = ReAlloc (hdsa->pData, nSize);343if (!lpDest)344return -1;345346hdsa->nMaxCount = hdsa->nItemCount;347hdsa->pData = lpDest;348}349350return nIndex;351}352353354/**************************************************************************355* DSA_DeleteAllItems [COMCTL32.327]356*357* Removes all items and reinitializes the array.358*359* PARAMS360* hdsa [I] pointer to the array control structure361*362* RETURNS363* Success: TRUE364* Failure: FALSE365*/366BOOL WINAPI DSA_DeleteAllItems (HDSA hdsa)367{368TRACE("(%p)\n", hdsa);369370if (!hdsa)371return FALSE;372if (hdsa->pData && (!Free (hdsa->pData)))373return FALSE;374375hdsa->nItemCount = 0;376hdsa->pData = NULL;377hdsa->nMaxCount = 0;378379return TRUE;380}381382383/**************************************************************************384* DSA_EnumCallback [COMCTL32.387]385*386* Enumerates all items in a dynamic storage array.387*388* PARAMS389* hdsa [I] handle to the dynamic storage array390* enumProc [I]391* lParam [I]392*393* RETURNS394* none395*/396VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,397LPVOID lParam)398{399INT i;400401TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);402403if (!hdsa)404return;405if (hdsa->nItemCount <= 0)406return;407408for (i = 0; i < hdsa->nItemCount; i++) {409LPVOID lpItem = DSA_GetItemPtr (hdsa, i);410if ((enumProc)(lpItem, lParam) == 0)411return;412}413414return;415}416417418/**************************************************************************419* DSA_DestroyCallback [COMCTL32.388]420*421* Enumerates all items in a dynamic storage array and destroys it.422*423* PARAMS424* hdsa [I] handle to the dynamic storage array425* enumProc [I]426* lParam [I]427*428* RETURNS429* none430*/431void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc,432LPVOID lParam)433{434TRACE("(%p %p %p)\n", hdsa, enumProc, lParam);435436DSA_EnumCallback (hdsa, enumProc, lParam);437DSA_Destroy (hdsa);438}439440/**************************************************************************441* DSA_Clone [COMCTL32.@]442*443* Creates a copy of a dsa444*445* PARAMS446* hdsa [I] handle to the dynamic storage array447*448* RETURNS449* Cloned dsa450*/451HDSA WINAPI DSA_Clone(HDSA hdsa)452{453HDSA dest;454INT i;455456TRACE("(%p)\n", hdsa);457458if (!hdsa)459return NULL;460461dest = DSA_Create (hdsa->nItemSize, hdsa->nGrow);462if (!dest)463return NULL;464465for (i = 0; i < hdsa->nItemCount; i++) {466void *ptr = DSA_GetItemPtr (hdsa, i);467if (DSA_InsertItem (dest, DA_LAST, ptr) == -1) {468DSA_Destroy (dest);469return NULL;470}471}472473return dest;474}475476/**************************************************************************477* DSA_GetSize [COMCTL32.@]478*479* Returns allocated memory size for this array480*481* PARAMS482* hdsa [I] handle to the dynamic storage array483*484* RETURNS485* Size486*/487ULONGLONG WINAPI DSA_GetSize(HDSA hdsa)488{489TRACE("(%p)\n", hdsa);490491if (!hdsa) return 0;492493return sizeof(*hdsa) + (ULONGLONG)hdsa->nMaxCount*hdsa->nItemSize;494}495496497