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