946 lines
28 KiB
C
946 lines
28 KiB
C
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <windows.h>
|
||
|
|
||
|
#include "windefs.h"
|
||
|
#include "restok.h"
|
||
|
#include "exentres.h"
|
||
|
#include "resread.h"
|
||
|
#include "checksum.h"
|
||
|
|
||
|
#define SAME 0 //... Used in string compares
|
||
|
#define MAXLEVELS 3 //... Max # of levels in resource directory
|
||
|
|
||
|
typedef struct tagResSectData {
|
||
|
ULONG ulVirtualAddress; //... Virtual address of section .rsrc
|
||
|
ULONG ulSizeOfResources; //... Size of resources in section .rsrc
|
||
|
ULONG ulVirtualSize; //... Virtual Size of resources in .rsrc
|
||
|
ULONG ulVirtualAddressX; //... Virtual address of section .rsrc1
|
||
|
ULONG ulSizeOfResourcesX; //... Size of resources in section .rsrc1
|
||
|
ULONG ulVirtualSizeX; //... Virtual Size of resources in .rsrc1
|
||
|
} RESSECTDATA, *PRESSECTDATA;
|
||
|
|
||
|
WORD gwFilter = 0;
|
||
|
|
||
|
int InsertResourcesInExe( FILE *, HANDLE);
|
||
|
LONG GetFileResources( FILE *, FILE *, ULONG);
|
||
|
ULONG MoveFilePos( FILE *, ULONG);
|
||
|
ULONG MyWrite( FILE *, PUCHAR, ULONG);
|
||
|
ULONG MyRead( FILE *, PUCHAR, ULONG);
|
||
|
WCHAR *GetDirNameU( WCHAR *, PIMAGE_RESOURCE_DIR_STRING_U);
|
||
|
ULONG ReadResources( FILE *, ULONG, ULONG, PUCHAR);
|
||
|
DWORD AddToLangIDList( DWORD);
|
||
|
|
||
|
ULONG ProcessDirectory( FILE *,
|
||
|
USHORT,
|
||
|
PRESSECTDATA,
|
||
|
PIMAGE_RESOURCE_DIRECTORY,
|
||
|
PIMAGE_RESOURCE_DIRECTORY);
|
||
|
|
||
|
ULONG ProcessDirEntry( FILE *,
|
||
|
USHORT,
|
||
|
PRESSECTDATA,
|
||
|
PIMAGE_RESOURCE_DIRECTORY,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY);
|
||
|
|
||
|
ULONG ProcessSubDir( FILE *,
|
||
|
USHORT,
|
||
|
PRESSECTDATA,
|
||
|
PIMAGE_RESOURCE_DIRECTORY,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY);
|
||
|
|
||
|
ULONG ProcessNamedEntry( FILE *,
|
||
|
PRESSECTDATA,
|
||
|
PIMAGE_RESOURCE_DIRECTORY,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY);
|
||
|
|
||
|
ULONG ProcessIdEntry( FILE *,
|
||
|
PRESSECTDATA,
|
||
|
PIMAGE_RESOURCE_DIRECTORY,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY);
|
||
|
|
||
|
ULONG ProcessDataEntry( FILE *,
|
||
|
PRESSECTDATA,
|
||
|
PIMAGE_RESOURCE_DIRECTORY,
|
||
|
PIMAGE_RESOURCE_DATA_ENTRY);
|
||
|
|
||
|
int FindNewExeHdr( FILE *, ULONG *);
|
||
|
|
||
|
IMAGE_DOS_HEADER ExeDosHdr;//... Exe's DOS header
|
||
|
IMAGE_NT_HEADERS NTHdrs; //... Exe's NT headers
|
||
|
|
||
|
struct tagLevelData //... Holds ID or name for each directory level
|
||
|
{
|
||
|
//... level [0] is for resource type
|
||
|
ULONG dwID; //... level [1] is for resource name
|
||
|
WCHAR wszName[128]; //... level [2] is for resource language
|
||
|
}
|
||
|
LevelData[ MAXLEVELS] = { 0L, TEXT(""), 0L, TEXT(""), 0L, TEXT("")};
|
||
|
|
||
|
BOOL fGetResLangIDs = FALSE;
|
||
|
|
||
|
extern BOOL fInThirdPartyEditer;//.. Are we in a 3rd-party resource editor?
|
||
|
|
||
|
extern MSTRDATA gMstr; //... Data from Master Project file (MPJ)
|
||
|
extern PROJDATA gProj; //... Data from Language Project file (PRJ)
|
||
|
extern UCHAR szDHW[];
|
||
|
|
||
|
|
||
|
PLANGLIST pLangIDList = NULL;
|
||
|
|
||
|
|
||
|
//..........................................................................
|
||
|
|
||
|
void FreeLangIDList( void)
|
||
|
{
|
||
|
PLANGLIST pID = NULL;
|
||
|
|
||
|
while ( pLangIDList ) {
|
||
|
pID = pLangIDList->pNext;
|
||
|
RLFREE( pLangIDList);
|
||
|
pLangIDList = pID;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//..........................................................................
|
||
|
|
||
|
ULONG GetListOfResLangIDs( char *szExeName)
|
||
|
{
|
||
|
ULONG ulRC = SUCCESS;
|
||
|
ULONG ulOffset = 0;
|
||
|
static RESHEADER ResHeader; // Structure contain Resource Header info.
|
||
|
|
||
|
|
||
|
if ( IsExe( szExeName) ) { //.. open the original exe file
|
||
|
FILE *fpExe = FOPEN( szExeName, "rb");
|
||
|
|
||
|
if ( fpExe != NULL ) {
|
||
|
//... Get list of languages in exe file
|
||
|
|
||
|
ulRC = (ULONG)FindNewExeHdr( fpExe, &ulOffset);
|
||
|
|
||
|
if ( ulRC == SUCCESS ) {
|
||
|
fGetResLangIDs = TRUE;
|
||
|
|
||
|
ulRC = (ULONG)GetFileResources( fpExe, NULL, ulOffset);
|
||
|
|
||
|
fGetResLangIDs = FALSE;
|
||
|
}
|
||
|
FCLOSE( fpExe);
|
||
|
} else {
|
||
|
ulRC = ERROR_OPEN_FAILED;
|
||
|
}
|
||
|
} else if ( IsWin32Res( szExeName) ) {
|
||
|
FILE *fpRes = FOPEN( szExeName, "rb");
|
||
|
|
||
|
if ( fpRes != NULL ) {
|
||
|
LONG lEndOffset = 0L;
|
||
|
|
||
|
|
||
|
//... How large is the res file?
|
||
|
fseek( fpRes, 0L, SEEK_END);
|
||
|
lEndOffset = ftell( fpRes);
|
||
|
|
||
|
rewind( fpRes);
|
||
|
//... Get list of languages in .RES file
|
||
|
|
||
|
while ( ulRC == SUCCESS && ! feof( fpRes) ) {
|
||
|
LONG lCurrOffset = 0L;
|
||
|
|
||
|
|
||
|
lCurrOffset = (LONG)ftell( fpRes);
|
||
|
|
||
|
if ( (lCurrOffset + (LONG)sizeof( RESHEADER)) >= lEndOffset ) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( GetResHeader( fpRes, &ResHeader, NULL) == -1 ) {
|
||
|
ulRC = 1L;
|
||
|
break;
|
||
|
}
|
||
|
//... Is this the dummy, res32-identifying, res?
|
||
|
|
||
|
if ( ResHeader.lSize == 0L ) {
|
||
|
continue;
|
||
|
}
|
||
|
ulRC = AddToLangIDList( (DWORD)ResHeader.wLanguageId);
|
||
|
|
||
|
SkipBytes( fpRes, (DWORD *)&ResHeader.lSize);
|
||
|
ClearResHeader( ResHeader);
|
||
|
|
||
|
DWordUpFilePointer( fpRes, MYREAD, ftell( fpRes), NULL);
|
||
|
|
||
|
} // END while ( ! feof( InResFile)
|
||
|
FCLOSE( fpRes);
|
||
|
} else {
|
||
|
ulRC = ERROR_OPEN_FAILED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( ulRC != SUCCESS ) {
|
||
|
FreeLangIDList();
|
||
|
}
|
||
|
return ( ulRC);
|
||
|
}
|
||
|
|
||
|
//..........................................................................
|
||
|
|
||
|
int ExtractResFromExe32A(
|
||
|
|
||
|
char *szExeName,
|
||
|
char *szResName,
|
||
|
WORD wFilter)
|
||
|
{
|
||
|
FILE *fpExe = NULL; //... Handle of input .EXE file
|
||
|
FILE *fpRes = NULL; //... Handle of output .RES file
|
||
|
ULONG ulRC = 0;
|
||
|
ULONG ulOffset = 0;
|
||
|
int nRC = SUCCESS;
|
||
|
|
||
|
|
||
|
gwFilter = wFilter;
|
||
|
|
||
|
//.. open the original exe file
|
||
|
|
||
|
fpExe = FOPEN( szExeName, "rb");
|
||
|
|
||
|
if ( fpExe == NULL ) {
|
||
|
return ( ERROR_OPEN_FAILED);
|
||
|
}
|
||
|
nRC = FindNewExeHdr( fpExe, &ulOffset);
|
||
|
|
||
|
if ( nRC != SUCCESS ) {
|
||
|
FCLOSE( fpExe);
|
||
|
return ( nRC);
|
||
|
}
|
||
|
fpRes = FOPEN( (CHAR *)szResName, "wb");
|
||
|
|
||
|
if ( fpRes != NULL ) {
|
||
|
//... First, write the dummy 32bit identifier
|
||
|
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
PutByte( fpRes, 0x20, NULL);
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
PutByte( fpRes, 0x00, NULL);
|
||
|
|
||
|
PutWord( fpRes, 0xffff, NULL);
|
||
|
PutWord( fpRes, 0x00, NULL);
|
||
|
PutWord( fpRes, 0xffff, NULL);
|
||
|
PutWord( fpRes, 0x00, NULL);
|
||
|
|
||
|
PutdWord( fpRes, 0L, NULL);
|
||
|
PutdWord( fpRes, 0L, NULL);
|
||
|
|
||
|
PutdWord( fpRes, 0L, NULL);
|
||
|
PutdWord( fpRes, 0L, NULL);
|
||
|
|
||
|
ulRC = (ULONG)GetFileResources( fpExe, fpRes, ulOffset);
|
||
|
|
||
|
FCLOSE( fpRes);
|
||
|
} else {
|
||
|
ulRC = GetLastError();
|
||
|
}
|
||
|
FCLOSE( fpExe);
|
||
|
return ( ulRC);
|
||
|
}
|
||
|
|
||
|
//..........................................................................
|
||
|
|
||
|
int BuildExeFromRes32A(
|
||
|
|
||
|
char * szOutExe, //... Output EXE file's name
|
||
|
char * szRes, //... File of replacement resources
|
||
|
char * szInExe ) //... Intput EXE file's name
|
||
|
{
|
||
|
HANDLE hExeFile = NULL;
|
||
|
FILE *fpRes = NULL;
|
||
|
DWORD dwRC = 0;
|
||
|
WORD wRC = 0;
|
||
|
|
||
|
|
||
|
//... Copy Input exe to out put exe
|
||
|
|
||
|
if ( CopyFileA( szInExe, szOutExe, FALSE) == FALSE ) {
|
||
|
QuitA( IDS_COPYFILE_FAILED, szInExe, szOutExe);
|
||
|
}
|
||
|
|
||
|
if ( (fpRes = FOPEN( szRes, "rb")) == NULL ) {
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
SetLastError(0);
|
||
|
|
||
|
//if Source file was set attributes READ-ONLY, CopyFile sets temp file also.
|
||
|
//And BeginUpdateResourceA returns ERROR.
|
||
|
|
||
|
SetFileAttributesA(szOutExe, FILE_ATTRIBUTE_NORMAL);
|
||
|
|
||
|
hExeFile = BeginUpdateResourceA( szOutExe, TRUE);
|
||
|
|
||
|
dwRC = GetLastError();
|
||
|
|
||
|
if ( ! hExeFile ) {
|
||
|
FCLOSE( fpRes);
|
||
|
return ( -3);
|
||
|
}
|
||
|
|
||
|
wRC = (WORD)InsertResourcesInExe( fpRes, hExeFile);
|
||
|
|
||
|
FCLOSE( fpRes);
|
||
|
|
||
|
if ( wRC != 1 ) {
|
||
|
return ( wRC);
|
||
|
}
|
||
|
|
||
|
SetLastError(0); // needed only to see if EndUpdateResource
|
||
|
// sets last error value.
|
||
|
|
||
|
dwRC = EndUpdateResource( hExeFile, FALSE);
|
||
|
|
||
|
if ( dwRC == FALSE ) {
|
||
|
return ( -4);
|
||
|
}
|
||
|
MapFileAndFixCheckSumA( szOutExe); //... This func always calls QuitT or returns 0
|
||
|
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
//..........................................................................
|
||
|
|
||
|
int FindNewExeHdr( FILE *fpExe, ULONG *ulOffset)
|
||
|
{
|
||
|
ULONG ulRC = 0;
|
||
|
|
||
|
//... read the old format EXE header
|
||
|
|
||
|
ulRC = MyRead( fpExe, (void *)&ExeDosHdr, sizeof( ExeDosHdr));
|
||
|
|
||
|
if ( ulRC != 0L && ulRC != sizeof( ExeDosHdr) ) {
|
||
|
return ( ERROR_READ_FAULT);
|
||
|
}
|
||
|
|
||
|
//... make sure its really an EXE file
|
||
|
|
||
|
if ( ExeDosHdr.e_magic != IMAGE_DOS_SIGNATURE ) {
|
||
|
return ( ERROR_INVALID_EXE_SIGNATURE);
|
||
|
}
|
||
|
|
||
|
//... make sure theres a new EXE header
|
||
|
//... floating around somewhere
|
||
|
|
||
|
if ( ! (*ulOffset = ExeDosHdr.e_lfanew) ) {
|
||
|
return ( ERROR_BAD_EXE_FORMAT);
|
||
|
}
|
||
|
return ( SUCCESS);
|
||
|
}
|
||
|
|
||
|
//..........................................................................
|
||
|
|
||
|
int InsertResourcesInExe(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
HANDLE hExeFile )
|
||
|
{
|
||
|
PVOID pResData = NULL;
|
||
|
LONG lEndOffset = 0L;
|
||
|
BOOL bUpdRC = FALSE;
|
||
|
LANGID wLangID = 0;
|
||
|
int nResCnt = 0;
|
||
|
int nResOut = 0;
|
||
|
static RESHEADER ResHeader;
|
||
|
|
||
|
//... How big is the .RES file?
|
||
|
|
||
|
fseek( fpRes, 0L, SEEK_END);
|
||
|
lEndOffset = ftell( fpRes);
|
||
|
|
||
|
rewind( fpRes);
|
||
|
|
||
|
//... Update all resources, found in the .RES,
|
||
|
//... to the .EXE
|
||
|
while ( ! feof( fpRes) ) {
|
||
|
DWordUpFilePointer( fpRes, MYREAD, ftell( fpRes), NULL);
|
||
|
RLFREE( pResData);
|
||
|
|
||
|
if ( ftell( fpRes) >= lEndOffset ) {
|
||
|
return (1);
|
||
|
}
|
||
|
ZeroMemory( &ResHeader, sizeof( ResHeader));
|
||
|
|
||
|
// Read in the resource header
|
||
|
|
||
|
if ( ( GetResHeader( fpRes, &ResHeader, (DWORD *) NULL) == -1 ) ) {
|
||
|
return ( -1);
|
||
|
}
|
||
|
|
||
|
if ( ResHeader.lSize > 0L ) {
|
||
|
wLangID = ResHeader.wLanguageId;
|
||
|
|
||
|
// Allocate Memory to hold resource data
|
||
|
|
||
|
pResData = (PVOID)FALLOC( ResHeader.lSize);
|
||
|
|
||
|
// Read it into the buffer
|
||
|
|
||
|
if ( ResReadBytes( fpRes,
|
||
|
pResData,
|
||
|
(size_t)ResHeader.lSize,
|
||
|
NULL ) == FALSE ) {
|
||
|
RLFREE( pResData);
|
||
|
return (-1);
|
||
|
}
|
||
|
|
||
|
nResCnt++; // Increment # resources read
|
||
|
|
||
|
DWordUpFilePointer( fpRes, MYREAD, ftell( fpRes), NULL);
|
||
|
} else {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// now write the data
|
||
|
|
||
|
if ( ResHeader.bTypeFlag == IDFLAG ) {
|
||
|
if ( ResHeader.bNameFlag == IDFLAG ) {
|
||
|
SetLastError(0);
|
||
|
|
||
|
bUpdRC = UpdateResource( hExeFile,
|
||
|
MAKEINTRESOURCE( ResHeader.wTypeID),
|
||
|
MAKEINTRESOURCE( ResHeader.wNameID),
|
||
|
wLangID,
|
||
|
pResData,
|
||
|
ResHeader.lSize);
|
||
|
|
||
|
if ( ! bUpdRC ) {
|
||
|
RLFREE( pResData);
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
SetLastError(0);
|
||
|
|
||
|
bUpdRC = UpdateResource( hExeFile,
|
||
|
MAKEINTRESOURCE( ResHeader.wTypeID),
|
||
|
ResHeader.pszName,
|
||
|
wLangID,
|
||
|
pResData,
|
||
|
ResHeader.lSize);
|
||
|
|
||
|
if ( ! bUpdRC ) {
|
||
|
RLFREE( pResData);
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
if (ResHeader.bNameFlag == IDFLAG) {
|
||
|
SetLastError(0);//BUGUG
|
||
|
|
||
|
bUpdRC = UpdateResource( hExeFile,
|
||
|
ResHeader.pszType,
|
||
|
MAKEINTRESOURCE( ResHeader.wNameID),
|
||
|
wLangID,
|
||
|
pResData,
|
||
|
ResHeader.lSize);
|
||
|
|
||
|
if ( ! bUpdRC ) {
|
||
|
RLFREE( pResData);
|
||
|
return (-1);
|
||
|
}
|
||
|
} else {
|
||
|
SetLastError(0);
|
||
|
|
||
|
bUpdRC = UpdateResource( hExeFile,
|
||
|
ResHeader.pszType,
|
||
|
ResHeader.pszName,
|
||
|
wLangID,
|
||
|
pResData,
|
||
|
ResHeader.lSize);
|
||
|
|
||
|
if ( ! bUpdRC ) {
|
||
|
RLFREE( pResData);
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
ClearResHeader( ResHeader);
|
||
|
RLFREE( pResData);
|
||
|
} //... END WHILE ( ! feof...
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
//............................................................
|
||
|
|
||
|
LONG GetFileResources(
|
||
|
|
||
|
FILE *fpExe,
|
||
|
FILE *fpRes,
|
||
|
ULONG ulHdrOffset)
|
||
|
{
|
||
|
ULONG ulOffsetToResources;
|
||
|
ULONG ulOffsetToResourcesX;
|
||
|
ULONG ulRead;
|
||
|
ULONG ulToRead;
|
||
|
ULONG ulRC = SUCCESS;
|
||
|
PUCHAR pResources = NULL; //... Ptr to start of resource directory table
|
||
|
|
||
|
PIMAGE_SECTION_HEADER pSectTbl = NULL;
|
||
|
PIMAGE_SECTION_HEADER pSectTblLast = NULL;
|
||
|
PIMAGE_SECTION_HEADER pSect = NULL;
|
||
|
PIMAGE_SECTION_HEADER pResSect = NULL;
|
||
|
PIMAGE_SECTION_HEADER pResSectX = NULL;
|
||
|
static RESSECTDATA ResSectData;
|
||
|
|
||
|
//... Read the NT image headers into memory
|
||
|
|
||
|
ulRC = MoveFilePos( fpExe, ulHdrOffset);
|
||
|
|
||
|
if ( ulRC != 0L ) {
|
||
|
return ( -1L);
|
||
|
}
|
||
|
ulRead = MyRead( fpExe, (PUCHAR)&NTHdrs, sizeof( IMAGE_NT_HEADERS));
|
||
|
|
||
|
if ( ulRead != 0L && ulRead != sizeof( IMAGE_NT_HEADERS) ) {
|
||
|
return ( -1L);
|
||
|
}
|
||
|
//... Check for valid exe
|
||
|
|
||
|
if ( *(PUSHORT)&NTHdrs.Signature != IMAGE_NT_SIGNATURE ) {
|
||
|
return ( ERROR_INVALID_EXE_SIGNATURE);
|
||
|
}
|
||
|
|
||
|
if ((NTHdrs.FileHeader.Characteristics&IMAGE_FILE_EXECUTABLE_IMAGE) == 0 &&
|
||
|
(NTHdrs.FileHeader.Characteristics&IMAGE_FILE_DLL) == 0) {
|
||
|
return ( ERROR_EXE_MARKED_INVALID);
|
||
|
}
|
||
|
//... Where is resource section in file
|
||
|
//... and how big is it?
|
||
|
|
||
|
//... First, read section table
|
||
|
|
||
|
ulToRead = NTHdrs.FileHeader.NumberOfSections
|
||
|
* sizeof( IMAGE_SECTION_HEADER);
|
||
|
pSectTbl = (PIMAGE_SECTION_HEADER)FALLOC( ulToRead);
|
||
|
|
||
|
memset( (PVOID)pSectTbl, 0, ulToRead);
|
||
|
|
||
|
ulHdrOffset += sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) +
|
||
|
NTHdrs.FileHeader.SizeOfOptionalHeader;
|
||
|
MoveFilePos( fpExe, ulHdrOffset);
|
||
|
ulRead = MyRead( fpExe, (PUCHAR)pSectTbl, ulToRead);
|
||
|
|
||
|
if ( ulRead != 0L && ulRead != ulToRead ) {
|
||
|
SetLastError(ERROR_BAD_FORMAT);
|
||
|
RLFREE( pSectTbl);
|
||
|
return ( -1L);
|
||
|
}
|
||
|
pSectTblLast = pSectTbl + NTHdrs.FileHeader.NumberOfSections;
|
||
|
|
||
|
for ( pSect = pSectTbl; pSect < pSectTblLast; ++pSect ) {
|
||
|
if ( lstrcmpA( (CHAR *)pSect->Name, ".rsrc") == SAME && pResSect==NULL ) {
|
||
|
pResSect = pSect;
|
||
|
} else if ( lstrcmpA( (CHAR *)pSect->Name, ".rsrc1") == SAME && pResSectX==NULL ) {
|
||
|
pResSectX = pSect;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( pResSect == NULL ) {
|
||
|
RLFREE( pSectTbl);
|
||
|
QuitA( IDS_NO_RES_SECTION, gMstr.szSrc, NULL);
|
||
|
}
|
||
|
|
||
|
ulOffsetToResources = pResSect->PointerToRawData;
|
||
|
ulOffsetToResourcesX = pResSectX ? pResSectX->PointerToRawData : 0L;
|
||
|
|
||
|
ResSectData.ulVirtualAddress = pResSect->VirtualAddress;
|
||
|
ResSectData.ulSizeOfResources = pResSect->SizeOfRawData;
|
||
|
ResSectData.ulVirtualSize = pResSect->Misc.VirtualSize;
|
||
|
ResSectData.ulVirtualAddressX = pResSectX ? pResSectX->VirtualAddress : 0L;
|
||
|
ResSectData.ulSizeOfResourcesX = pResSectX ? pResSectX->SizeOfRawData : 0L;
|
||
|
ResSectData.ulVirtualSizeX = pResSectX ? pResSectX->Misc.VirtualSize : 0L;
|
||
|
|
||
|
//... Read resource section into memory
|
||
|
|
||
|
pResources = (PUCHAR)FALLOC((ulToRead =
|
||
|
(max(ResSectData.ulVirtualSize, ResSectData.ulSizeOfResources) +
|
||
|
max(ResSectData.ulVirtualSizeX, ResSectData.ulSizeOfResourcesX))));
|
||
|
memset( (PVOID)pResources, 0, ulToRead);
|
||
|
|
||
|
ulRC = ReadResources( fpExe,
|
||
|
ulOffsetToResources,
|
||
|
ResSectData.ulSizeOfResources,
|
||
|
pResources);
|
||
|
|
||
|
if ( ulRC != 0L ) {
|
||
|
RLFREE( pSectTbl);
|
||
|
RLFREE( pResources);
|
||
|
return ( ulRC);
|
||
|
} else if ( ResSectData.ulSizeOfResourcesX > 0L ) {
|
||
|
ulRC = ReadResources( fpExe,
|
||
|
ulOffsetToResourcesX,
|
||
|
ResSectData.ulSizeOfResourcesX,
|
||
|
&pResources[ ResSectData.ulVirtualSize]);
|
||
|
if ( ulRC != 0L ) {
|
||
|
RLFREE( pSectTbl);
|
||
|
RLFREE( pResources);
|
||
|
return ( ulRC);
|
||
|
}
|
||
|
}
|
||
|
//... Now process the resource table
|
||
|
|
||
|
ulRC = ProcessDirectory( fpRes,
|
||
|
0,
|
||
|
&ResSectData,
|
||
|
(PIMAGE_RESOURCE_DIRECTORY)pResources,
|
||
|
(PIMAGE_RESOURCE_DIRECTORY)pResources);
|
||
|
|
||
|
RLFREE( pSectTbl);
|
||
|
RLFREE( pResources);
|
||
|
|
||
|
return ( (LONG)ulRC);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG ProcessDirectory(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
USHORT usLevel,
|
||
|
PRESSECTDATA pResSectData,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResStart,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResDir)
|
||
|
{
|
||
|
ULONG ulRC = SUCCESS;
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirEntry;
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirStart;
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirEnd;
|
||
|
|
||
|
|
||
|
pResDirStart = (PIMAGE_RESOURCE_DIRECTORY_ENTRY)
|
||
|
((PBYTE)pResDir + sizeof( IMAGE_RESOURCE_DIRECTORY));
|
||
|
|
||
|
pResDirEnd = pResDirStart
|
||
|
+ pResDir->NumberOfNamedEntries
|
||
|
+ pResDir->NumberOfIdEntries;
|
||
|
|
||
|
for ( pResDirEntry = pResDirStart, ulRC = 0L;
|
||
|
pResDirEntry < pResDirEnd && ulRC == 0L;
|
||
|
++pResDirEntry ) {
|
||
|
ulRC = ProcessDirEntry( fpRes,
|
||
|
usLevel,
|
||
|
pResSectData,
|
||
|
pResStart,
|
||
|
pResDirEntry);
|
||
|
}
|
||
|
return ( ulRC);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG ProcessDirEntry(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
USHORT usLevel,
|
||
|
PRESSECTDATA pResSectData,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResStart,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirEntry)
|
||
|
{
|
||
|
ULONG ulRC = SUCCESS;
|
||
|
|
||
|
if ( pResDirEntry->Name & IMAGE_RESOURCE_NAME_IS_STRING ) {
|
||
|
GetDirNameU( LevelData[ usLevel].wszName,
|
||
|
(PIMAGE_RESOURCE_DIR_STRING_U)((PBYTE)pResStart
|
||
|
+ (pResDirEntry->Name & (~IMAGE_RESOURCE_NAME_IS_STRING))));
|
||
|
LevelData[ usLevel].dwID = IMAGE_RESOURCE_NAME_IS_STRING;
|
||
|
} else {
|
||
|
LevelData[ usLevel].wszName[0] = TEXT('\0');
|
||
|
LevelData[ usLevel].dwID = pResDirEntry->Name;
|
||
|
}
|
||
|
|
||
|
if ( pResDirEntry->OffsetToData & IMAGE_RESOURCE_DATA_IS_DIRECTORY ) {
|
||
|
ulRC = ProcessSubDir( fpRes,
|
||
|
usLevel,
|
||
|
pResSectData,
|
||
|
pResStart,
|
||
|
pResDirEntry);
|
||
|
} else if ( pResDirEntry->Name & IMAGE_RESOURCE_NAME_IS_STRING ) {
|
||
|
ulRC = ProcessNamedEntry( fpRes, pResSectData, pResStart, pResDirEntry);
|
||
|
} else {
|
||
|
ulRC = ProcessIdEntry( fpRes, pResSectData, pResStart, pResDirEntry);
|
||
|
}
|
||
|
return ( ulRC);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG ProcessSubDir(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
USHORT usLevel,
|
||
|
PRESSECTDATA pResSectData,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResStart,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirEntry)
|
||
|
{
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResDir;
|
||
|
|
||
|
pResDir = (PIMAGE_RESOURCE_DIRECTORY)((PBYTE)pResStart
|
||
|
+ (pResDirEntry->OffsetToData & (~IMAGE_RESOURCE_DATA_IS_DIRECTORY)));
|
||
|
|
||
|
return ( ++usLevel < MAXLEVELS ? ProcessDirectory( fpRes,
|
||
|
usLevel,
|
||
|
pResSectData,
|
||
|
pResStart,
|
||
|
pResDir)
|
||
|
: -1L);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG ProcessIdEntry(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
PRESSECTDATA pResSectData,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResStart,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirEntry)
|
||
|
{
|
||
|
return ( ProcessDataEntry( fpRes,
|
||
|
pResSectData,
|
||
|
pResStart,
|
||
|
(PIMAGE_RESOURCE_DATA_ENTRY)((PBYTE)pResStart
|
||
|
+ pResDirEntry->OffsetToData)));
|
||
|
}
|
||
|
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG ProcessNamedEntry(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
PRESSECTDATA pResSectData,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResStart,
|
||
|
PIMAGE_RESOURCE_DIRECTORY_ENTRY pResDirEntry)
|
||
|
{
|
||
|
return ( ProcessDataEntry( fpRes,
|
||
|
pResSectData,
|
||
|
pResStart,
|
||
|
(PIMAGE_RESOURCE_DATA_ENTRY)((PBYTE)pResStart
|
||
|
+ pResDirEntry->OffsetToData)));
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG ProcessDataEntry(
|
||
|
|
||
|
FILE *fpRes,
|
||
|
PRESSECTDATA pResSectData,
|
||
|
PIMAGE_RESOURCE_DIRECTORY pResStart,
|
||
|
PIMAGE_RESOURCE_DATA_ENTRY pResData)
|
||
|
{
|
||
|
ULONG ulOffset;
|
||
|
ULONG ulCopied;
|
||
|
DWORD dwHdrSize = 0L;
|
||
|
fpos_t HdrSizePos;
|
||
|
|
||
|
|
||
|
if ( fGetResLangIDs ) { //... Are we just looking for LANG IDs?
|
||
|
return ( AddToLangIDList( (WORD)(LevelData[2].dwID)));
|
||
|
}
|
||
|
|
||
|
if ( gwFilter != 0 ) { //... Filtering turned on?
|
||
|
//... Yes, is this a resource we want?
|
||
|
if ( LevelData[0].dwID == IMAGE_RESOURCE_NAME_IS_STRING
|
||
|
|| LevelData[0].dwID != (DWORD)gwFilter ) {
|
||
|
return ( 0L); //... Not a resource we want
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//... Are we in the dialog editor?
|
||
|
if ( fInThirdPartyEditer ) { //... Is the language we want?
|
||
|
if ( LevelData[2].dwID != gMstr.wLanguageID ) {
|
||
|
return ( 0L); //... Not the language we want
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
ulOffset = pResData->OffsetToData - pResSectData->ulVirtualAddress;
|
||
|
|
||
|
if ( ulOffset >= pResSectData->ulVirtualSize ) {
|
||
|
if ( pResSectData->ulVirtualSizeX > 0L ) {
|
||
|
ulOffset = pResData->OffsetToData
|
||
|
+ pResSectData->ulVirtualSize
|
||
|
- pResSectData->ulVirtualAddressX;
|
||
|
|
||
|
if ( ulOffset >= pResSectData->ulVirtualSize
|
||
|
+ pResSectData->ulSizeOfResourcesX ) {
|
||
|
return ( (ULONG)-1L);
|
||
|
}
|
||
|
} else {
|
||
|
return ( (ULONG)-1L);
|
||
|
}
|
||
|
}
|
||
|
//... write out the resource header info
|
||
|
//... First, write the resource's size
|
||
|
|
||
|
PutdWord( fpRes, pResData->Size, &dwHdrSize);
|
||
|
|
||
|
//... Remember where to write real hdr size and
|
||
|
//... write out bogus hdr size, fix up later
|
||
|
|
||
|
fgetpos( fpRes, &HdrSizePos);
|
||
|
PutdWord( fpRes, 0, &dwHdrSize);
|
||
|
|
||
|
//... Write resource type
|
||
|
|
||
|
if ( LevelData[0].dwID == IMAGE_RESOURCE_NAME_IS_STRING ) {
|
||
|
PutString( fpRes, (TCHAR *)LevelData[0].wszName, &dwHdrSize);
|
||
|
} else {
|
||
|
PutWord( fpRes, IDFLAG, &dwHdrSize);
|
||
|
PutWord( fpRes, LOWORD( LevelData[0].dwID), &dwHdrSize);
|
||
|
}
|
||
|
|
||
|
//... Write resource name
|
||
|
//... dbl-null-terminated if string
|
||
|
|
||
|
if ( LevelData[1].dwID == IMAGE_RESOURCE_NAME_IS_STRING ) {
|
||
|
PutString( fpRes, (TCHAR *)LevelData[1].wszName, &dwHdrSize);
|
||
|
} else {
|
||
|
PutWord( fpRes, IDFLAG, &dwHdrSize);
|
||
|
PutWord( fpRes, LOWORD( LevelData[1].dwID), &dwHdrSize);
|
||
|
}
|
||
|
|
||
|
DWordUpFilePointer( fpRes, MYWRITE, ftell( fpRes), &dwHdrSize);
|
||
|
|
||
|
//... More Win32 header stuff
|
||
|
|
||
|
PutdWord( fpRes, 0, &dwHdrSize); //... Data version
|
||
|
PutWord( fpRes, 0x1030, &dwHdrSize); //... MemoryFlags (WORD)
|
||
|
|
||
|
//... language is always a number (WORD)
|
||
|
|
||
|
PutWord( fpRes, LOWORD( LevelData[2].dwID), &dwHdrSize);
|
||
|
|
||
|
//... More Win32 header stuff
|
||
|
|
||
|
PutdWord( fpRes, 0, &dwHdrSize); //... Version
|
||
|
PutdWord( fpRes, 0, &dwHdrSize); //... Characteristics
|
||
|
|
||
|
//... Now, fix up the resource header size
|
||
|
|
||
|
UpdateResSize( fpRes, &HdrSizePos, dwHdrSize);
|
||
|
|
||
|
//... Copy the resource data to the res file
|
||
|
|
||
|
ulCopied = MyWrite( fpRes, (PUCHAR)pResStart + ulOffset, pResData->Size);
|
||
|
|
||
|
if ( ulCopied != 0L && ulCopied != pResData->Size ) {
|
||
|
return ( (ULONG)-1);
|
||
|
}
|
||
|
DWordUpFilePointer( fpRes, MYWRITE, ftell( fpRes), NULL);
|
||
|
return ( 0L);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
/*
|
||
|
* Utility routines
|
||
|
*/
|
||
|
|
||
|
|
||
|
ULONG ReadResources(
|
||
|
|
||
|
FILE *fpExe,
|
||
|
ULONG ulOffsetToResources,
|
||
|
ULONG ulSizeOfResources,
|
||
|
PUCHAR pResources)
|
||
|
{
|
||
|
ULONG ulRC = SUCCESS;
|
||
|
ULONG ulRead;
|
||
|
|
||
|
|
||
|
ulRC = MoveFilePos( fpExe, ulOffsetToResources);
|
||
|
|
||
|
if ( ulRC != 0L ) {
|
||
|
return ( (ULONG)-1L);
|
||
|
}
|
||
|
ulRead = MyRead( fpExe, pResources, ulSizeOfResources);
|
||
|
|
||
|
if ( ulRead != 0L && ulRead != ulSizeOfResources ) {
|
||
|
return ( (ULONG)-1L);
|
||
|
}
|
||
|
return ( 0L);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
WCHAR * GetDirNameU(
|
||
|
|
||
|
WCHAR *pszDest,
|
||
|
PIMAGE_RESOURCE_DIR_STRING_U pDirStr)
|
||
|
{
|
||
|
CopyMemory( pszDest, pDirStr->NameString, MEMSIZE( pDirStr->Length));
|
||
|
pszDest[ pDirStr->Length] = L'\0';
|
||
|
return ( pszDest);
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG MoveFilePos( FILE *fp, ULONG pos)
|
||
|
{
|
||
|
return ( fseek( fp, pos, SEEK_SET));
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG MyWrite( FILE *fp, UCHAR *p, ULONG ulToWrite)
|
||
|
{
|
||
|
size_t cWritten;
|
||
|
|
||
|
|
||
|
|
||
|
cWritten = fwrite( p, 1, (size_t)ulToWrite, fp);
|
||
|
|
||
|
return ( (ULONG)(cWritten == ulToWrite ? 0L : cWritten));
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
ULONG MyRead( FILE *fp, UCHAR*p, ULONG ulRequested )
|
||
|
{
|
||
|
size_t cRead;
|
||
|
|
||
|
|
||
|
cRead = fread( p, 1, (size_t)ulRequested, fp);
|
||
|
|
||
|
return ( (ULONG)(cRead == ulRequested ? 0L : cRead));
|
||
|
}
|
||
|
|
||
|
//......................................................................
|
||
|
|
||
|
DWORD AddToLangIDList( DWORD dwLangID)
|
||
|
{
|
||
|
WORD wLangID = (WORD)dwLangID;
|
||
|
|
||
|
if ( pLangIDList ) {
|
||
|
PLANGLIST pID;
|
||
|
|
||
|
for ( pID = pLangIDList; pID; pID = pID->pNext ) {
|
||
|
if ( pID->wLang == wLangID ) {
|
||
|
break; //... LANGID already in list
|
||
|
} else if ( pID->pNext == NULL ) {
|
||
|
pID->pNext = (PLANGLIST)FALLOC( sizeof( LANGLIST));
|
||
|
pID = pID->pNext;
|
||
|
pID->pNext = NULL;
|
||
|
pID->wLang = wLangID;
|
||
|
//... LANGID now added to list
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
pLangIDList = (PLANGLIST)FALLOC( sizeof( LANGLIST));
|
||
|
pLangIDList->pNext = NULL;
|
||
|
pLangIDList->wLang = wLangID;
|
||
|
}
|
||
|
return ( SUCCESS);
|
||
|
}
|