/* * Dynamic structure array (DSA) implementation * * Copyright 1998 Eric Kohl * 1998 Juergen Schmied * 2000 Eric Kohl for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * NOTES * These functions were involuntarily documented by Microsoft in 2002 as * the outcome of an anti-trust suit brought by various U.S. governments. * As a result the specifications on MSDN are inaccurate, incomplete * and misleading. A much more complete (unofficial) documentation is * available at: * * http://members.ozemail.com.au/~geoffch/samples/win32/shell/comctl32 */ #include "comctl32.h" WINE_DEFAULT_DEBUG_CHANNEL(dsa); struct _DSA { INT nItemCount; LPVOID pData; INT nMaxCount; INT nItemSize; INT nGrow; }; /************************************************************************** * DSA_Create [COMCTL32.320] * * Creates a dynamic storage array * * PARAMS * nSize [I] size of the array elements * nGrow [I] number of elements by which the array grows when it is filled * * RETURNS * Success: pointer to an array control structure. Use this like a handle. * Failure: NULL * * NOTES * The DSA_ functions can be used to create and manipulate arrays of * fixed-size memory blocks. These arrays can store any kind of data * (e.g. strings and icons). */ HDSA WINAPI DSA_Create (INT nSize, INT nGrow) { HDSA hdsa; TRACE("(size=%d grow=%d)\n", nSize, nGrow); hdsa = Alloc (sizeof(*hdsa)); if (hdsa) { hdsa->nItemCount = 0; hdsa->pData = NULL; hdsa->nMaxCount = 0; hdsa->nItemSize = nSize; hdsa->nGrow = max(1, nGrow); } return hdsa; } /************************************************************************** * DSA_Destroy [COMCTL32.321] * * Destroys a dynamic storage array * * PARAMS * hdsa [I] pointer to the array control structure * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI DSA_Destroy (HDSA hdsa) { TRACE("(%p)\n", hdsa); if (!hdsa) return FALSE; if (hdsa->pData && (!Free (hdsa->pData))) return FALSE; return Free (hdsa); } /************************************************************************** * DSA_GetItem [COMCTL32.322] * * Copies the specified item into a caller-supplied buffer. * * PARAMS * hdsa [I] pointer to the array control structure * nIndex [I] number of the Item to get * pDest [O] destination buffer. Has to be >= dwElementSize. * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI DSA_GetItem (HDSA hdsa, INT nIndex, LPVOID pDest) { LPVOID pSrc; TRACE("(%p %d %p)\n", hdsa, nIndex, pDest); if (!hdsa) return FALSE; if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) return FALSE; pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); memmove (pDest, pSrc, hdsa->nItemSize); return TRUE; } /************************************************************************** * DSA_GetItemPtr [COMCTL32.323] * * Retrieves a pointer to the specified item. * * PARAMS * hdsa [I] pointer to the array control structure * nIndex [I] index of the desired item * * RETURNS * Success: pointer to an item * Failure: NULL */ LPVOID WINAPI DSA_GetItemPtr (HDSA hdsa, INT nIndex) { LPVOID pSrc; TRACE("(%p %d)\n", hdsa, nIndex); if (!hdsa) return NULL; if ((nIndex < 0) || (nIndex >= hdsa->nItemCount)) return NULL; pSrc = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); TRACE("-- ret=%p\n", pSrc); return pSrc; } /************************************************************************** * DSA_SetItem [COMCTL32.325] * * Sets the contents of an item in the array. * * PARAMS * hdsa [I] pointer to the array control structure * nIndex [I] index for the item * pSrc [I] pointer to the new item data * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI DSA_SetItem (HDSA hdsa, INT nIndex, LPVOID pSrc) { INT nSize, nNewItems; LPVOID pDest, lpTemp; TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); if ((!hdsa) || nIndex < 0) return FALSE; if (hdsa->nItemCount <= nIndex) { /* within the old array */ if (hdsa->nMaxCount > nIndex) { /* within the allocated space, set a new boundary */ hdsa->nItemCount = nIndex + 1; } else { /* resize the block of memory */ nNewItems = hdsa->nGrow * ((((nIndex + 1) - 1) / hdsa->nGrow) + 1); nSize = hdsa->nItemSize * nNewItems; lpTemp = ReAlloc (hdsa->pData, nSize); if (!lpTemp) return FALSE; hdsa->nMaxCount = nNewItems; hdsa->nItemCount = nIndex + 1; hdsa->pData = lpTemp; } } /* put the new entry in */ pDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); TRACE("-- move dest=%p src=%p size=%d\n", pDest, pSrc, hdsa->nItemSize); memmove (pDest, pSrc, hdsa->nItemSize); return TRUE; } /************************************************************************** * DSA_InsertItem [COMCTL32.324] * * Inserts an item into the array at the specified index. * * PARAMS * hdsa [I] pointer to the array control structure * nIndex [I] index for the new item * pSrc [I] pointer to the element * * RETURNS * Success: position of the new item * Failure: -1 */ INT WINAPI DSA_InsertItem (HDSA hdsa, INT nIndex, LPVOID pSrc) { INT nNewItems, nSize; LPVOID lpTemp, lpDest; TRACE("(%p %d %p)\n", hdsa, nIndex, pSrc); if ((!hdsa) || nIndex < 0) return -1; /* when nIndex >= nItemCount then append */ if (nIndex >= hdsa->nItemCount) nIndex = hdsa->nItemCount; /* do we need to resize ? */ if (hdsa->nItemCount >= hdsa->nMaxCount) { nNewItems = hdsa->nMaxCount + hdsa->nGrow; nSize = hdsa->nItemSize * nNewItems; if (nSize / hdsa->nItemSize != nNewItems) return -1; lpTemp = ReAlloc (hdsa->pData, nSize); if (!lpTemp) return -1; hdsa->nMaxCount = nNewItems; hdsa->pData = lpTemp; } /* do we need to move elements ? */ if (nIndex < hdsa->nItemCount) { lpTemp = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); lpDest = (char *) lpTemp + hdsa->nItemSize; nSize = (hdsa->nItemCount - nIndex) * hdsa->nItemSize; TRACE("-- move dest=%p src=%p size=%d\n", lpDest, lpTemp, nSize); memmove (lpDest, lpTemp, nSize); } /* ok, we can put the new Item in */ hdsa->nItemCount++; lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); TRACE("-- move dest=%p src=%p size=%d\n", lpDest, pSrc, hdsa->nItemSize); memmove (lpDest, pSrc, hdsa->nItemSize); return nIndex; } /************************************************************************** * DSA_DeleteItem [COMCTL32.326] * * Deletes the specified item from the array. * * PARAMS * hdsa [I] pointer to the array control structure * nIndex [I] index for the element to delete * * RETURNS * Success: number of the deleted element * Failure: -1 */ INT WINAPI DSA_DeleteItem (HDSA hdsa, INT nIndex) { LPVOID lpDest,lpSrc; INT nSize; TRACE("(%p %d)\n", hdsa, nIndex); if (!hdsa) return -1; if (nIndex < 0 || nIndex >= hdsa->nItemCount) return -1; /* do we need to move ? */ if (nIndex < hdsa->nItemCount - 1) { lpDest = (char *) hdsa->pData + (hdsa->nItemSize * nIndex); lpSrc = (char *) lpDest + hdsa->nItemSize; nSize = hdsa->nItemSize * (hdsa->nItemCount - nIndex - 1); TRACE("-- move dest=%p src=%p size=%d\n", lpDest, lpSrc, nSize); memmove (lpDest, lpSrc, nSize); } hdsa->nItemCount--; /* free memory ? */ if ((hdsa->nMaxCount - hdsa->nItemCount) >= hdsa->nGrow) { nSize = hdsa->nItemSize * hdsa->nItemCount; lpDest = ReAlloc (hdsa->pData, nSize); if (!lpDest) return -1; hdsa->nMaxCount = hdsa->nItemCount; hdsa->pData = lpDest; } return nIndex; } /************************************************************************** * DSA_DeleteAllItems [COMCTL32.327] * * Removes all items and reinitializes the array. * * PARAMS * hdsa [I] pointer to the array control structure * * RETURNS * Success: TRUE * Failure: FALSE */ BOOL WINAPI DSA_DeleteAllItems (HDSA hdsa) { TRACE("(%p)\n", hdsa); if (!hdsa) return FALSE; if (hdsa->pData && (!Free (hdsa->pData))) return FALSE; hdsa->nItemCount = 0; hdsa->pData = NULL; hdsa->nMaxCount = 0; return TRUE; } /************************************************************************** * DSA_EnumCallback [COMCTL32.387] * * Enumerates all items in a dynamic storage array. * * PARAMS * hdsa [I] handle to the dynamic storage array * enumProc [I] * lParam [I] * * RETURNS * none */ VOID WINAPI DSA_EnumCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, LPVOID lParam) { INT i; TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); if (!hdsa) return; if (hdsa->nItemCount <= 0) return; for (i = 0; i < hdsa->nItemCount; i++) { LPVOID lpItem = DSA_GetItemPtr (hdsa, i); if ((enumProc)(lpItem, lParam) == 0) return; } return; } /************************************************************************** * DSA_DestroyCallback [COMCTL32.388] * * Enumerates all items in a dynamic storage array and destroys it. * * PARAMS * hdsa [I] handle to the dynamic storage array * enumProc [I] * lParam [I] * * RETURNS * none */ void WINAPI DSA_DestroyCallback (HDSA hdsa, PFNDSAENUMCALLBACK enumProc, LPVOID lParam) { TRACE("(%p %p %p)\n", hdsa, enumProc, lParam); DSA_EnumCallback (hdsa, enumProc, lParam); DSA_Destroy (hdsa); } /************************************************************************** * DSA_Clone [COMCTL32.@] * * Creates a copy of a dsa * * PARAMS * hdsa [I] handle to the dynamic storage array * * RETURNS * Cloned dsa */ HDSA WINAPI DSA_Clone(HDSA hdsa) { HDSA dest; INT i; TRACE("(%p)\n", hdsa); if (!hdsa) return NULL; dest = DSA_Create (hdsa->nItemSize, hdsa->nGrow); if (!dest) return NULL; for (i = 0; i < hdsa->nItemCount; i++) { void *ptr = DSA_GetItemPtr (hdsa, i); if (DSA_InsertItem (dest, DA_LAST, ptr) == -1) { DSA_Destroy (dest); return NULL; } } return dest; } /************************************************************************** * DSA_GetSize [COMCTL32.@] * * Returns allocated memory size for this array * * PARAMS * hdsa [I] handle to the dynamic storage array * * RETURNS * Size */ ULONGLONG WINAPI DSA_GetSize(HDSA hdsa) { TRACE("(%p)\n", hdsa); if (!hdsa) return 0; return sizeof(*hdsa) + (ULONGLONG)hdsa->nMaxCount*hdsa->nItemSize; }