kernel32: Store resources to be updated in a tree.

oldstable
Mike McCormack 2007-01-03 17:32:52 +09:00 committed by Alexandre Julliard
parent 1c85155eaa
commit 9196a37201
2 changed files with 190 additions and 7 deletions

View File

@ -616,16 +616,200 @@ DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
}
/*
* Data structure for updating resources.
* Type/Name/Language is a keyset for accessing resource data.
*
* QUEUEDUPDATES (root) ->
* list of struct resouce_dir_entry (Type) ->
* list of struct resouce_dir_entry (Name) ->
* list of struct resouce_data Language + Data
*/
typedef struct
{
LPWSTR pFileName;
struct list root;
} QUEUEDUPDATES;
/* this structure is shared for types and names */
struct resource_dir_entry {
struct list entry;
LPWSTR id;
struct list children;
};
/* this structure is the leaf */
struct resource_data {
struct list entry;
LANGID lang;
DWORD codepage;
DWORD cbData;
BYTE data[1];
};
int resource_strcmp( LPCWSTR a, LPCWSTR b )
{
if ( a == b )
return 0;
if (HIWORD( a ) && HIWORD( b ) )
return lstrcmpW( a, b );
/* strings come before ids */
if (HIWORD( a ) && !HIWORD( b ))
return -1;
if (HIWORD( b ) && !HIWORD( a ))
return 1;
return ( a < b ) ? -1 : 1;
}
struct resource_dir_entry *find_resource_dir_entry( struct list *dir, LPCWSTR id )
{
struct resource_dir_entry *ent;
/* match either IDs or strings */
LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
if (!resource_strcmp( id, ent->id ))
return ent;
return NULL;
}
struct resource_data *find_resource_data( struct list *dir, LANGID lang )
{
struct resource_data *res_data;
/* match only languages here */
LIST_FOR_EACH_ENTRY( res_data, dir, struct resource_data, entry )
if ( lang == res_data->lang )
return res_data;
return NULL;
}
void add_resource_dir_entry( struct list *dir, struct resource_dir_entry *resdir )
{
struct resource_dir_entry *ent;
LIST_FOR_EACH_ENTRY( ent, dir, struct resource_dir_entry, entry )
{
if (0>resource_strcmp( ent->id, resdir->id ))
continue;
list_add_before( &ent->entry, &resdir->entry );
return;
}
list_add_tail( dir, &resdir->entry );
}
void add_resource_data_entry( struct list *dir, struct resource_data *resdata )
{
struct resource_data *ent;
LIST_FOR_EACH_ENTRY( ent, dir, struct resource_data, entry )
{
if (ent->lang < resdata->lang)
continue;
list_add_before( &ent->entry, &resdata->entry );
return;
}
list_add_tail( dir, &resdata->entry );
}
LPWSTR res_strdupW( LPCWSTR str )
{
LPWSTR ret;
UINT len;
if (HIWORD(str) == 0)
return (LPWSTR) (UINT_PTR) LOWORD(str);
len = (lstrlenW( str ) + 1) * sizeof (WCHAR);
ret = HeapAlloc( GetProcessHeap(), 0, len );
memcpy( ret, str, len );
return ret;
}
void res_free_str( LPWSTR str )
{
if (HIWORD(str))
HeapFree( GetProcessHeap(), 0, str );
}
BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
WORD Language, DWORD codepage, LPCVOID lpData, DWORD cbData )
{
FIXME("%p %s %s %04x %p %d bytes\n", updates, debugstr_w(Type), debugstr_w(Name), Language, lpData, cbData);
return FALSE;
struct resource_dir_entry *restype, *resname;
struct resource_data *resdata;
TRACE("%p %s %s %04x %04x %p %d bytes\n", updates, debugstr_w(Type), debugstr_w(Name), Language, codepage, lpData, cbData);
if (!lpData || !cbData)
return FALSE;
restype = find_resource_dir_entry( &updates->root, Type );
if (!restype)
{
restype = HeapAlloc( GetProcessHeap(), 0, sizeof *restype );
restype->id = res_strdupW( Type );
list_init( &restype->children );
add_resource_dir_entry( &updates->root, restype );
}
resname = find_resource_dir_entry( &restype->children, Name );
if (!resname)
{
resname = HeapAlloc( GetProcessHeap(), 0, sizeof *resname );
resname->id = res_strdupW( Name );
list_init( &resname->children );
add_resource_dir_entry( &restype->children, resname );
}
/*
* If there's an existing resource entry with matching (Type,Name,Language)
* it needs to be removed before adding the new data.
*/
resdata = find_resource_data( &resname->children, Language );
if (resdata)
{
list_remove( &resdata->entry );
HeapFree( GetProcessHeap(), 0, resdata );
}
resdata = HeapAlloc( GetProcessHeap(), 0, sizeof *resdata + cbData );
resdata->lang = Language;
resdata->codepage = codepage;
resdata->cbData = cbData;
memcpy( resdata->data, lpData, cbData );
add_resource_data_entry( &resname->children, resdata );
return TRUE;
}
void free_resource_directory( struct list *head, int level )
{
struct list *ptr = NULL;
while ((ptr = list_head( head )))
{
list_remove( ptr );
if (level)
{
struct resource_dir_entry *ent;
ent = LIST_ENTRY( ptr, struct resource_dir_entry, entry );
res_free_str( ent->id );
free_resource_directory( &ent->children, level - 1 );
HeapFree(GetProcessHeap(), 0, ent);
}
else
{
struct resource_data *data;
data = LIST_ENTRY( ptr, struct resource_data, entry );
HeapFree( GetProcessHeap(), 0, data );
}
}
}
IMAGE_NT_HEADERS *get_nt_header( void *base, DWORD mapping_size )
@ -740,6 +924,7 @@ HANDLE WINAPI BeginUpdateResourceW( LPCWSTR pFileName, BOOL bDeleteExistingResou
updates = GlobalLock(hUpdate);
if (updates)
{
list_init( &updates->root );
updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
if (updates->pFileName)
{
@ -797,6 +982,8 @@ BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
ret = fDiscard || write_raw_resources( updates );
free_resource_directory( &updates->root, 2 );
HeapFree( GetProcessHeap(), 0, updates->pFileName );
GlobalUnlock( hUpdate );
GlobalFree( hUpdate );

View File

@ -178,7 +178,6 @@ void update_resources_version(void)
res = BeginUpdateResource( filename, TRUE );
ok( res != NULL, "BeginUpdateResource failed\n");
todo_wine {
memset( &hdr, 0, sizeof hdr );
r = UpdateResource( res,
RT_VERSION,
@ -186,7 +185,6 @@ void update_resources_version(void)
MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
&hdr, sizeof hdr );
ok( r, "UpdateResouce failed\n");
}
r = UpdateResource( res,
MAKEINTRESOURCE(0x1230),
@ -195,7 +193,6 @@ void update_resources_version(void)
NULL, 0 );
ok( r == FALSE, "UpdateResouce failed\n");
todo_wine {
r = UpdateResource( res,
MAKEINTRESOURCE(0x1230),
MAKEINTRESOURCE(0x4567),
@ -204,8 +201,7 @@ void update_resources_version(void)
ok( r == TRUE, "UpdateResouce failed\n");
r = EndUpdateResource( res, FALSE );
ok( r, "EndUpdateResouce failed\n");
}
todo_wine ok( r, "EndUpdateResouce failed\n");
}