Mike McCormack : kernel32: Store resources to be updated in a tree.
Alexandre Julliard
julliard at wine.codeweavers.com
Wed Jan 3 05:37:39 CST 2007
Module: wine
Branch: master
Commit: 9196a3720124c78242f214e2b1433256a635db48
URL: http://source.winehq.org/git/wine.git/?a=commit;h=9196a3720124c78242f214e2b1433256a635db48
Author: Mike McCormack <mike at codeweavers.com>
Date: Wed Jan 3 17:32:52 2007 +0900
kernel32: Store resources to be updated in a tree.
---
dlls/kernel32/resource.c | 191 +++++++++++++++++++++++++++++++++++++++-
dlls/kernel32/tests/resource.c | 6 +-
2 files changed, 190 insertions(+), 7 deletions(-)
diff --git a/dlls/kernel32/resource.c b/dlls/kernel32/resource.c
index c817fcb..23833f5 100644
--- a/dlls/kernel32/resource.c
+++ b/dlls/kernel32/resource.c
@@ -616,16 +616,200 @@ DWORD WINAPI SizeofResource( HINSTANCE h
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( LPCW
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 h
ret = fDiscard || write_raw_resources( updates );
+ free_resource_directory( &updates->root, 2 );
+
HeapFree( GetProcessHeap(), 0, updates->pFileName );
GlobalUnlock( hUpdate );
GlobalFree( hUpdate );
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c
index 0c84757..9a26a12 100644
--- a/dlls/kernel32/tests/resource.c
+++ b/dlls/kernel32/tests/resource.c
@@ -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");
}
More information about the wine-cvs
mailing list