windows-nt/Source/XPSP1/NT/sdktools/restools/rlt32/bingen/tokgen.cpp
2020-09-26 16:20:57 +08:00

728 lines
29 KiB
C++

//////////////////////////////////////////////////////////////////////////
//
// The format of the token file is:
// [[TYPE ID|RES ID|Item ID|Flags|Status Flags|Item Name]]=
// this is the standar format used by several token file tools in MS.
//
///////////////////////////////////////////////////////////////////////////////
//
// Author: Alessandro Muti
// Date: 12/02/94
//
///////////////////////////////////////////////////////////////////////////////
#include <afx.h>
#include "iodll.h"
#include "main.h"
#include "vktbl.h"
extern CMainApp theApp;
#define RECURSIVE 0x10
#define WARNINGS 0x20
///////////////////////////////////////////////////////////////////////////////
CString CreateName(CString & strTokenName, CString strExt, int iID)
{
CString strOutputName = strTokenName;
int iNamePos = strTokenName.ReverseFind('\\');
if(iNamePos!=-1) {
strOutputName = strTokenName.Right(strTokenName.GetLength()-iNamePos-1);
} else if(iNamePos = strTokenName.ReverseFind(':')!=-1){
strOutputName = strTokenName.Right(strTokenName.GetLength()-iNamePos-1);
}
CString strID = "";
// subst with ID name
_itoa(iID++, strID.GetBuffer(10), 10);
strID.ReleaseBuffer(-1);
// Check the length of the name
iNamePos = strOutputName.Find('.');
if(iNamePos!=-1)
strOutputName.SetAt(iNamePos, '_');
strOutputName = strOutputName + "_" + strID + strExt;
return strOutputName;
}
CString CreateName(CString & strTokenName, CString strExt, CString strIdName)
{
CString strOutputName = strTokenName;
int iNamePos = strTokenName.ReverseFind('\\');
if(iNamePos!=-1) {
strOutputName = strTokenName.Right(strTokenName.GetLength()-iNamePos-1);
} else if(iNamePos = strTokenName.ReverseFind(':')!=-1){
strOutputName = strTokenName.Right(strTokenName.GetLength()-iNamePos-1);
}
iNamePos = strOutputName.Find('.');
if(iNamePos!=-1)
strOutputName.SetAt(iNamePos, '_');
iNamePos = strIdName.Find(':');
if (iNamePos!=-1)
strIdName.SetAt(iNamePos, '_');
iNamePos = strIdName.Find('\\');
if (iNamePos!=-1)
strIdName.SetAt(iNamePos, '_');
strOutputName = strOutputName + "_" + strIdName + strExt;
return strOutputName;
}
///////////////////////////////////////////////////////////////////////////////
// This function will parse the source file and create the token file
CMainApp::Error_Codes CMainApp::TokGen()
{
Error_Codes ReturnErr = ERR_NOERROR;
WriteCon(CONERR, "%s\r\n", CalcTab("", 79, '-'));
// Open the iodll.dll using the first file name
HANDLE hModule = RSOpenModule(m_strInExe, NULL);
if ((int)(INT_PTR)hModule < LAST_ERROR) {
// error or warning
WriteCon(CONERR, "%s", CalcTab(m_strInExe, m_strInExe.GetLength()+5, ' '));
IoDllError((int)(INT_PTR)hModule);
return ERR_FILE_NOTSUPP;
} else {
// before we do anything else we have to check how many languages we have in the file
CString strLang;
char szLang[8];
BOOL b_multi_lang = FALSE;
USHORT usInputLang = MAKELANGID(m_usIPriLangId, m_usISubLangId);
if((b_multi_lang = RSLanguages(hModule, strLang.GetBuffer(1024))) && !IsFlag(INPUT_LANG))
{
// this is a multiple language file but we don't have an input language specified
// Fail, but warn the user that he has to set the input language to continue.
strLang.ReleaseBuffer();
WriteCon(CONERR, "Multiple language file. Please specify an input language %s.\r\n", strLang);
theApp.SetReturn(ERROR_FILE_MULTILANG);
goto exit;
}
// Convert the language in to the hex value
sprintf(szLang,"0x%3.3X", usInputLang);
// Check if the input language that we got is a valid one
if(IsFlag(INPUT_LANG) && strLang.Find(szLang)==-1)
{
WriteCon(CONERR, "The language %s in not a valid language for this file.\r\n", szLang);
WriteCon(CONERR, "Valid languages are: %s.\r\n", strLang);
theApp.SetReturn(ERROR_RES_NOT_FOUND);
goto exit;
}
// Check if the user is extracting the neutral language
if(!usInputLang)
usInputLang = 0xFFFF;
// Open the output file
CStdioFile fileOut;
if(!fileOut.Open(m_strTgtTok, CFile::modeCreate | CFile::modeReadWrite)) {
WriteCon(CONERR, "Cannot create file: %s\r\n", CalcTab(m_strTgtTok, m_strTgtTok.GetLength()+5, ' '));
return ERR_FILE_CREATE;
}
CString strOutputDir = "";
CString strFileName = m_strInExe;
int pos = m_strInExe.ReverseFind('\\');
if(pos!=-1)
{
strFileName = m_strInExe.Right(m_strInExe.GetLength()-pos-1);
}
else
if((pos = m_strInExe.ReverseFind(':'))!=-1)
{
strFileName = m_strInExe.Right(m_strInExe.GetLength()-pos-1);
}
pos = m_strTgtTok.ReverseFind('\\');
if(pos!=-1)
{
strOutputDir = m_strTgtTok.Left(pos+1);
}
else
if((pos = m_strTgtTok.ReverseFind(':'))!=-1)
{
strOutputDir = m_strTgtTok.Left(pos+1);
}
// inform the user ...
WriteCon(CONOUT, "Processing\t");
WriteCon(CONBOTH, "%s", CalcTab(strFileName, strFileName.GetLength()+5, ' '));
if (IsFlag(WARNING))
WriteCon(CONOUT, "\r\n");
LPCSTR lpszType = 0L;
LPCSTR lpszRes = 0L;
DWORD dwLang = 0L;
DWORD dwItem = 0L;
DWORD dwItemID = 0L;
LPRESITEM lpResItem = NULL;
CString strToken;
CString strResName;
CString strCaption;
WORD wFlag;
BOOL bSkip = FALSE;
BOOL bSkipEmpty = FALSE;
BOOL bSkipLang = FALSE;
WORD wCount = 0;
WORD wMsgCount = 0;
int iPos = 1;
int iBmpIdCount = 0;
BOOL bVersionStampOnly = TRUE;
BOOL bCustomResource = FALSE;
while ((lpszType = RSEnumResType(hModule, lpszType))) {
// Check if is one of the type we care about
if(HIWORD(lpszType)==0)
{
switch(LOWORD(lpszType))
{
case 2:
case 3:
if(theApp.IsFlag(CMainApp::BITMAPS))
bSkip = FALSE;
else bSkip = TRUE;
break;
case 4:
case 5:
case 6:
case 11:
bVersionStampOnly = FALSE;
case 9:
case 10:
case 16:
bSkip = FALSE;
break;
case 23:
case 240:
case 1024:
case 2110:
if(theApp.IsFlag(CMainApp::GIFHTMLINF))
bSkip = FALSE;
else
bSkip = TRUE;
bVersionStampOnly = FALSE;
bCustomResource = TRUE;
break;
default:
bSkip = TRUE;
}
}
else
{
if (lstrcmp (lpszType, "REGINST") == 0)
{
if(theApp.IsFlag(CMainApp::GIFHTMLINF))
bSkip = FALSE;
else
bSkip = TRUE;
bCustomResource = TRUE;
}
else
{
bSkip = FALSE;
}
bVersionStampOnly = FALSE;
}
lpszRes = 0L;
dwLang = 0L;
dwItem = 0L;
while ((!bSkip) && (lpszRes = RSEnumResId(hModule, lpszType, lpszRes))) {
while ((dwLang = RSEnumResLang(hModule, lpszType, lpszRes, dwLang))) {
// Check if we have to skip this language
if(b_multi_lang && (LOWORD(dwLang)!=usInputLang))
bSkipLang = TRUE;
else
bSkipLang = FALSE;
while ((!bSkipLang) && (dwItem = RSEnumResItemId(hModule, lpszType, lpszRes, dwLang, dwItem))) {
// Now Get the Data
DWORD dwImageSize = RSGetResItemData( hModule,
lpszType,
lpszRes,
dwLang,
dwItem,
m_pBuf,
MAX_BUF_SIZE );
lpResItem = (LPRESITEM)m_pBuf;
if((wCount++ % 50)==0 && !(IsFlag(WARNING)))
WriteCon(CONOUT, ".");
if (HIWORD(lpszType))
{
if (lstrcmp (lpszType,"REGINST") == 0)
{
//
// Currently there is no id for REGINST defined
// in nt. We just use this 2200 for now.
//
lpResItem->dwTypeID = 2200;
}
}
// Check if we want or not empty strings
// Allow empty strings for Dialog resources
switch(lpResItem->dwTypeID)
{
case 4:
case 16:
bSkipEmpty = TRUE;
break;
default:
bSkipEmpty = FALSE;
break;
}
// Version stamp use class name as res id
if(lpResItem->lpszResID)
strResName = lpResItem->lpszResID;
else strResName = "";
dwItemID = lpResItem->dwItemID;
if(lpResItem->dwTypeID==5 &&
dwItemID==0 &&
lpResItem->dwExtStyle){
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=0x%08x\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID,
ISEXTSTYLE,
ST_TRANSLATED,
strResName.GetBuffer(0),
lpResItem->dwExtStyle);
fileOut.WriteString(strToken);
}
// Add font info for dialogs
if((theApp.IsFlag(CMainApp::FONTS)
&& (lpResItem->dwTypeID==5) && (dwItemID==0)))
{
if( (lpResItem->dwStyle & DS_SETFONT)!=DS_SETFONT ){
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID,
ISDLGFONTNAME | ISDLGFONTSIZE,
ST_TRANSLATED,
strResName.GetBuffer(0));
WriteCon(CONWRN, "Dialog ID %s is missing the DS_SETFONT bit. Cannot extract font information!\r\n", strToken);
}else{
// Add font information
if (lpResItem->bCharSet != DEFAULT_CHARSET){
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%s:%hd:%d\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID,
ISDLGFONTNAME | ISDLGFONTSIZE|ISDLGFONTCHARSET,
ST_TRANSLATED,
strResName.GetBuffer(0),
Format(lpResItem->lpszFaceName),
lpResItem->wPointSize,
lpResItem->bCharSet);
}else{
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%s:%hd\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID,
ISDLGFONTNAME | ISDLGFONTSIZE ,
ST_TRANSLATED,
strResName.GetBuffer(0),
Format(lpResItem->lpszFaceName),
lpResItem->wPointSize);
}
fileOut.WriteString(strToken);
}
}
strCaption = lpResItem->lpszCaption;
// Set the flag
wFlag = 0;
if(!(bSkipEmpty && strCaption.IsEmpty()))
{
CString strExt;
switch(lpResItem->dwTypeID)
{
case 2:
case 3:
case 23:
case 240:
case 1024:
case 2110:
case 2200:
{
switch(lpResItem->dwTypeID)
{
case 2:
strExt = ".bmp";
break;
case 3:
strExt = ".ico";
break;
case 240:
case 1024:
strExt = ".bin";
break;
case 23:
case 2110:
strExt = "";
break;
case 2200:
strExt = ".inf";
break;
}
// create the output name
CString strOutputName;
if(lpResItem->dwResID)
{
strOutputName = CreateName(
strFileName,
strExt,
lpResItem->dwResID);
}
else
{
strOutputName = CreateName(
strFileName,
strExt,
lpResItem->lpszResID);
}
// Get the image from the file
DWORD dwBufSize = RSGetResImage( hModule,
lpszType,
lpszRes,
dwLang,
NULL,
0 );
BYTE * pBuf = (BYTE*)(new BYTE[dwBufSize]);
if(pBuf==NULL)
{
WriteCon(CONERR,
"Warning: Failed to allocate buffer for image! (%d, %d, %s, Size: %d)\r\n",
lpResItem->dwTypeID,
lpResItem->dwResID,
lpResItem->lpszResID,
dwBufSize);
break;
}
dwBufSize = RSGetResImage( hModule,
lpszType,
lpszRes,
dwLang,
pBuf,
dwBufSize );
// write the data in to a file
CFile OutputFile;
if(!OutputFile.Open(strOutputDir+strOutputName, CFile::modeCreate | CFile::modeWrite))
{
WriteCon(CONERR, "Cannot create file: %s\r\n",
CalcTab(strOutputDir+strOutputName, strOutputName.GetLength()+strOutputDir.GetLength()+5, ' '));
delete pBuf;
break;
}
switch(lpResItem->dwTypeID)
{
case 2:
{
BITMAPFILEHEADER bmpFileHeader;
BITMAPINFO * pbmpInfo = (BITMAPINFO *)pBuf;
DWORD dwNumColor = 0;
if(pbmpInfo->bmiHeader.biBitCount!=24)
dwNumColor = ( 1L << pbmpInfo->bmiHeader.biBitCount);
bmpFileHeader.bfType = 0x4d42;
bmpFileHeader.bfSize = (dwBufSize+sizeof(BITMAPFILEHEADER))/4;
bmpFileHeader.bfReserved1 = 0;
bmpFileHeader.bfReserved2 = 0;
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + pbmpInfo->bmiHeader.biSize + dwNumColor*sizeof(RGBQUAD);
OutputFile.Write(&bmpFileHeader, sizeof(BITMAPFILEHEADER));
}
break;
case 3:
{
ICONHEADER icoHeader;
BITMAPINFOHEADER * pbmpInfoH = (BITMAPINFOHEADER*)pBuf;
icoHeader.idReserved = 0;
icoHeader.idType = 1;
icoHeader.idCount = 1;
icoHeader.bWidth = LOBYTE(pbmpInfoH->biWidth);
icoHeader.bHeight = LOBYTE(pbmpInfoH->biWidth);
icoHeader.bColorCount = 16;
icoHeader.bReserved = 0;
icoHeader.wPlanes = 0;
icoHeader.wBitCount = 0;
icoHeader.dwBytesInRes = dwBufSize;
icoHeader.dwImageOffset = sizeof(ICONHEADER);
OutputFile.Write(&icoHeader, sizeof(ICONHEADER));
}
case 23:
case 240:
case 1024:
case 2110:
case 2200:
{
//
// No header for html stuff.
//
break;
}
break;
default:
break;
}
OutputFile.Write(pBuf, dwBufSize);
OutputFile.Close();
delete pBuf;
strCaption = strOutputName;
}
break;
case 4:
if(lpResItem->dwFlags & MF_POPUP) {
wFlag = ISPOPUP;
// check if this popup has a valid ID
if (LOWORD(dwItemID)==0xffff)
wFlag |= OLD_POPUP_ID;
dwItemID = (LOWORD(dwItemID)==0xffff ? HIWORD(dwItemID) : dwItemID);
}
else if (LOWORD(dwItemID)==0xffff)
{
dwItemID = HIWORD(dwItemID);
WriteCon (CONWRN, TEXT("Token [[%u|%u|%u|%u|%u|\"%s\"]] is generated with a suspicious ID. Please check the resource file for invalid ID's.\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID,
wFlag,
ST_TRANSLATED,
strResName.GetBuffer(0));
}
break;
case 5:
if(dwItemID==0) {
wFlag = ISCAP;
}
// check if this is a duplicated id
if (LOWORD(dwItemID)==0xffff)
wFlag |= ISDUP;
dwItemID = (LOWORD(dwItemID)==0xffff ? HIWORD(dwItemID) : dwItemID);
break;
case 9:
{
CAccel accel(lpResItem->dwFlags, lpResItem->dwStyle);
strCaption = accel.GetText();
// check if this is a duplicated ID
if(HIWORD(dwItemID))
{
wFlag |= ISDUP;
}
}
break;
case 11:
dwItemID = LOWORD(dwItemID);
break;
case 16:
strResName = lpResItem->lpszClassName;
break;
default:
break;
}
// Create the token file
if(lpResItem->dwTypeID==11 && theApp.IsFlag(CMainApp::SPLIT))
{
// Search for the \r\n and replace them
while((iPos = strCaption.Find("\r\n"))!=-1)
{
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%s\\r\\n\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID,
wFlag | wMsgCount++,
ST_TRANSLATED,
strResName.GetBuffer(0),
Format(strCaption.Left(iPos)));
strCaption = strCaption.Right(strCaption.GetLength()-2-iPos);
fileOut.WriteString(strToken);
}
wMsgCount = 0;
}
else
{
if(lpResItem->dwTypeID==16 &&
theApp.IsFlag(CMainApp::NOVERSION) &&
(strResName==TEXT("FileVersion") ||
strResName==TEXT("ProductVersion") ||
strResName==TEXT("Platform"))){
//
// do not generate token for these resources
//
}else{
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%s\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
dwItemID, /*(LOWORD(dwItemID)==0xffff ? HIWORD(dwItemID) : dwItemID),*/
wFlag,
ST_TRANSLATED,
strResName.GetBuffer(0),
Format(strCaption));
fileOut.WriteString(strToken);
}
}
// If this is a dialog box add the coordinates
if(lpResItem->dwTypeID==5)
{
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%hu %hu %hu %hu\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
(LOWORD(dwItemID)==0xffff ? HIWORD(dwItemID) : dwItemID),
wFlag | ISCOR,
ST_TRANSLATED,
strResName.GetBuffer(0),
lpResItem->wX,
lpResItem->wY,
lpResItem->wcX,
lpResItem->wcY);
fileOut.WriteString(strToken);
//Extract STATIC control alignment style info
if (LOBYTE(lpResItem->wClassName) == 0x82 &&
theApp.IsFlag(CMainApp::ALIGNMENT))
{
CHAR szBuf[20]="SS_LEFT";
if ((lpResItem->dwStyle & SS_CENTER) == SS_CENTER)
lstrcpy(szBuf, "SS_CENTER");
else if ((lpResItem->dwStyle & SS_RIGHT)==SS_RIGHT)
lstrcpy(szBuf, "SS_RIGHT");
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%s\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
(LOWORD(dwItemID)==0xffff ? HIWORD(dwItemID) : dwItemID),
wFlag | ISALIGN,
ST_TRANSLATED,
strResName.GetBuffer(0),
szBuf);
fileOut.WriteString(strToken);
}
}
}
else
{
// If this is a dialog box add the coordinates
if(lpResItem->dwTypeID==5) {
sprintf(strToken.GetBuffer(MAX_STR_SIZE),
TEXT("[[%u|%u|%u|%u|%u|\"%s\"]]=%hu %hu %hu %hu\n"),
lpResItem->dwTypeID,
lpResItem->dwResID,
(LOWORD(dwItemID)==0xffff ? HIWORD(dwItemID) : dwItemID),
wFlag | ISCOR,
ST_TRANSLATED,
strResName.GetBuffer(0),
lpResItem->wX,
lpResItem->wY,
lpResItem->wcX,
lpResItem->wcY);
fileOut.WriteString(strToken);
}
}
} // end while
}
}
}
fileOut.Close();
// Check the size of the new file and remove it if empty...
CFileStatus fstat;
if(CFile::GetStatus(m_strTgtTok, fstat))
if(fstat.m_size==0)
CFile::Remove(m_strTgtTok);
WriteCon(CONBOTH, " %hu Items\r\n", wCount);
if(bVersionStampOnly) {
ReturnErr = ERR_FILE_VERSTAMPONLY;
theApp.SetReturn(ERROR_FILE_VERSTAMPONLY);
WriteCon(CONWRN, "%s : Version Stamping only!\r\n", strFileName);
}
if(bCustomResource) {
SetReturn(ERROR_FILE_CUSTOMRES);
WriteCon(CONWRN, "%s : Custom resource!\r\n", strFileName);
}
}
exit:
RSCloseModule(hModule);
return ReturnErr;
}