Support named version resource in VxD files so we can handle MSGame.VxD
git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@6934 212acab6-be3b-0410-9dea-997c60f758d6
This commit is contained in:
parent
a8a53f6696
commit
b4b709769e
3 changed files with 100 additions and 118 deletions
|
@ -18,10 +18,14 @@
|
||||||
#include "BinInterop.h"
|
#include "BinInterop.h"
|
||||||
#include "ResourceEditor.h"
|
#include "ResourceEditor.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include <string.h> // strlen
|
||||||
#include <wchar.h> // _tcstoul
|
#include <wchar.h> // _tcstoul
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#define MKPTR(cast, base, offset) ( (cast) ( ((char*)(base)) + (offset) ) )
|
#define MKPTR(cast, base, offset) ( (cast) ( ((char*)(base)) + (offset) ) )
|
||||||
|
#define LE2HE16 FIX_ENDIAN_INT16 // Little-endian 2 Host-endian
|
||||||
|
#define LE2HE32 FIX_ENDIAN_INT32
|
||||||
|
#define HE2LE16 LE2HE16
|
||||||
const size_t invalid_res_id = ~(size_t)0;
|
const size_t invalid_res_id = ~(size_t)0;
|
||||||
|
|
||||||
FILE* MSTLB_fopen(const TCHAR*filepath, size_t*pResId)
|
FILE* MSTLB_fopen(const TCHAR*filepath, size_t*pResId)
|
||||||
|
@ -379,132 +383,57 @@ static bool GetDLLVersionUsingAPI(const TCHAR *filepath, DWORD &high, DWORD &low
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma pack(push, pre_vxd_ver, 1)
|
#pragma pack(push, 1)
|
||||||
typedef struct _VXD_VERSION_RESOURCE {
|
typedef struct tagMINI_IMAGE_VXD_HEADER {
|
||||||
char cType;
|
WORD e32_magic, endian;
|
||||||
WORD wID;
|
BYTE data[180];
|
||||||
char cName;
|
DWORD e32_winresoff, e32_winreslen;
|
||||||
WORD wOrdinal;
|
WORD e32_devid, e32_ddkver;
|
||||||
WORD wFlags;
|
} MINI_IMAGE_VXD_HEADER, *PMINI_IMAGE_VXD_HEADER;
|
||||||
DWORD dwResSize;
|
#pragma pack(pop)
|
||||||
BYTE bVerData;
|
|
||||||
} VXD_VERSION_RESOURCE, *PVXD_VERSION_RESOURCE;
|
|
||||||
#pragma pack(pop, pre_vxd_ver)
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
static void* CreateReadOnlyFullMappedView(LPCTSTR szFile, DWORD Access, DWORD Share, DWORD Mode)
|
|
||||||
{
|
|
||||||
void *pView = NULL;
|
|
||||||
HANDLE hFile = CreateFile(szFile, Access, Share, NULL, Mode, 0, NULL);
|
|
||||||
if (hFile == INVALID_HANDLE_VALUE) return pView;
|
|
||||||
HANDLE hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
|
||||||
if (hMap != INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
CloseHandle(hFile);
|
|
||||||
if ((pView = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)))
|
|
||||||
{
|
|
||||||
CloseHandle(hMap);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DWORD error = GetLastError();
|
|
||||||
CloseHandle(hMap);
|
|
||||||
SetLastError(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DWORD error = GetLastError();
|
|
||||||
CloseHandle(hFile);
|
|
||||||
SetLastError(error);
|
|
||||||
}
|
|
||||||
return pView;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL GetVxdVersion(LPCTSTR szFile, LPDWORD lpdwLen, LPVOID lpData)
|
|
||||||
{
|
|
||||||
BOOL result = FALSE;
|
|
||||||
DWORD resSize = 0, outSize = *lpdwLen;
|
|
||||||
void *pView = CreateReadOnlyFullMappedView(szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
|
|
||||||
if (!pView) return FALSE;
|
|
||||||
|
|
||||||
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER) pView;
|
|
||||||
if (pDosHdr->e_magic == IMAGE_DOS_SIGNATURE)
|
|
||||||
{
|
|
||||||
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS) ((ULONG_PTR) pView + pDosHdr->e_lfanew);
|
|
||||||
if ((DWORD) pNtHdr->Signature == IMAGE_VXD_SIGNATURE) // Is it a little-endian VXD?
|
|
||||||
{
|
|
||||||
PIMAGE_VXD_HEADER pLEHdr = (PIMAGE_VXD_HEADER) pNtHdr;
|
|
||||||
if (pLEHdr->e32_winreslen != 0)
|
|
||||||
{
|
|
||||||
PVXD_VERSION_RESOURCE pVerRes;
|
|
||||||
pVerRes = (VXD_VERSION_RESOURCE*) ((ULONG_PTR) pView + pLEHdr->e32_winresoff);
|
|
||||||
resSize = pVerRes->dwResSize;
|
|
||||||
if (lpData && outSize >= resSize)
|
|
||||||
{
|
|
||||||
void *pResData = &(pVerRes->bVerData);
|
|
||||||
ZeroMemory(lpData, outSize);
|
|
||||||
CopyMemory(lpData, pResData, resSize);
|
|
||||||
result = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetLastError(ERROR_BAD_FORMAT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SetLastError(ERROR_BAD_FORMAT);
|
|
||||||
|
|
||||||
UnmapViewOfFile(pView);
|
|
||||||
*lpdwLen = resSize;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static DWORD GetVxdVersionInfoSize(LPCTSTR szFile)
|
|
||||||
{
|
|
||||||
DWORD result = 0;
|
|
||||||
if (!GetVxdVersion(szFile, &result, NULL))
|
|
||||||
{
|
|
||||||
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) // Successfully queried the required size?
|
|
||||||
{
|
|
||||||
SetLastError(0);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL GetVxdVersionInfo(LPCTSTR szFile, DWORD dwLen, LPVOID lpData)
|
|
||||||
{
|
|
||||||
return GetVxdVersion(szFile, &dwLen, lpData);
|
|
||||||
}
|
|
||||||
#endif //_WIN32
|
|
||||||
|
|
||||||
static bool GetDLLVersionFromVXD(const TCHAR *filepath, DWORD &high, DWORD &low)
|
static bool GetDLLVersionFromVXD(const TCHAR *filepath, DWORD &high, DWORD &low)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
#ifdef _WIN32
|
FILEVIEW map;
|
||||||
DWORD verSize = GetVxdVersionInfoSize(filepath);
|
char *filedata = create_file_view_readonly(filepath, map);
|
||||||
if (verSize)
|
if (filedata)
|
||||||
{
|
{
|
||||||
void *buf = malloc(verSize);
|
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER) filedata;
|
||||||
if (buf)
|
if ((pDosHdr->e_magic == 0x5A4D) | (pDosHdr->e_magic == 0x4D5A))
|
||||||
{
|
{
|
||||||
UINT valSize;
|
PMINI_IMAGE_VXD_HEADER pVxdHdr = MKPTR(PMINI_IMAGE_VXD_HEADER, pDosHdr, LE2HE32(pDosHdr->e_lfanew));
|
||||||
VS_FIXEDFILEINFO *pvsf;
|
if (pVxdHdr->e32_magic == HE2LE16(0x454C) && pVxdHdr->endian == 0) // Is it a little-endian VXD?
|
||||||
if (GetVxdVersionInfo(filepath, verSize, buf) && VerQueryValue(buf, _T("\\"), (void**) &pvsf, &valSize))
|
|
||||||
{
|
{
|
||||||
high = pvsf->dwFileVersionMS, low = pvsf->dwFileVersionLS;
|
UINT minvsvi16 = 2 + 2 + 16, minvsffi = 52, minressecsize = ((1 + 2) + (1 + 2) + 2 + 4) + minvsvi16 + minvsffi;
|
||||||
found = true;
|
PMINI_IMAGE_VXD_HEADER pLEHdr = pVxdHdr;
|
||||||
|
UINT ressecsize = LE2HE32(pLEHdr->e32_winreslen);
|
||||||
|
if (ressecsize >= minressecsize && pLEHdr->e32_winresoff != 0)
|
||||||
|
{
|
||||||
|
// MSKB201685 just assumes that the first item is the version and we do the same.
|
||||||
|
char *pRes = MKPTR(char*, pDosHdr, LE2HE32(pLEHdr->e32_winresoff));
|
||||||
|
UINT ressize, ofs = 3, succ = *MKPTR(BYTE*, pRes, 0) == 0xff && *MKPTR(WORD*, pRes, 1) == HE2LE16(16); // RT_VERSION
|
||||||
|
if (succ) succ = *MKPTR(BYTE*, pRes, ofs) == 0xff ? (ofs += (1 + 2) + 2) : (ofs += (strlen(MKPTR(char*, pRes, ofs)) + !0) + 2); // Ordinal or string name
|
||||||
|
if (succ) succ = ofs + 4 < ressecsize;
|
||||||
|
if (succ) ressize = LE2HE32(*MKPTR(DWORD*, pRes, ofs)), ofs += 4;
|
||||||
|
if (succ && ressize >= minvsvi16 + minvsffi && ressize < ressecsize)
|
||||||
|
{
|
||||||
|
WORD *pVSVI = MKPTR(WORD*, pRes, ofs); // VS_VERSIONINFO (16-bit/ASCII version)
|
||||||
|
if (LE2HE16(pVSVI[0]) >= minvsvi16 + minvsffi && LE2HE16(pVSVI[1]) >= minvsffi && !memcmp(&pVSVI[2], "VS_VERSION_INFO", 16))
|
||||||
|
{
|
||||||
|
VS_FIXEDFILEINFO *pFFI = MKPTR(VS_FIXEDFILEINFO*, pVSVI, 2 + 2 + 16);
|
||||||
|
if (LE2HE32(pFFI->dwSignature) == 0xFEEF04BD)
|
||||||
|
{
|
||||||
|
high = LE2HE32(pFFI->dwFileVersionMS), low = LE2HE32(pFFI->dwFileVersionLS);
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
|
close_file_view(map);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,38 @@ using namespace std;
|
||||||
extern int g_display_errors;
|
extern int g_display_errors;
|
||||||
extern FILE *g_output, *g_errout;
|
extern FILE *g_output, *g_errout;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static char* CreateMappedFileView(LPCTSTR szFile, DWORD FAccess, DWORD FShare, DWORD FMode, DWORD PProtect, DWORD MAccess)
|
||||||
|
{
|
||||||
|
char *pView = NULL, restoreGLE = false;
|
||||||
|
HANDLE hFile = CreateFile(szFile, FAccess, FShare, NULL, FMode, 0, NULL);
|
||||||
|
if (hFile == INVALID_HANDLE_VALUE) return pView;
|
||||||
|
HANDLE hMap = CreateFileMapping(hFile, NULL, PProtect, 0, 0, NULL);
|
||||||
|
if (hMap != INVALID_HANDLE_VALUE)
|
||||||
|
{
|
||||||
|
CloseHandle(hFile);
|
||||||
|
if ((pView = (char*) MapViewOfFile(hMap, MAccess, 0, 0, 0)))
|
||||||
|
{
|
||||||
|
CloseHandle(hMap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD error = restoreGLE ? GetLastError() : 0;
|
||||||
|
CloseHandle(hMap);
|
||||||
|
if (restoreGLE) SetLastError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DWORD error = restoreGLE ? GetLastError() : 0;
|
||||||
|
CloseHandle(hFile);
|
||||||
|
if (restoreGLE) SetLastError(error);
|
||||||
|
}
|
||||||
|
return pView;
|
||||||
|
}
|
||||||
|
#endif //~ _WIN32
|
||||||
|
|
||||||
|
|
||||||
double my_wtof(const wchar_t *str)
|
double my_wtof(const wchar_t *str)
|
||||||
{
|
{
|
||||||
char buf[100];
|
char buf[100];
|
||||||
|
@ -585,7 +617,7 @@ int my_open(const TCHAR *pathname, int flags)
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endif//!_WIN32
|
#endif //! _WIN32
|
||||||
|
|
||||||
FILE* my_fopen(const TCHAR *path, const char *mode)
|
FILE* my_fopen(const TCHAR *path, const char *mode)
|
||||||
{
|
{
|
||||||
|
@ -669,6 +701,23 @@ BYTE* alloc_and_read_file(const TCHAR *filepath, unsigned long &size)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void close_file_view(FILEVIEW&mmfv)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (mmfv.base) UnmapViewOfFile(mmfv.base);
|
||||||
|
#else
|
||||||
|
// TODO
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
char* create_file_view_readonly(const TCHAR *filepath, FILEVIEW&mmfv)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
return mmfv.base = CreateMappedFileView(filepath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, PAGE_READONLY, FILE_MAP_READ);
|
||||||
|
#else
|
||||||
|
return 0; // TODO
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
tstring get_full_path(const tstring &path) {
|
tstring get_full_path(const tstring &path) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
TCHAR real_path[1024], *fnpart;
|
TCHAR real_path[1024], *fnpart;
|
||||||
|
|
|
@ -268,7 +268,7 @@ int my_open(const TCHAR *pathname, int flags);
|
||||||
|
|
||||||
#define OPEN(a, b) _topen(a, b)
|
#define OPEN(a, b) _topen(a, b)
|
||||||
|
|
||||||
#endif // ~_WIN32
|
#endif //~ _WIN32
|
||||||
|
|
||||||
FILE* my_fopen(const TCHAR *path, const char *mode);
|
FILE* my_fopen(const TCHAR *path, const char *mode);
|
||||||
#define FOPEN(a, b) my_fopen((a), (b))
|
#define FOPEN(a, b) my_fopen((a), (b))
|
||||||
|
@ -279,6 +279,10 @@ const UINT64 invalid_file_size64 = ~ (UINT64) 0;
|
||||||
BYTE* alloc_and_read_file(FILE *f, unsigned long &size);
|
BYTE* alloc_and_read_file(FILE *f, unsigned long &size);
|
||||||
BYTE* alloc_and_read_file(const TCHAR *filepath, unsigned long &size);
|
BYTE* alloc_and_read_file(const TCHAR *filepath, unsigned long &size);
|
||||||
|
|
||||||
|
typedef struct { char*base; size_t internal; } FILEVIEW;
|
||||||
|
void close_file_view(FILEVIEW&mmfv);
|
||||||
|
char* create_file_view_readonly(const TCHAR *filepath, FILEVIEW&mmfv);
|
||||||
|
|
||||||
// round a value up to be a multiple of 512
|
// round a value up to be a multiple of 512
|
||||||
// assumption: T is an int type
|
// assumption: T is an int type
|
||||||
template <class T> inline T align_to_512(const T x) { return (x+511) & ~511; }
|
template <class T> inline T align_to_512(const T x) { return (x+511) & ~511; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue