|  | /* | 
|  | * Dynamic structure array (DSA) implementation | 
|  | * | 
|  | * Copyright 1998 Eric Kohl | 
|  | *           1998 Juergen Schmied <j.schmied@metronet.de> | 
|  | *           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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 <stdarg.h> | 
|  |  | 
|  | #include "windef.h" | 
|  | #include "winbase.h" | 
|  | #include "winuser.h" | 
|  | #include "commctrl.h" | 
|  |  | 
|  | #include "comctl32.h" | 
|  | #include "wine/debug.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 (const 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 (const 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 (const 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 (const 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 * ((INT)(((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 (const 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; | 
|  |  | 
|  | 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 (const 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 (const 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); | 
|  | } |