diff --git a/dlls/shlwapi/ordinal.c b/dlls/shlwapi/ordinal.c index e5643593087..77db650abd0 100644 --- a/dlls/shlwapi/ordinal.c +++ b/dlls/shlwapi/ordinal.c @@ -2216,63 +2216,129 @@ BOOL WINAPI SHIsChildOrSelf(HWND hParent, HWND hChild) return !IsChild(hParent, hChild); } +/************************************************************************* + * FDSA functions. Manage a dynamic array of fixed size memory blocks. + */ + +typedef struct +{ + DWORD num_items; /* Number of elements inserted */ + void *mem; /* Ptr to array */ + DWORD blocks_alloced; /* Number of elements allocated */ + BYTE inc; /* Number of elements to grow by when we need to expand */ + BYTE block_size; /* Size in bytes of an element */ + BYTE flags; /* Flags */ +} FDSA_info; + +#define FDSA_FLAG_INTERNAL_ALLOC 0x01 /* When set we have allocated mem internally */ + /************************************************************************* * @ [SHLWAPI.208] * - * Some sort of memory management process. + * Initialize an FDSA arrary. */ -DWORD WINAPI FDSA_Initialize( - DWORD a, - DWORD b, - LPVOID c, - LPVOID d, - DWORD e) +BOOL WINAPI FDSA_Initialize(DWORD block_size, DWORD inc, FDSA_info *info, void *mem, + DWORD init_blocks) { - FIXME("(0x%08lx 0x%08lx %p %p 0x%08lx) stub\n", - a, b, c, d, e); - return 1; + TRACE("(0x%08lx 0x%08lx %p %p 0x%08lx)\n", block_size, inc, info, mem, init_blocks); + + if(inc == 0) + inc = 1; + + if(mem) + memset(mem, 0, block_size * init_blocks); + + info->num_items = 0; + info->inc = inc; + info->mem = mem; + info->blocks_alloced = init_blocks; + info->block_size = block_size; + info->flags = 0; + + return TRUE; } /************************************************************************* * @ [SHLWAPI.209] * - * Some sort of memory management process. + * Destroy an FDSA array */ -DWORD WINAPI FDSA_Destroy( - LPVOID a) +BOOL WINAPI FDSA_Destroy(FDSA_info *info) { - FIXME("(%p) stub\n", - a); - return 1; + TRACE("(%p)\n", info); + + if(info->flags & FDSA_FLAG_INTERNAL_ALLOC) + { + HeapFree(GetProcessHeap(), 0, info->mem); + return FALSE; + } + + return TRUE; } /************************************************************************* * @ [SHLWAPI.210] * - * Some sort of memory management process. + * Insert element into an FDSA array */ -DWORD WINAPI FDSA_InsertItem( - LPVOID a, - DWORD b, - LPVOID c) +DWORD WINAPI FDSA_InsertItem(FDSA_info *info, DWORD where, void *block) { - FIXME("(%p 0x%08lx %p) stub\n", - a, b, c); - return 0; + TRACE("(%p 0x%08lx %p)\n", info, where, block); + if(where > info->num_items) + where = info->num_items; + + if(info->num_items >= info->blocks_alloced) + { + DWORD size = (info->blocks_alloced + info->inc) * info->block_size; + if(info->flags & 0x1) + info->mem = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, info->mem, size); + else + { + void *old_mem = info->mem; + info->mem = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size); + memcpy(info->mem, old_mem, info->blocks_alloced * info->block_size); + } + info->blocks_alloced += info->inc; + info->flags |= 0x1; + } + + if(where < info->num_items) + { + memmove((char*)info->mem + (where + 1) * info->block_size, + (char*)info->mem + where * info->block_size, + (info->num_items - where) * info->block_size); + } + memcpy((char*)info->mem + where * info->block_size, block, info->block_size); + + info->num_items++; + return where; } /************************************************************************* * @ [SHLWAPI.211] + * + * Delete an element from an FDSA array. */ -DWORD WINAPI FDSA_DeleteItem( - LPVOID a, - DWORD b) +BOOL WINAPI FDSA_DeleteItem(FDSA_info *info, DWORD where) { - FIXME("(%p 0x%08lx) stub\n", - a, b); - return 1; + TRACE("(%p 0x%08lx)\n", info, where); + + if(where >= info->num_items) + return FALSE; + + if(where < info->num_items - 1) + { + memmove((char*)info->mem + where * info->block_size, + (char*)info->mem + (where + 1) * info->block_size, + (info->num_items - where - 1) * info->block_size); + } + memset((char*)info->mem + (info->num_items - 1) * info->block_size, + 0, info->block_size); + info->num_items--; + return TRUE; } + typedef struct { REFIID refid; DWORD indx; diff --git a/dlls/shlwapi/tests/ordinal.c b/dlls/shlwapi/tests/ordinal.c index 20798c72c9a..8a27116878a 100644 --- a/dlls/shlwapi/tests/ordinal.c +++ b/dlls/shlwapi/tests/ordinal.c @@ -227,6 +227,106 @@ static void test_alloc_shared(void) ok( ret, "SHFreeShared failed: %ld\n", GetLastError()); } +static void test_fdsa(void) +{ + typedef struct + { + DWORD num_items; /* Number of elements inserted */ + void *mem; /* Ptr to array */ + DWORD blocks_alloced; /* Number of elements allocated */ + BYTE inc; /* Number of elements to grow by when we need to expand */ + BYTE block_size; /* Size in bytes of an element */ + BYTE flags; /* Flags */ + } FDSA_info; + + BOOL (WINAPI *pFDSA_Initialize)(DWORD block_size, DWORD inc, FDSA_info *info, void *mem, + DWORD init_blocks); + BOOL (WINAPI *pFDSA_Destroy)(FDSA_info *info); + DWORD (WINAPI *pFDSA_InsertItem)(FDSA_info *info, DWORD where, void *block); + BOOL (WINAPI *pFDSA_DeleteItem)(FDSA_info *info, DWORD where); + + FDSA_info info; + int block_size = 10, init_blocks = 4, inc = 2; + DWORD ret; + char *mem; + + pFDSA_Initialize = (void *)GetProcAddress(hShlwapi, (LPSTR)208); + pFDSA_Destroy = (void *)GetProcAddress(hShlwapi, (LPSTR)209); + pFDSA_InsertItem = (void *)GetProcAddress(hShlwapi, (LPSTR)210); + pFDSA_DeleteItem = (void *)GetProcAddress(hShlwapi, (LPSTR)211); + + mem = HeapAlloc(GetProcessHeap(), 0, block_size * init_blocks); + memset(&info, 0, sizeof(info)); + + ok(pFDSA_Initialize(block_size, inc, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n"); + ok(info.num_items == 0, "num_items = %ld\n", info.num_items); + ok(info.mem == mem, "mem = %p\n", info.mem); + ok(info.blocks_alloced == init_blocks, "blocks_alloced = %ld\n", info.blocks_alloced); + ok(info.inc == inc, "inc = %d\n", info.inc); + ok(info.block_size == block_size, "block_size = %d\n", info.block_size); + ok(info.flags == 0, "flags = %d\n", info.flags); + + ret = pFDSA_InsertItem(&info, 1234, "1234567890"); + ok(ret == 0, "ret = %ld\n", ret); + ok(info.num_items == 1, "num_items = %ld\n", info.num_items); + ok(info.mem == mem, "mem = %p\n", info.mem); + ok(info.blocks_alloced == init_blocks, "blocks_alloced = %ld\n", info.blocks_alloced); + ok(info.inc == inc, "inc = %d\n", info.inc); + ok(info.block_size == block_size, "block_size = %d\n", info.block_size); + ok(info.flags == 0, "flags = %d\n", info.flags); + + ret = pFDSA_InsertItem(&info, 1234, "abcdefghij"); + ok(ret == 1, "ret = %ld\n", ret); + + ret = pFDSA_InsertItem(&info, 1, "klmnopqrst"); + ok(ret == 1, "ret = %ld\n", ret); + + ret = pFDSA_InsertItem(&info, 0, "uvwxyzABCD"); + ok(ret == 0, "ret = %ld\n", ret); + ok(info.mem == mem, "mem = %p\n", info.mem); + ok(info.flags == 0, "flags = %d\n", info.flags); + + /* This next InsertItem will cause shlwapi to allocate its own mem buffer */ + ret = pFDSA_InsertItem(&info, 0, "EFGHIJKLMN"); + ok(ret == 0, "ret = %ld\n", ret); + ok(info.mem != mem, "mem = %p\n", info.mem); + ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\n", info.blocks_alloced); + ok(info.flags == 0x1, "flags = %d\n", info.flags); + + ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCD1234567890klmnopqrstabcdefghij", 50), "mem %s\n", (char*)info.mem); + + ok(pFDSA_DeleteItem(&info, 2), "rets FALSE\n"); + ok(info.mem != mem, "mem = %p\n", info.mem); + ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\n", info.blocks_alloced); + ok(info.flags == 0x1, "flags = %d\n", info.flags); + + ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrstabcdefghij", 40), "mem %s\n", (char*)info.mem); + + ok(pFDSA_DeleteItem(&info, 3), "rets FALSE\n"); + ok(info.mem != mem, "mem = %p\n", info.mem); + ok(info.blocks_alloced == init_blocks + inc, "blocks_alloced = %ld\n", info.blocks_alloced); + ok(info.flags == 0x1, "flags = %d\n", info.flags); + + ok(!memcmp(info.mem, "EFGHIJKLMNuvwxyzABCDklmnopqrst", 30), "mem %s\n", (char*)info.mem); + + ok(!pFDSA_DeleteItem(&info, 4), "does not ret FALSE\n"); + + /* As shlwapi has allocated memory internally, Destroy will ret FALSE */ + ok(!pFDSA_Destroy(&info), "FDSA_Destroy does not ret FALSE\n"); + + + /* When Initialize is called with inc = 0, set it to 1 */ + ok(pFDSA_Initialize(block_size, 0, &info, mem, init_blocks), "FDSA_Initialize rets FALSE\n"); + ok(info.inc == 1, "inc = %d\n", info.inc); + + /* This time, because shlwapi hasn't had to allocate memory + internally, Destroy rets non-zero */ + ok(pFDSA_Destroy(&info), "FDSA_Destroy rets FALSE\n"); + + + HeapFree(GetProcessHeap(), 0, mem); +} + START_TEST(ordinal) { hShlwapi = LoadLibraryA("shlwapi.dll"); @@ -244,5 +344,7 @@ START_TEST(ordinal) test_GetAcceptLanguagesA(); test_SHSearchMapInt(); test_alloc_shared(); + test_fdsa(); + FreeLibrary(hShlwapi); }