Implement/document @17,18,19,20,21,22 (Compact list API).

This commit is contained in:
Jon Griffiths 2002-07-09 02:01:56 +00:00 committed by Alexandre Julliard
parent 5da88a2cb9
commit 2d990806ec
6 changed files with 897 additions and 78 deletions

View file

@ -12,6 +12,7 @@ LDDLLFLAGS = @LDDLLFLAGS@
SYMBOLFILE = $(MODULE).tmp.o
C_SRCS = \
clist.c \
ordinal.c \
path.c \
reg.c \
@ -24,6 +25,7 @@ C_SRCS = \
EXTRASUBDIRS = tests
CTESTS = \
tests/clist.c \
tests/shreg.c
@MAKE_DLL_RULES@

434
dlls/shlwapi/clist.c Normal file
View file

@ -0,0 +1,434 @@
/*
* SHLWAPI Compact List functions
*
* Copyright 2002 Jon Griffiths
*
* 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
*/
#include <string.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "wine/obj_base.h"
#include "wine/obj_storage.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(shell);
/* Compact list element (ordinals 17-22) */
typedef struct tagSHLWAPI_CLIST
{
ULONG ulSize; /* Size of this list element and its data */
ULONG ulId; /* If -1, The real element follows */
/* Item data (or a contained SHLWAPI_CLIST) follows... */
} SHLWAPI_CLIST, *LPSHLWAPI_CLIST;
typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST;
/* ulId for contained SHLWAPI_CLIST items */
static const ULONG CLIST_ID_CONTAINER = -1u;
HRESULT WINAPI SHLWAPI_20(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST);
/*************************************************************************
* NextItem
*
* Internal helper: move a clist pointer to the next item.
*/
inline static LPSHLWAPI_CLIST NextItem(LPCSHLWAPI_CLIST lpList)
{
const char* address = (char*)lpList;
address += lpList->ulSize;
return (LPSHLWAPI_CLIST)address;
}
/*************************************************************************
* @ [SHLWAPI.17]
*
* Write a compact list to a stream.
*
* PARAMS
* lpStream [I] Stream to write the list to
* lpList [I] List of items to write
*
* RETURNS
* Success: S_OK
* Failure: An HRESULT error code
*
* NOTES
* Ordinals 17,18,19,20,21 and 22 are related and together provide a compact
* list structure which may be stored and retrieved from a stream.
*
* The exposed API consists of:
* @17 Write a compact list to a stream
* @18 Read and create a list from a stream
* @19 Free a list
* @20 Insert a new item into a list
* @21 Remove an item from a list
* @22 Find an item in a list
*
* The compact list is stored packed into a memory array. Each element has a
* size and an associated ID. Elements must be less than 64k if the list is
* to be subsequently read from a stream.
*
* Elements are aligned on DWORD boundaries. If an elements data size is not
* a DWORD size multiple, the element is wrapped by inserting a surrounding
* element with an Id of -1, and size sufficient to pad to a DWORD boundary.
*
* These functions are slow for large objects and long lists.
*/
HRESULT WINAPI SHLWAPI_17(IStream* lpStream, LPSHLWAPI_CLIST lpList)
{
ULONG ulSize;
HRESULT hRet = E_FAIL;
TRACE("(%p,%p)\n", lpStream, lpList);
if(lpList)
{
while (lpList->ulSize)
{
LPSHLWAPI_CLIST lpItem = lpList;
if(lpList->ulId == CLIST_ID_CONTAINER)
lpItem++;
hRet = IStream_Write(lpStream,lpItem,lpItem->ulSize,&ulSize);
if (FAILED(hRet))
return hRet;
if(lpItem->ulSize != ulSize)
return STG_E_MEDIUMFULL;
lpList = NextItem(lpList);
}
}
if(SUCCEEDED(hRet))
{
ULONG ulDummy;
ulSize = 0;
/* Write a terminating list entry with zero size */
hRet = IStream_Write(lpStream, &ulSize,sizeof(ulSize),&ulDummy);
}
return hRet;
}
/*************************************************************************
* @ [SHLWAPI.18]
*
* Read and create a compact list from a stream
*
* PARAMS
* lpStream [I] Stream to read the list from
* lppList [0] Pointer to recieve the new List
*
* RETURNS
* Success: S_OK
* Failure: An HRESULT error code
*
* NOTES
* When read from a file, list objects are limited in size to 64k.
*/
HRESULT WINAPI SHLWAPI_18(IStream* lpStream, LPSHLWAPI_CLIST* lppList)
{
SHLWAPI_CLIST bBuff[128]; /* Temporary storage for new list item */
ULONG ulBuffSize = sizeof(bBuff);
LPSHLWAPI_CLIST pItem = bBuff;
ULONG ulRead, ulSize;
HRESULT hRet = S_OK;
TRACE("(%p,%p)\n", lpStream, lppList);
if(*lppList)
{
/* Free any existing list */
LocalFree((HLOCAL)*lppList);
*lppList = NULL;
}
do
{
/* Read the size of the next item */
hRet = IStream_Read(lpStream, &ulSize,sizeof(ulSize),&ulRead);
if(FAILED(hRet) || ulRead != sizeof(ulSize) || !ulSize)
break; /* Read failed or read zero size (the end of the list) */
if(ulSize > 0xFFFF)
{
LARGE_INTEGER liZero;
ULARGE_INTEGER ulPos;
liZero.QuadPart = 0;
/* Back the stream up; this object is too big for the list */
if(SUCCEEDED(IStream_Seek(lpStream, liZero, STREAM_SEEK_CUR, &ulPos)))
{
liZero.QuadPart = ulPos.QuadPart - sizeof(ULONG);
IStream_Seek(lpStream, liZero, STREAM_SEEK_SET, NULL);
}
break;
}
else if (ulSize >= sizeof(SHLWAPI_CLIST))
{
/* Add this new item to the list */
if(ulSize > ulBuffSize)
{
/* We need more buffer space, allocate it */
LPSHLWAPI_CLIST lpTemp;
if (pItem == bBuff)
lpTemp = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT, ulSize);
else
lpTemp = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)pItem, ulSize,
LMEM_ZEROINIT|LMEM_MOVEABLE);
if(!lpTemp)
{
hRet = E_OUTOFMEMORY;
break;
}
ulBuffSize = ulSize;
pItem = lpTemp;
}
pItem->ulSize = ulSize;
ulSize -= sizeof(pItem->ulSize); /* already read this member */
/* Read the item Id and data */
hRet = IStream_Read(lpStream, &pItem->ulId, ulSize, &ulRead);
if(FAILED(hRet) || ulRead != ulSize)
break;
SHLWAPI_20(lppList, pItem); /* Insert Item */
}
} while(1);
/* If we allocated space, free it */
if(pItem != bBuff)
LocalFree((HLOCAL)pItem);
return hRet;
}
/*************************************************************************
* @ [SHLWAPI.19]
*
* Free a compact list.
*
* PARAMS
* lpList [I] List to free
*
* RETURNS
* Nothing.
*/
VOID WINAPI SHLWAPI_19(LPSHLWAPI_CLIST lpList)
{
TRACE("(%p)\n", lpList);
if (lpList)
LocalFree((HLOCAL)lpList);
}
/*************************************************************************
* @ [SHLWAPI.20]
*
* Insert a new item into a compact list.
*
* PARAMS
* lppList [0] Pointer to the List
* lpNewItem [I] The new item to add to the list
*
* RETURNS
* Success: The size of the inserted item.
* Failure: An HRESULT error code.
*/
HRESULT WINAPI SHLWAPI_20(LPSHLWAPI_CLIST* lppList, LPCSHLWAPI_CLIST lpNewItem)
{
LPSHLWAPI_CLIST lpInsertAt = NULL;
ULONG ulSize;
TRACE("(%p,%p)\n", lppList, lpNewItem);
if(!lppList || !lpNewItem ||
lpNewItem->ulId == CLIST_ID_CONTAINER ||
lpNewItem->ulSize < sizeof(SHLWAPI_CLIST))
return E_INVALIDARG;
ulSize = lpNewItem->ulSize;
if(ulSize & 0x3)
{
/* Tune size to a ULONG boundary, add space for container element */
ulSize = ((ulSize + 0x3) & 0xFFFFFFFC) + sizeof(SHLWAPI_CLIST);
TRACE("Creating container item, new size = %ld\n", ulSize);
}
if(!*lppList)
{
/* An empty list. Allocate space for terminal ulSize also */
*lppList = (LPSHLWAPI_CLIST)LocalAlloc(LMEM_ZEROINIT,
ulSize + sizeof(ULONG));
lpInsertAt = *lppList;
}
else
{
/* Append to the end of the list */
ULONG ulTotalSize = 0;
LPSHLWAPI_CLIST lpIter = *lppList;
/* Iterate to the end of the list, calculating the total size */
while (lpIter->ulSize)
{
ulTotalSize += lpIter->ulSize;
lpIter = NextItem(lpIter);
}
/* Increase the size of the list */
lpIter = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList,
ulTotalSize + ulSize+sizeof(ULONG),
LMEM_ZEROINIT | LMEM_MOVEABLE);
if(lpIter)
{
*lppList = lpIter;
lpInsertAt = (LPSHLWAPI_CLIST)((char*)lpIter + ulTotalSize); /* At end */
}
}
if(lpInsertAt)
{
/* Copy in the new item */
LPSHLWAPI_CLIST lpDest = lpInsertAt;
if(ulSize != lpNewItem->ulSize)
{
lpInsertAt->ulSize = ulSize;
lpInsertAt->ulId = CLIST_ID_CONTAINER;
lpDest++;
}
memcpy(lpDest, lpNewItem, lpNewItem->ulSize);
/* Terminate the list */
lpInsertAt = NextItem(lpInsertAt);
lpInsertAt->ulSize = 0;
return lpNewItem->ulSize;
}
return S_OK;
}
/*************************************************************************
* @ [SHLWAPI.21]
*
* Remove an item from a compact list.
*
* PARAMS
* lppList [O] List to remove the item from
* ulId [I] Id of item to remove
*
* RETURNS
* Success: TRUE.
* Failure: FALSE, If any parameters are invalid, or the item was not found.
*/
BOOL WINAPI SHLWAPI_21(LPSHLWAPI_CLIST* lppList, ULONG ulId)
{
LPSHLWAPI_CLIST lpList = 0;
LPSHLWAPI_CLIST lpItem = NULL;
LPSHLWAPI_CLIST lpNext;
ULONG ulNewSize;
TRACE("(%p,%ld)\n", lppList, ulId);
if(lppList && (lpList = *lppList))
{
/* Search for item in list */
while (lpList->ulSize)
{
if(lpList->ulId == ulId ||
(lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId))
{
lpItem = lpList; /* Found */
break;
}
lpList = NextItem(lpList);
}
}
if(!lpItem)
return FALSE;
lpList = lpNext = NextItem(lpItem);
/* Locate the end of the list */
while (lpList->ulSize)
lpList = NextItem(lpList);
/* Resize the list */
ulNewSize = LocalSize((HLOCAL)*lppList) - lpItem->ulSize;
/* Copy following elements over lpItem */
memmove(lpItem, lpNext, (char *)lpList - (char *)lpNext + sizeof(ULONG));
if(ulNewSize <= sizeof(ULONG))
{
LocalFree((HLOCAL)*lppList);
*lppList = NULL; /* Removed the last element */
}
else
{
lpList = (LPSHLWAPI_CLIST)LocalReAlloc((HLOCAL)*lppList, ulNewSize,
LMEM_ZEROINIT|LMEM_MOVEABLE);
if(lpList)
*lppList = lpList;
}
return TRUE;
}
/*************************************************************************
* @ [SHLWAPI.22]
*
* Find an item in a compact list.
*
* PARAMS
* lpList [I] List to search
* ulId [I] ID of item to find
*
* RETURNS
* Success: A pointer to the list item found
* Failure: NULL
*/
LPSHLWAPI_CLIST WINAPI SHLWAPI_22(LPSHLWAPI_CLIST lpList, ULONG ulId)
{
TRACE("(%p,%ld)\n", lpList, ulId);
if(lpList)
{
while(lpList->ulSize)
{
if(lpList->ulId == ulId)
return lpList; /* Matched */
else if(lpList->ulId == CLIST_ID_CONTAINER && lpList[1].ulId == ulId)
return lpList + 1; /* Contained item matches */
lpList = NextItem(lpList);
}
}
return NULL;
}

View file

@ -737,78 +737,6 @@ HRESULT WINAPI SHLWAPI_16 (
return 0xabba1252;
}
/*************************************************************************
* @ [SHLWAPI.18]
*
* w is pointer to address of callback routine
* x is pointer to LPVOID to receive address of locally allocated
* space size 0x14
* return is 0 (unless out of memory???)
*
* related to _19, _21 and _22 below
* only seen invoked by SHDOCVW
*/
LONG WINAPI SHLWAPI_18 (
LPVOID *w,
LPVOID x)
{
FIXME("(%p %p)stub\n",w,x);
*((LPDWORD)x) = 0;
return 0;
}
/*************************************************************************
* @ [SHLWAPI.19]
*
* w is address of allocated memory from _21
* return is 0 (unless out of memory???)
*
* related to _18, _21 and _22 below
* only seen invoked by SHDOCVW
*/
LONG WINAPI SHLWAPI_19 (
LPVOID w)
{
FIXME("(%p) stub\n",w);
return 0;
}
/*************************************************************************
* @ [SHLWAPI.21]
*
* w points to space allocated via .18 above
* LocalSize is done on it (retrieves 18)
* LocalReAlloc is done on it to size 8 with LMEM_MOVEABLE & LMEM_ZEROINIT
* x values seen 0xa0000005
* returns 1
*
* relates to _18, _19 and _22 above and below
* only seen invoked by SHDOCVW
*/
LONG WINAPI SHLWAPI_21 (
LPVOID w,
DWORD x)
{
FIXME("(%p %lx)stub\n",w,x);
return 1;
}
/*************************************************************************
* @ [SHLWAPI.22]
*
* return is 'w' value seen in x is 0xa0000005
*
* relates to _18, _19 and _21 above
* only seen invoked by SHDOCVW
*/
LPVOID WINAPI SHLWAPI_22 (
LPVOID w,
DWORD x)
{
FIXME("(%p %lx)stub\n",w,x);
return w;
}
/*************************************************************************
* @ [SHLWAPI.23]
*

View file

@ -16,12 +16,12 @@ init SHLWAPI_LibMain
14 stdcall @(ptr ptr) SHLWAPI_14
15 stdcall @(ptr ptr) SHLWAPI_15
16 stdcall @(long long long long) SHLWAPI_16
17 stub @
18 stdcall @(ptr ptr) SHLWAPI_18
19 stdcall @(ptr) SHLWAPI_19
20 stub @
21 stdcall @(ptr long) SHLWAPI_21
22 stdcall @(ptr long) SHLWAPI_22
17 stdcall @ (ptr ptr) SHLWAPI_17
18 stdcall @ (ptr ptr) SHLWAPI_18
19 stdcall @ (ptr) SHLWAPI_19
20 stdcall @ (ptr ptr) SHLWAPI_20
21 stdcall @ (ptr long) SHLWAPI_21
22 stdcall @ (ptr long) SHLWAPI_22
23 stdcall @(ptr ptr long) SHLWAPI_23
24 stdcall @(ptr ptr long) SHLWAPI_24
25 stdcall @(long) SHLWAPI_25

View file

@ -1,3 +1,4 @@
clist.ok
shlwapi_test.exe.spec.c
shreg.ok
testlist.c

454
dlls/shlwapi/tests/clist.c Normal file
View file

@ -0,0 +1,454 @@
/* Unit test suite for SHLWAPI Compact List functions
*
* Copyright 2002 Jon Griffiths
*
* 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
*/
#include "wine/test.h"
#include "winbase.h"
#include "objbase.h"
typedef struct tagSHLWAPI_CLIST
{
ULONG ulSize;
ULONG ulId;
} SHLWAPI_CLIST, *LPSHLWAPI_CLIST;
typedef const SHLWAPI_CLIST* LPCSHLWAPI_CLIST;
/* Items to add */
static const SHLWAPI_CLIST SHLWAPI_CLIST_items[] =
{
{4, 1},
{8, 3},
{12, 2},
{16, 8},
{20, 9},
{3, 11},
{9, 82},
{33, 16},
{32, 55},
{24, 100},
{39, 116},
{ 0, 0}
};
/* Dummy IStream object for testing calls */
typedef struct
{
void* lpVtbl;
ULONG ref;
int readcalls;
BOOL failreadcall;
BOOL failreadsize;
BOOL readbeyondend;
BOOL readreturnlarge;
int writecalls;
BOOL failwritecall;
BOOL failwritesize;
int seekcalls;
int statcalls;
LPCSHLWAPI_CLIST item;
} _IDummyStream;
static
HRESULT WINAPI QueryInterface(_IDummyStream *This,REFIID riid, LPVOID *ppvObj)
{
return S_OK;
}
static ULONG WINAPI AddRef(_IDummyStream *This)
{
return ++This->ref;
}
static ULONG WINAPI Release(_IDummyStream *This)
{
return --This->ref;
}
static HRESULT WINAPI Read(_IDummyStream* This, LPVOID lpMem, ULONG ulSize,
LPULONG lpRead)
{
HRESULT hRet = S_OK;
++This->readcalls;
if (This->failreadcall)
{
return STG_E_ACCESSDENIED;
}
else if (This->failreadsize)
{
*lpRead = ulSize + 8;
return S_OK;
}
else if (This->readreturnlarge)
{
*((ULONG*)lpMem) = 0xffff01;
*lpRead = ulSize;
This->readreturnlarge = FALSE;
return S_OK;
}
if (ulSize == sizeof(ULONG))
{
/* Read size of item */
*((ULONG*)lpMem) = This->item->ulSize ? This->item->ulSize + sizeof(SHLWAPI_CLIST) : 0;
*lpRead = ulSize;
}
else
{
unsigned int i;
char* buff = (char*)lpMem;
/* Read item data */
if (!This->item->ulSize)
{
This->readbeyondend = TRUE;
*lpRead = 0;
return E_FAIL; /* Should never happen */
}
*((ULONG*)lpMem) = This->item->ulId;
*lpRead = ulSize;
for (i = 0; i < This->item->ulSize; i++)
buff[4+i] = i*2;
This->item++;
}
return hRet;
}
static HRESULT WINAPI Write(_IDummyStream* This, LPVOID lpMem, ULONG ulSize,
LPULONG lpWritten)
{
HRESULT hRet = S_OK;
++This->writecalls;
if (This->failwritecall)
{
return STG_E_ACCESSDENIED;
}
else if (This->failwritesize)
{
*lpWritten = 0;
}
else
*lpWritten = ulSize;
return hRet;
}
static HRESULT WINAPI Seek(_IDummyStream* This, LARGE_INTEGER dlibMove,
DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition)
{
++This->seekcalls;
if (plibNewPosition)
plibNewPosition->QuadPart = sizeof(ULONG);
return S_OK;
}
static HRESULT WINAPI Stat(_IDummyStream* This, STATSTG* pstatstg,
DWORD grfStatFlag)
{
++This->statcalls;
if (pstatstg)
pstatstg->cbSize.QuadPart = 5000l;
return S_OK;
}
/* VTable */
static void* iclvt[] =
{
QueryInterface,
AddRef,
Release,
Read,
Write,
Seek,
NULL, /* SetSize */
NULL, /* CopyTo */
NULL, /* Commit */
NULL, /* Revert */
NULL, /* LockRegion */
NULL, /* UnlockRegion */
Stat,
NULL /* Clone */
};
/* Function ptrs for ordinal calls */
static HMODULE SHLWAPI_hshlwapi = 0;
static VOID (WINAPI *pSHLWAPI_19)(LPSHLWAPI_CLIST);
static HRESULT (WINAPI *pSHLWAPI_20)(LPSHLWAPI_CLIST*,LPCSHLWAPI_CLIST);
static BOOL (WINAPI *pSHLWAPI_21)(LPSHLWAPI_CLIST*,ULONG);
static LPSHLWAPI_CLIST (WINAPI *pSHLWAPI_22)(LPSHLWAPI_CLIST,ULONG);
static HRESULT (WINAPI *pSHLWAPI_17)(_IDummyStream*,LPSHLWAPI_CLIST);
static HRESULT (WINAPI *pSHLWAPI_18)(_IDummyStream*,LPSHLWAPI_CLIST*);
static void InitFunctionPtrs()
{
SHLWAPI_hshlwapi = LoadLibraryA("shlwapi.dll");
ok(SHLWAPI_hshlwapi != 0, "LoadLibrary failed");
if (SHLWAPI_hshlwapi)
{
pSHLWAPI_17 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)17);
ok(pSHLWAPI_17 != 0, "No Ordinal 17");
pSHLWAPI_18 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)18);
ok(pSHLWAPI_18 != 0, "No Ordinal 18");
pSHLWAPI_19 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)19);
ok(pSHLWAPI_19 != 0, "No Ordinal 19");
pSHLWAPI_20 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)20);
ok(pSHLWAPI_20 != 0, "No Ordinal 20");
pSHLWAPI_21 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)21);
ok(pSHLWAPI_21 != 0, "No Ordinal 21");
pSHLWAPI_22 = (void *)GetProcAddress( SHLWAPI_hshlwapi, (LPSTR)22);
ok(pSHLWAPI_22 != 0, "No Ordinal 22");
}
}
static void InitDummyStream(_IDummyStream* iface)
{
iface->lpVtbl = (void*)iclvt;
iface->ref = 1;
iface->readcalls = 0;
iface->failreadcall = FALSE;
iface->failreadsize = FALSE;
iface->readbeyondend = FALSE;
iface->readreturnlarge = FALSE;
iface->writecalls = 0;
iface->failwritecall = FALSE;
iface->failwritesize = FALSE;
iface->seekcalls = 0;
iface->statcalls = 0;
iface->item = SHLWAPI_CLIST_items;
}
static void test_CList(void)
{
_IDummyStream streamobj;
LPSHLWAPI_CLIST list = NULL;
LPCSHLWAPI_CLIST item = SHLWAPI_CLIST_items;
HRESULT hRet;
LPSHLWAPI_CLIST inserted;
char buff[64];
unsigned int i;
if (!pSHLWAPI_17 || !pSHLWAPI_18 || !pSHLWAPI_19 || !pSHLWAPI_20 ||
!pSHLWAPI_21 || !pSHLWAPI_22)
return;
/* Populate a list and test the items are added correctly */
while (item->ulSize)
{
/* Create item and fill with data */
inserted = (LPSHLWAPI_CLIST)buff;
inserted->ulSize = item->ulSize + sizeof(SHLWAPI_CLIST);
inserted->ulId = item->ulId;
for (i = 0; i < item->ulSize; i++)
buff[sizeof(SHLWAPI_CLIST)+i] = i*2;
/* Add it */
hRet = pSHLWAPI_20(&list, inserted);
ok(hRet > S_OK, "failed list add");
if (hRet > S_OK)
{
ok(list && list->ulSize, "item not added");
/* Find it */
inserted = pSHLWAPI_22(list, item->ulId);
ok(inserted != NULL, "lost after adding");
ok(!inserted || inserted->ulId != -1u, "find returned a container");
/* Check size */
if (inserted && inserted->ulSize & 0x3)
{
/* Contained */
ok(inserted[-1].ulId == -1u, "invalid size is not countained");
ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST),
"container too small");
}
else if (inserted)
{
ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST),
"id %ld size wrong (%ld!=%ld)", inserted->ulId, inserted->ulSize,
item->ulSize+sizeof(SHLWAPI_CLIST));
}
if (inserted)
{
BOOL bDataOK = TRUE;
LPBYTE bufftest = (LPBYTE)inserted;
for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++)
if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2)
bDataOK = FALSE;
ok(bDataOK == TRUE, "data corrupted on insert");
}
ok(!inserted || inserted->ulId==item->ulId, "find got wrong item");
}
item++;
}
/* Write the list */
InitDummyStream(&streamobj);
hRet = pSHLWAPI_17(&streamobj, list);
ok(hRet == S_OK, "write failed");
if (hRet == S_OK)
{
/* 1 call for each element, + 1 for OK (use our null element for this) */
ok(streamobj.writecalls == sizeof(SHLWAPI_CLIST_items)/sizeof(SHLWAPI_CLIST),
"wrong call count");
ok(streamobj.readcalls == 0,"called Read() in write");
ok(streamobj.seekcalls == 0,"called Seek() in write");
}
/* Failure cases for writing */
InitDummyStream(&streamobj);
streamobj.failwritecall = TRUE;
hRet = pSHLWAPI_17(&streamobj, list);
ok(hRet == STG_E_ACCESSDENIED, "changed object failure return");
ok(streamobj.writecalls == 1, "called object after failure");
ok(streamobj.readcalls == 0,"called Read() after failure");
ok(streamobj.seekcalls == 0,"called Seek() after failure");
InitDummyStream(&streamobj);
streamobj.failwritesize = TRUE;
hRet = pSHLWAPI_17(&streamobj, list);
ok(hRet == STG_E_MEDIUMFULL, "changed size failure return");
ok(streamobj.writecalls == 1, "called object after size failure");
ok(streamobj.readcalls == 0,"called Read() after failure");
ok(streamobj.seekcalls == 0,"called Seek() after failure");
/* Invalid inputs for adding */
inserted = (LPSHLWAPI_CLIST)buff;
inserted->ulSize = sizeof(SHLWAPI_CLIST) -1;
inserted->ulId = 33;
hRet = pSHLWAPI_20(&list, inserted);
ok(hRet == E_INVALIDARG, "allowed bad element size");
inserted->ulSize = 44;
inserted->ulId = -1;
hRet = pSHLWAPI_20(&list, inserted);
ok(hRet == E_INVALIDARG, "allowed adding a container");
item = SHLWAPI_CLIST_items;
/* Look for non-existing item in populated list */
inserted = pSHLWAPI_22(list, 99999999);
ok(inserted == NULL, "found a non-existing item");
while (item->ulSize)
{
/* Delete items */
BOOL bRet = pSHLWAPI_21(&list, item->ulId);
ok(bRet == TRUE, "couldn't find item to delete");
item++;
}
/* Look for non-existing item in empty list */
inserted = pSHLWAPI_22(list, 99999999);
ok(inserted == NULL, "found an item in empty list");
/* Create a list by reading in data */
InitDummyStream(&streamobj);
hRet = pSHLWAPI_18(&streamobj, &list);
ok(hRet == S_OK, "failed create from Read()");
if (hRet == S_OK)
{
ok(streamobj.readbeyondend == FALSE, "read beyond end");
/* 2 calls per item, but only 1 for the terminator */
ok(streamobj.readcalls == sizeof(SHLWAPI_CLIST_items)/sizeof(SHLWAPI_CLIST)*2-1,
"wrong call count");
ok(streamobj.writecalls == 0, "called Write() from create");
ok(streamobj.seekcalls == 0,"called Seek() from create");
item = SHLWAPI_CLIST_items;
/* Check the items were added correctly */
while (item->ulSize)
{
inserted = pSHLWAPI_22(list, item->ulId);
ok(inserted != NULL, "lost after adding");
ok(!inserted || inserted->ulId != -1, "find returned a container");
/* Check size */
if (inserted && inserted->ulSize & 0x3)
{
/* Contained */
ok(inserted[-1].ulId == -1, "invalid size is not countained");
ok(inserted[-1].ulSize > inserted->ulSize+sizeof(SHLWAPI_CLIST),
"container too small");
}
else if (inserted)
{
ok(inserted->ulSize==item->ulSize+sizeof(SHLWAPI_CLIST),
"id %ld size wrong (%ld!=%ld)", inserted->ulId, inserted->ulSize,
item->ulSize+sizeof(SHLWAPI_CLIST));
}
ok(!inserted || inserted->ulId==item->ulId, "find got wrong item");
if (inserted)
{
BOOL bDataOK = TRUE;
char *bufftest = (char*)inserted;
for (i = 0; i < inserted->ulSize - sizeof(SHLWAPI_CLIST); i++)
if (bufftest[sizeof(SHLWAPI_CLIST)+i] != i*2)
bDataOK = FALSE;
ok(bDataOK == TRUE, "data corrupted on insert");
}
item++;
}
}
/* Failure cases for reading */
InitDummyStream(&streamobj);
streamobj.failreadcall = TRUE;
hRet = pSHLWAPI_18(&streamobj, &list);
ok(hRet == STG_E_ACCESSDENIED, "changed object failure return");
ok(streamobj.readbeyondend == FALSE, "read beyond end");
ok(streamobj.readcalls == 1, "called object after read failure");
ok(streamobj.writecalls == 0,"called Write() after read failure");
ok(streamobj.seekcalls == 0,"called Seek() after read failure");
/* Read returns large object */
InitDummyStream(&streamobj);
streamobj.readreturnlarge = TRUE;
hRet = pSHLWAPI_18(&streamobj, &list);
ok(hRet == S_OK, "failed create from Read() with large item");
ok(streamobj.readbeyondend == FALSE, "read beyond end");
ok(streamobj.readcalls == 1,"wrong call count");
ok(streamobj.writecalls == 0,"called Write() after read failure");
ok(streamobj.seekcalls == 2,"wrong Seek() call count (%d)", streamobj.seekcalls);
pSHLWAPI_19(list);
}
START_TEST(clist)
{
InitFunctionPtrs();
test_CList();
if (SHLWAPI_hshlwapi)
FreeLibrary(SHLWAPI_hshlwapi);
}