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