kernel32: Merge existing resources in EndUpdateResource.

This commit is contained in:
Mike McCormack 2007-01-11 17:43:54 +09:00 committed by Alexandre Julliard
parent 38e27fa9f8
commit f01707dfc1
2 changed files with 166 additions and 17 deletions

View file

@ -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 hModule, HRSRC hRsrc )
* 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( QUEUEDUPDATES *updates )
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( QUEUEDUPDATES *updates )
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( QUEUEDUPDATES *updates )
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 hUpdate, BOOL fDiscard )
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 );

View file

@ -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_delete();
check_exe( check_empty );
update_resources_version();