Mike McCormack : kernel32: Merge existing resources in EndUpdateResource.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Jan 11 05:34:14 CST 2007


Module: wine
Branch: master
Commit: f01707dfc14d7aec496f66e1810e210bf329e64e
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=f01707dfc14d7aec496f66e1810e210bf329e64e

Author: Mike McCormack <mike at codeweavers.com>
Date:   Thu Jan 11 17:43:54 2007 +0900

kernel32: Merge existing resources in EndUpdateResource.

---

 dlls/kernel32/resource.c       |  174 +++++++++++++++++++++++++++++++++++++---
 dlls/kernel32/tests/resource.c |    9 +--
 2 files changed, 166 insertions(+), 17 deletions(-)

diff --git a/dlls/kernel32/resource.c b/dlls/kernel32/resource.c
index 54955c5..2b1bdf4 100644
--- a/dlls/kernel32/resource.c
+++ b/dlls/kernel32/resource.c
@@ -3,6 +3,7 @@
  *
  * Copyright 1993 Robert J. Amstadt
  * Copyright 1995, 2003 Alexandre Julliard
+ * Copyright 2006 Mike McCormack
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -621,9 +622,9 @@ DWORD WINAPI SizeofResource( HINSTANCE h
  *  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
+ *    list of struct resource_dir_entry    (Type) ->
+ *      list of struct resource_dir_entry  (Name)   ->
+ *         list of struct resource_data    Language + Data
  */
 
 typedef struct
@@ -938,6 +939,150 @@ struct mapping_info {
     BOOL read_write;
 };
 
+static const IMAGE_SECTION_HEADER *section_from_rva( void *base, DWORD mapping_size, DWORD rva )
+{
+    const IMAGE_SECTION_HEADER *sec;
+    DWORD num_sections = 0;
+    int i;
+
+    sec = get_section_header( base, mapping_size, &num_sections );
+    if (!sec)
+        return NULL;
+
+    for (i=num_sections-1; i>=0; i--)
+    {
+        if (sec[i].VirtualAddress <= rva &&
+            rva <= (DWORD)sec[i].VirtualAddress + sec[i].SizeOfRawData)
+        {
+            return &sec[i];
+        }
+    }
+
+    return NULL;
+}
+
+static void *address_from_rva( void *base, DWORD mapping_size, DWORD rva, DWORD len )
+{
+    const IMAGE_SECTION_HEADER *sec;
+
+    sec = section_from_rva( base, mapping_size, rva );
+    if (!sec)
+        return NULL;
+
+    if (rva + len <= (DWORD)sec->VirtualAddress + sec->SizeOfRawData)
+        return (void*)((const BYTE*) base + (sec->PointerToRawData + rva - sec->VirtualAddress));
+
+    return NULL;
+}
+
+static LPWSTR resource_dup_string( const IMAGE_RESOURCE_DIRECTORY *root, const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry )
+{
+    const IMAGE_RESOURCE_DIR_STRING_U* string;
+    LPWSTR s;
+
+    if (!entry->u1.s1.NameIsString)
+        return (LPWSTR) (DWORD) entry->u1.s2.Id;
+
+    string = (const IMAGE_RESOURCE_DIR_STRING_U*) (((const char *)root) + entry->u1.s1.NameOffset);
+    s = HeapAlloc(GetProcessHeap(), 0, (string->Length + 1)*sizeof (WCHAR) );
+    memcpy( s, string->NameString, (string->Length + 1)*sizeof (WCHAR) );
+    s[string->Length] = 0;
+
+    return s;
+}
+
+/* this function is based on the code in winedump's pe.c */
+static BOOL enumerate_mapped_resources( QUEUEDUPDATES *updates,
+                             void *base, DWORD mapping_size,
+                             const IMAGE_RESOURCE_DIRECTORY *root )
+{
+    const IMAGE_RESOURCE_DIRECTORY *namedir, *langdir;
+    const IMAGE_RESOURCE_DIRECTORY_ENTRY *e1, *e2, *e3;
+    const IMAGE_RESOURCE_DATA_ENTRY *data;
+    DWORD i, j, k;
+
+    TRACE("version (%d.%d) %d named %d id entries\n",
+          root->MajorVersion, root->MinorVersion, root->NumberOfNamedEntries, root->NumberOfIdEntries);
+
+    for (i = 0; i< root->NumberOfNamedEntries + root->NumberOfIdEntries; i++)
+    {
+        LPWSTR Type;
+
+        e1 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(root + 1) + i;
+
+        Type = resource_dup_string( root, e1 );
+
+        namedir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e1->u2.s3.OffsetToDirectory);
+        for (j = 0; j < namedir->NumberOfNamedEntries + namedir->NumberOfIdEntries; j++)
+        {
+            LPWSTR Name;
+
+            e2 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(namedir + 1) + j;
+
+            Name = resource_dup_string( root, e2 );
+
+            langdir = (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + e2->u2.s3.OffsetToDirectory);
+            for (k = 0; k < langdir->NumberOfNamedEntries + langdir->NumberOfIdEntries; k++)
+            {
+                LANGID Lang;
+                void *p;
+                struct resource_data *resdata;
+
+                e3 = (const IMAGE_RESOURCE_DIRECTORY_ENTRY*)(langdir + 1) + k;
+
+                Lang = e3->u1.s2.Id;
+
+                data = (const IMAGE_RESOURCE_DATA_ENTRY *)((const char *)root + e3->u2.OffsetToData);
+
+                p = address_from_rva( base, mapping_size, data->OffsetToData, data->Size );
+
+                resdata = allocate_resource_data( Lang, data->CodePage, p, data->Size, FALSE );
+                if (resdata)
+                    update_add_resource( updates, Type, Name, resdata, FALSE );
+            }
+            res_free_str( Name );
+        }
+        res_free_str( Type );
+    }
+
+    return TRUE;
+}
+
+static BOOL read_mapped_resources( QUEUEDUPDATES *updates, void *base, DWORD mapping_size )
+{
+    const IMAGE_RESOURCE_DIRECTORY *root;
+    const IMAGE_NT_HEADERS *nt;
+    const IMAGE_SECTION_HEADER *sec;
+    DWORD num_sections = 0, i;
+
+    nt = get_nt_header( base, mapping_size );
+    if (!nt)
+        return FALSE;
+
+    sec = get_section_header( base, mapping_size, &num_sections );
+    if (!sec)
+        return FALSE;
+
+    for (i=0; i<num_sections; i++)
+        if (!memcmp(sec[i].Name, ".rsrc", 6))
+            break;
+
+    if (i == num_sections)
+        return TRUE;
+
+    /* check the resource data is inside the mapping */
+    if (sec[i].PointerToRawData > mapping_size ||
+        (sec[i].PointerToRawData + sec[i].SizeOfRawData) > mapping_size)
+        return TRUE;
+
+    TRACE("found .rsrc at %08x, size %08x\n", sec[i].PointerToRawData, sec[i].SizeOfRawData);
+
+    root = (void*) ((BYTE*)base + sec[i].PointerToRawData);
+    enumerate_mapped_resources( updates, base, mapping_size, root );
+
+    return TRUE;
+}
+
 static BOOL map_file_into_memory( struct mapping_info *mi )
 {
     DWORD page_attr, perm;
@@ -1293,7 +1438,7 @@ static BOOL write_raw_resources( QUEUEDU
     IMAGE_NT_HEADERS *nt;
     struct resource_size_info res_size;
     BYTE *res_base;
-    struct mapping_info *write_map = NULL;
+    struct mapping_info *read_map = NULL, *write_map = NULL;
 
     /* copy the exe to a temp file then update the temp file... */
     tempdir[0] = 0;
@@ -1308,6 +1453,20 @@ static BOOL write_raw_resources( QUEUEDU
 
     TRACE("tempfile %s\n", debugstr_w(tempfile));
 
+    if (!updates->bDeleteExistingResources)
+    {
+        read_map = create_mapping( updates->pFileName, FALSE );
+        if (!read_map)
+            goto done;
+
+        ret = read_mapped_resources( updates, read_map->base, read_map->size );
+        if (!ret)
+        {
+            ERR("failed to read existing resources\n");
+            goto done;
+        }
+    }
+
     write_map = create_mapping( tempfile, TRUE );
     if (!write_map)
         goto done;
@@ -1386,6 +1545,7 @@ static BOOL write_raw_resources( QUEUEDU
     TRACE("after  .rsrc at %08x, size %08x\n", sec->PointerToRawData, sec->SizeOfRawData);
 
 done:
+    destroy_mapping( read_map );
     destroy_mapping( write_map );
 
     if (ret)
@@ -1470,12 +1630,6 @@ BOOL WINAPI EndUpdateResourceW( HANDLE h
     if (!updates)
         return FALSE;
 
-    if (!updates->bDeleteExistingResources)
-    {
-        FIXME("preserving existing resources not yet implemented\n");
-        fDiscard = TRUE;
-    }
-
     ret = fDiscard || write_raw_resources( updates );
 
     free_resource_directory( &updates->root, 2 );
diff --git a/dlls/kernel32/tests/resource.c b/dlls/kernel32/tests/resource.c
index 0826c34..b77f86c 100644
--- a/dlls/kernel32/tests/resource.c
+++ b/dlls/kernel32/tests/resource.c
@@ -266,13 +266,8 @@ START_TEST(resource)
     update_missing_exe();
     update_empty_exe();
     build_exe();
-
-    /* for when BeginUpdateResource( bDeleteExisting = FALSE ) works right */
-    if (0)
-    {
-        update_resources_none();
-        check_exe( check_empty );
-    }
+    update_resources_none();
+    check_exe( check_empty );
     update_resources_delete();
     check_exe( check_empty );
     update_resources_version();




More information about the wine-cvs mailing list