437 lines
11 KiB
C
437 lines
11 KiB
C
/*
|
|
* 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., 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 <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 * ((((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);
|
|
}
|