kernel32: Store resources to be updated in a tree.
This commit is contained in:
parent
1c85155eaa
commit
9196a37201
|
@ -616,16 +616,200 @@ DWORD WINAPI SizeofResource( HINSTANCE hModule, HRSRC hRsrc )
|
||||||
return ((PIMAGE_RESOURCE_DATA_ENTRY)hRsrc)->Size;
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
LPWSTR pFileName;
|
LPWSTR pFileName;
|
||||||
|
struct list root;
|
||||||
} QUEUEDUPDATES;
|
} 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,
|
BOOL update_add_resource( QUEUEDUPDATES *updates, LPCWSTR Type, LPCWSTR Name,
|
||||||
WORD Language, DWORD codepage, LPCVOID lpData, DWORD cbData )
|
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);
|
struct resource_dir_entry *restype, *resname;
|
||||||
return FALSE;
|
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 )
|
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);
|
updates = GlobalLock(hUpdate);
|
||||||
if (updates)
|
if (updates)
|
||||||
{
|
{
|
||||||
|
list_init( &updates->root );
|
||||||
updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
|
updates->pFileName = HeapAlloc(GetProcessHeap(), 0, (lstrlenW(pFileName)+1)*sizeof(WCHAR));
|
||||||
if (updates->pFileName)
|
if (updates->pFileName)
|
||||||
{
|
{
|
||||||
|
@ -797,6 +982,8 @@ BOOL WINAPI EndUpdateResourceW( HANDLE hUpdate, BOOL fDiscard )
|
||||||
|
|
||||||
ret = fDiscard || write_raw_resources( updates );
|
ret = fDiscard || write_raw_resources( updates );
|
||||||
|
|
||||||
|
free_resource_directory( &updates->root, 2 );
|
||||||
|
|
||||||
HeapFree( GetProcessHeap(), 0, updates->pFileName );
|
HeapFree( GetProcessHeap(), 0, updates->pFileName );
|
||||||
GlobalUnlock( hUpdate );
|
GlobalUnlock( hUpdate );
|
||||||
GlobalFree( hUpdate );
|
GlobalFree( hUpdate );
|
||||||
|
|
|
@ -178,7 +178,6 @@ void update_resources_version(void)
|
||||||
res = BeginUpdateResource( filename, TRUE );
|
res = BeginUpdateResource( filename, TRUE );
|
||||||
ok( res != NULL, "BeginUpdateResource failed\n");
|
ok( res != NULL, "BeginUpdateResource failed\n");
|
||||||
|
|
||||||
todo_wine {
|
|
||||||
memset( &hdr, 0, sizeof hdr );
|
memset( &hdr, 0, sizeof hdr );
|
||||||
r = UpdateResource( res,
|
r = UpdateResource( res,
|
||||||
RT_VERSION,
|
RT_VERSION,
|
||||||
|
@ -186,7 +185,6 @@ void update_resources_version(void)
|
||||||
MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
|
MAKELANGID(LANG_ENGLISH, SUBLANG_NEUTRAL),
|
||||||
&hdr, sizeof hdr );
|
&hdr, sizeof hdr );
|
||||||
ok( r, "UpdateResouce failed\n");
|
ok( r, "UpdateResouce failed\n");
|
||||||
}
|
|
||||||
|
|
||||||
r = UpdateResource( res,
|
r = UpdateResource( res,
|
||||||
MAKEINTRESOURCE(0x1230),
|
MAKEINTRESOURCE(0x1230),
|
||||||
|
@ -195,7 +193,6 @@ void update_resources_version(void)
|
||||||
NULL, 0 );
|
NULL, 0 );
|
||||||
ok( r == FALSE, "UpdateResouce failed\n");
|
ok( r == FALSE, "UpdateResouce failed\n");
|
||||||
|
|
||||||
todo_wine {
|
|
||||||
r = UpdateResource( res,
|
r = UpdateResource( res,
|
||||||
MAKEINTRESOURCE(0x1230),
|
MAKEINTRESOURCE(0x1230),
|
||||||
MAKEINTRESOURCE(0x4567),
|
MAKEINTRESOURCE(0x4567),
|
||||||
|
@ -204,8 +201,7 @@ void update_resources_version(void)
|
||||||
ok( r == TRUE, "UpdateResouce failed\n");
|
ok( r == TRUE, "UpdateResouce failed\n");
|
||||||
|
|
||||||
r = EndUpdateResource( res, FALSE );
|
r = EndUpdateResource( res, FALSE );
|
||||||
ok( r, "EndUpdateResouce failed\n");
|
todo_wine ok( r, "EndUpdateResouce failed\n");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue