Module: wine Branch: master Commit: f01707dfc14d7aec496f66e1810e210bf329e64e URL: http://source.winehq.org/git/wine.git/?a=commit;h=f01707dfc14d7aec496f66e181...
Author: Mike McCormack mike@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();