2003-12-29 22:50:59 +00:00
|
|
|
/*
|
|
|
|
* Implementation of VERSION.DLL - Resource Access routines
|
|
|
|
*
|
|
|
|
* Copyright 1996,1997 Marcus Meissner
|
|
|
|
* Copyright 1997 David Cuthbert
|
|
|
|
* Copyright 1999 Ulrich Weigand
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2007-07-27 10:17:42 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2003-12-29 22:50:59 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2007-07-27 10:17:42 +00:00
|
|
|
#define NONAMELESSUNION
|
2003-12-29 22:50:59 +00:00
|
|
|
#define NONAMELESSSTRUCT
|
|
|
|
#include "windef.h"
|
|
|
|
#include "winbase.h"
|
|
|
|
#include "lzexpand.h"
|
2010-03-21 21:02:06 +00:00
|
|
|
#include "winuser.h"
|
|
|
|
#include "winver.h"
|
|
|
|
#undef VS_FILE_INFO
|
|
|
|
#define VS_FILE_INFO 16
|
2003-12-29 22:50:59 +00:00
|
|
|
|
|
|
|
#include "wine/unicode.h"
|
|
|
|
|
|
|
|
#include "wine/debug.h"
|
|
|
|
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
WORD offset;
|
|
|
|
WORD length;
|
|
|
|
WORD flags;
|
|
|
|
WORD id;
|
|
|
|
WORD handle;
|
|
|
|
WORD usage;
|
|
|
|
} NE_NAMEINFO;
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
WORD type_id;
|
|
|
|
WORD count;
|
|
|
|
DWORD resloader;
|
|
|
|
} NE_TYPEINFO;
|
|
|
|
|
2003-12-29 22:50:59 +00:00
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(ver);
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* find_entry_by_id
|
|
|
|
*
|
|
|
|
* Find an entry by id in a resource directory
|
|
|
|
* Copied from loader/pe_resource.c
|
|
|
|
*/
|
|
|
|
static const IMAGE_RESOURCE_DIRECTORY *find_entry_by_id( const IMAGE_RESOURCE_DIRECTORY *dir,
|
|
|
|
WORD id, const void *root )
|
|
|
|
{
|
|
|
|
const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
|
|
|
|
int min, max, pos;
|
|
|
|
|
|
|
|
entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
|
|
|
|
min = dir->NumberOfNamedEntries;
|
|
|
|
max = min + dir->NumberOfIdEntries - 1;
|
|
|
|
while (min <= max)
|
|
|
|
{
|
|
|
|
pos = (min + max) / 2;
|
2010-07-31 22:20:34 +00:00
|
|
|
if (entry[pos].u1.Id == id)
|
|
|
|
return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry[pos].u2.s3.OffsetToDirectory);
|
|
|
|
if (entry[pos].u1.Id > id) max = pos - 1;
|
2006-05-10 08:19:03 +00:00
|
|
|
else min = pos + 1;
|
2003-12-29 22:50:59 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**********************************************************************
|
|
|
|
* find_entry_default
|
|
|
|
*
|
|
|
|
* Find a default entry in a resource directory
|
|
|
|
* Copied from loader/pe_resource.c
|
|
|
|
*/
|
|
|
|
static const IMAGE_RESOURCE_DIRECTORY *find_entry_default( const IMAGE_RESOURCE_DIRECTORY *dir,
|
|
|
|
const void *root )
|
|
|
|
{
|
|
|
|
const IMAGE_RESOURCE_DIRECTORY_ENTRY *entry;
|
|
|
|
|
|
|
|
entry = (const IMAGE_RESOURCE_DIRECTORY_ENTRY *)(dir + 1);
|
2010-07-31 22:20:34 +00:00
|
|
|
return (const IMAGE_RESOURCE_DIRECTORY *)((const char *)root + entry->u2.s3.OffsetToDirectory);
|
2003-12-29 22:50:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* read_xx_header [internal]
|
|
|
|
*/
|
|
|
|
static int read_xx_header( HFILE lzfd )
|
|
|
|
{
|
|
|
|
IMAGE_DOS_HEADER mzh;
|
|
|
|
char magic[3];
|
|
|
|
|
|
|
|
LZSeek( lzfd, 0, SEEK_SET );
|
|
|
|
if ( sizeof(mzh) != LZRead( lzfd, (LPSTR)&mzh, sizeof(mzh) ) )
|
|
|
|
return 0;
|
|
|
|
if ( mzh.e_magic != IMAGE_DOS_SIGNATURE )
|
2010-03-21 21:02:06 +00:00
|
|
|
{
|
|
|
|
if (!memcmp( &mzh, "\177ELF", 4 )) return 1; /* ELF */
|
|
|
|
if (*(UINT *)&mzh == 0xfeedface || *(UINT *)&mzh == 0xcefaedfe) return 1; /* Mach-O */
|
2003-12-29 22:50:59 +00:00
|
|
|
return 0;
|
2010-03-21 21:02:06 +00:00
|
|
|
}
|
2003-12-29 22:50:59 +00:00
|
|
|
|
|
|
|
LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
|
|
|
|
if ( 2 != LZRead( lzfd, magic, 2 ) )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
LZSeek( lzfd, mzh.e_lfanew, SEEK_SET );
|
|
|
|
|
|
|
|
if ( magic[0] == 'N' && magic[1] == 'E' )
|
|
|
|
return IMAGE_OS2_SIGNATURE;
|
|
|
|
if ( magic[0] == 'P' && magic[1] == 'E' )
|
|
|
|
return IMAGE_NT_SIGNATURE;
|
|
|
|
|
|
|
|
magic[2] = '\0';
|
|
|
|
WARN("Can't handle %s files.\n", magic );
|
|
|
|
return 0;
|
|
|
|
}
|
2006-05-10 08:19:03 +00:00
|
|
|
|
2003-12-29 22:50:59 +00:00
|
|
|
/***********************************************************************
|
2009-06-07 11:12:48 +00:00
|
|
|
* find_ne_resource [internal]
|
2003-12-29 22:50:59 +00:00
|
|
|
*/
|
2010-03-21 21:02:06 +00:00
|
|
|
static BOOL find_ne_resource( HFILE lzfd, DWORD *resLen, DWORD *resOff )
|
2003-12-29 22:50:59 +00:00
|
|
|
{
|
2010-03-21 21:02:06 +00:00
|
|
|
const WORD typeid = VS_FILE_INFO | 0x8000;
|
|
|
|
const WORD resid = VS_VERSION_INFO | 0x8000;
|
2003-12-29 22:50:59 +00:00
|
|
|
IMAGE_OS2_HEADER nehd;
|
|
|
|
NE_TYPEINFO *typeInfo;
|
|
|
|
NE_NAMEINFO *nameInfo;
|
|
|
|
DWORD nehdoffset;
|
|
|
|
LPBYTE resTab;
|
|
|
|
DWORD resTabSize;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
/* Read in NE header */
|
|
|
|
nehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
|
|
|
|
if ( sizeof(nehd) != LZRead( lzfd, (LPSTR)&nehd, sizeof(nehd) ) ) return 0;
|
|
|
|
|
|
|
|
resTabSize = nehd.ne_restab - nehd.ne_rsrctab;
|
|
|
|
if ( !resTabSize )
|
|
|
|
{
|
|
|
|
TRACE("No resources in NE dll\n" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in resource table */
|
|
|
|
resTab = HeapAlloc( GetProcessHeap(), 0, resTabSize );
|
|
|
|
if ( !resTab ) return FALSE;
|
|
|
|
|
|
|
|
LZSeek( lzfd, nehd.ne_rsrctab + nehdoffset, SEEK_SET );
|
2006-05-10 08:19:03 +00:00
|
|
|
if ( resTabSize != LZRead( lzfd, (char*)resTab, resTabSize ) )
|
2003-12-29 22:50:59 +00:00
|
|
|
{
|
|
|
|
HeapFree( GetProcessHeap(), 0, resTab );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find resource */
|
|
|
|
typeInfo = (NE_TYPEINFO *)(resTab + 2);
|
2010-03-21 21:02:06 +00:00
|
|
|
while (typeInfo->type_id)
|
2003-12-29 22:50:59 +00:00
|
|
|
{
|
2010-03-21 21:02:06 +00:00
|
|
|
if (typeInfo->type_id == typeid) goto found_type;
|
|
|
|
typeInfo = (NE_TYPEINFO *)((char *)(typeInfo + 1) +
|
|
|
|
typeInfo->count * sizeof(NE_NAMEINFO));
|
2003-12-29 22:50:59 +00:00
|
|
|
}
|
2010-03-21 21:02:06 +00:00
|
|
|
TRACE("No typeid entry found\n" );
|
2003-12-29 22:50:59 +00:00
|
|
|
HeapFree( GetProcessHeap(), 0, resTab );
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
found_type:
|
|
|
|
nameInfo = (NE_NAMEINFO *)(typeInfo + 1);
|
|
|
|
|
2010-03-21 21:02:06 +00:00
|
|
|
for (count = typeInfo->count; count > 0; count--, nameInfo++)
|
|
|
|
if (nameInfo->id == resid) goto found_name;
|
|
|
|
|
|
|
|
TRACE("No resid entry found\n" );
|
2003-12-29 22:50:59 +00:00
|
|
|
HeapFree( GetProcessHeap(), 0, resTab );
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
found_name:
|
|
|
|
/* Return resource data */
|
|
|
|
if ( resLen ) *resLen = nameInfo->length << *(WORD *)resTab;
|
|
|
|
if ( resOff ) *resOff = nameInfo->offset << *(WORD *)resTab;
|
|
|
|
|
|
|
|
HeapFree( GetProcessHeap(), 0, resTab );
|
|
|
|
return TRUE;
|
|
|
|
}
|
2006-05-10 08:19:03 +00:00
|
|
|
|
2003-12-29 22:50:59 +00:00
|
|
|
/***********************************************************************
|
2009-06-07 11:12:48 +00:00
|
|
|
* find_pe_resource [internal]
|
2003-12-29 22:50:59 +00:00
|
|
|
*/
|
2010-03-21 21:02:06 +00:00
|
|
|
static BOOL find_pe_resource( HFILE lzfd, DWORD *resLen, DWORD *resOff )
|
2003-12-29 22:50:59 +00:00
|
|
|
{
|
2010-04-20 21:18:54 +00:00
|
|
|
union
|
|
|
|
{
|
|
|
|
IMAGE_NT_HEADERS32 nt32;
|
|
|
|
IMAGE_NT_HEADERS64 nt64;
|
|
|
|
} pehd;
|
2003-12-29 22:50:59 +00:00
|
|
|
DWORD pehdoffset;
|
|
|
|
PIMAGE_DATA_DIRECTORY resDataDir;
|
|
|
|
PIMAGE_SECTION_HEADER sections;
|
|
|
|
LPBYTE resSection;
|
|
|
|
DWORD resSectionSize;
|
|
|
|
const void *resDir;
|
|
|
|
const IMAGE_RESOURCE_DIRECTORY *resPtr;
|
|
|
|
const IMAGE_RESOURCE_DATA_ENTRY *resData;
|
2010-04-20 21:18:54 +00:00
|
|
|
int i, len, nSections;
|
2003-12-29 22:50:59 +00:00
|
|
|
BOOL ret = FALSE;
|
|
|
|
|
|
|
|
/* Read in PE header */
|
|
|
|
pehdoffset = LZSeek( lzfd, 0, SEEK_CUR );
|
2010-04-20 21:18:54 +00:00
|
|
|
len = LZRead( lzfd, (LPSTR)&pehd, sizeof(pehd) );
|
|
|
|
if (len < sizeof(pehd.nt32.FileHeader)) return 0;
|
|
|
|
if (len < sizeof(pehd)) memset( (char *)&pehd + len, 0, sizeof(pehd) - len );
|
|
|
|
|
|
|
|
switch (pehd.nt32.OptionalHeader.Magic)
|
|
|
|
{
|
|
|
|
case IMAGE_NT_OPTIONAL_HDR32_MAGIC:
|
|
|
|
resDataDir = pehd.nt32.OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
|
|
|
|
break;
|
|
|
|
case IMAGE_NT_OPTIONAL_HDR64_MAGIC:
|
|
|
|
resDataDir = pehd.nt64.OptionalHeader.DataDirectory + IMAGE_DIRECTORY_ENTRY_RESOURCE;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
2003-12-29 22:50:59 +00:00
|
|
|
|
|
|
|
if ( !resDataDir->Size )
|
|
|
|
{
|
|
|
|
TRACE("No resources in PE dll\n" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in section table */
|
2010-04-20 21:18:54 +00:00
|
|
|
nSections = pehd.nt32.FileHeader.NumberOfSections;
|
2003-12-29 22:50:59 +00:00
|
|
|
sections = HeapAlloc( GetProcessHeap(), 0,
|
|
|
|
nSections * sizeof(IMAGE_SECTION_HEADER) );
|
|
|
|
if ( !sections ) return FALSE;
|
|
|
|
|
2010-04-20 21:18:54 +00:00
|
|
|
len = FIELD_OFFSET( IMAGE_NT_HEADERS32, OptionalHeader ) + pehd.nt32.FileHeader.SizeOfOptionalHeader;
|
|
|
|
LZSeek( lzfd, pehdoffset + len, SEEK_SET );
|
2003-12-29 22:50:59 +00:00
|
|
|
|
|
|
|
if ( nSections * sizeof(IMAGE_SECTION_HEADER) !=
|
|
|
|
LZRead( lzfd, (LPSTR)sections, nSections * sizeof(IMAGE_SECTION_HEADER) ) )
|
|
|
|
{
|
|
|
|
HeapFree( GetProcessHeap(), 0, sections );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find resource section */
|
|
|
|
for ( i = 0; i < nSections; i++ )
|
|
|
|
if ( resDataDir->VirtualAddress >= sections[i].VirtualAddress
|
|
|
|
&& resDataDir->VirtualAddress < sections[i].VirtualAddress +
|
|
|
|
sections[i].SizeOfRawData )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ( i == nSections )
|
|
|
|
{
|
|
|
|
HeapFree( GetProcessHeap(), 0, sections );
|
|
|
|
TRACE("Couldn't find resource section\n" );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Read in resource section */
|
|
|
|
resSectionSize = sections[i].SizeOfRawData;
|
|
|
|
resSection = HeapAlloc( GetProcessHeap(), 0, resSectionSize );
|
|
|
|
if ( !resSection )
|
|
|
|
{
|
|
|
|
HeapFree( GetProcessHeap(), 0, sections );
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LZSeek( lzfd, sections[i].PointerToRawData, SEEK_SET );
|
2006-05-10 08:19:03 +00:00
|
|
|
if ( resSectionSize != LZRead( lzfd, (char*)resSection, resSectionSize ) ) goto done;
|
2003-12-29 22:50:59 +00:00
|
|
|
|
|
|
|
/* Find resource */
|
|
|
|
resDir = resSection + (resDataDir->VirtualAddress - sections[i].VirtualAddress);
|
|
|
|
|
2009-06-07 11:12:48 +00:00
|
|
|
resPtr = resDir;
|
2010-03-21 21:02:06 +00:00
|
|
|
resPtr = find_entry_by_id( resPtr, VS_FILE_INFO, resDir );
|
2003-12-29 22:50:59 +00:00
|
|
|
if ( !resPtr )
|
|
|
|
{
|
2010-03-21 21:02:06 +00:00
|
|
|
TRACE("No typeid entry found\n" );
|
2003-12-29 22:50:59 +00:00
|
|
|
goto done;
|
|
|
|
}
|
2010-03-21 21:02:06 +00:00
|
|
|
resPtr = find_entry_by_id( resPtr, VS_VERSION_INFO, resDir );
|
2003-12-29 22:50:59 +00:00
|
|
|
if ( !resPtr )
|
|
|
|
{
|
2010-03-21 21:02:06 +00:00
|
|
|
TRACE("No resid entry found\n" );
|
2003-12-29 22:50:59 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
resPtr = find_entry_default( resPtr, resDir );
|
|
|
|
if ( !resPtr )
|
|
|
|
{
|
2010-03-21 21:02:06 +00:00
|
|
|
TRACE("No default language entry found\n" );
|
2003-12-29 22:50:59 +00:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Find resource data section */
|
2006-05-10 08:19:03 +00:00
|
|
|
resData = (const IMAGE_RESOURCE_DATA_ENTRY*)resPtr;
|
2003-12-29 22:50:59 +00:00
|
|
|
for ( i = 0; i < nSections; i++ )
|
|
|
|
if ( resData->OffsetToData >= sections[i].VirtualAddress
|
|
|
|
&& resData->OffsetToData < sections[i].VirtualAddress +
|
|
|
|
sections[i].SizeOfRawData )
|
|
|
|
break;
|
|
|
|
|
|
|
|
if ( i == nSections )
|
|
|
|
{
|
|
|
|
TRACE("Couldn't find resource data section\n" );
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return resource data */
|
|
|
|
if ( resLen ) *resLen = resData->Size;
|
|
|
|
if ( resOff ) *resOff = resData->OffsetToData - sections[i].VirtualAddress
|
|
|
|
+ sections[i].PointerToRawData;
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
done:
|
|
|
|
HeapFree( GetProcessHeap(), 0, resSection );
|
|
|
|
HeapFree( GetProcessHeap(), 0, sections );
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-21 21:02:06 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* find_version_resource [internal]
|
2003-12-29 22:50:59 +00:00
|
|
|
*/
|
2010-03-21 21:02:06 +00:00
|
|
|
DWORD find_version_resource( HFILE lzfd, DWORD *reslen, DWORD *offset )
|
2003-12-29 22:50:59 +00:00
|
|
|
{
|
2010-03-21 21:02:06 +00:00
|
|
|
DWORD magic = read_xx_header( lzfd );
|
2003-12-29 22:50:59 +00:00
|
|
|
|
2010-03-21 21:02:06 +00:00
|
|
|
switch (magic)
|
2003-12-29 22:50:59 +00:00
|
|
|
{
|
|
|
|
case IMAGE_OS2_SIGNATURE:
|
2010-03-21 21:02:06 +00:00
|
|
|
if (!find_ne_resource( lzfd, reslen, offset )) magic = 0;
|
2003-12-29 22:50:59 +00:00
|
|
|
break;
|
|
|
|
case IMAGE_NT_SIGNATURE:
|
2010-03-21 21:02:06 +00:00
|
|
|
if (!find_pe_resource( lzfd, reslen, offset )) magic = 0;
|
2003-12-29 22:50:59 +00:00
|
|
|
break;
|
|
|
|
}
|
2010-03-21 21:02:06 +00:00
|
|
|
return magic;
|
2003-12-29 22:50:59 +00:00
|
|
|
}
|