You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1188 lines
39 KiB
1188 lines
39 KiB
/***********************************************************************
|
|
* Microsoft (R) Windows (R) Resource Compiler
|
|
*
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
*
|
|
* File Comments:
|
|
*
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "rc.h"
|
|
|
|
|
|
static BOOL fFontDirRead = FALSE;
|
|
|
|
BOOL bExternParse = FALSE;
|
|
|
|
WORD language = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|
LONG version = 0;
|
|
LONG characteristics = 0;
|
|
|
|
static int rowError = 0;
|
|
static int colError = 0;
|
|
static int idError = 0;
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ParseError3() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
ParseError3(
|
|
int id
|
|
)
|
|
{
|
|
// Don't get caught giving the same error over and over and over...
|
|
if ((Nerrors > 0) && (idError == id) && (rowError == token.row) && (colError == token.col))
|
|
quit(NULL);
|
|
|
|
SendError(L"\n");
|
|
SendError(Msg_Text);
|
|
|
|
if (++Nerrors > 25)
|
|
quit(NULL);
|
|
|
|
rowError = token.row;
|
|
colError = token.col;
|
|
idError = id;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ParseError2() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
ParseError2(
|
|
int id,
|
|
PWCHAR arg
|
|
)
|
|
{
|
|
// Don't get caught giving the same error over and over and over...
|
|
if ((Nerrors > 0) && (idError == id) && (rowError == token.row) && (colError == token.col))
|
|
quit(NULL);
|
|
|
|
SendError(L"\n");
|
|
SET_MSG(id, curFile, token.row, arg);
|
|
SendError(Msg_Text);
|
|
|
|
if (++Nerrors > 25)
|
|
quit(NULL);
|
|
|
|
rowError = token.row;
|
|
colError = token.col;
|
|
idError = id;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ParseError1() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
void
|
|
ParseError1(
|
|
int id
|
|
)
|
|
{
|
|
// Don't get caught giving the same error over and over and over...
|
|
if ((Nerrors > 0) && (idError == id) && (rowError == token.row) && (colError == token.col))
|
|
quit(NULL);
|
|
|
|
SendError(L"\n");
|
|
SET_MSG(id, curFile, token.row);
|
|
SendError(Msg_Text);
|
|
|
|
if (++Nerrors > 25)
|
|
quit(NULL);
|
|
|
|
rowError = token.row;
|
|
colError = token.col;
|
|
idError = id;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* GetFileName() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* Read in a filename from the RC file. */
|
|
|
|
VOID
|
|
SearchInclude(wchar_t *szFile, wchar_t *szActual)
|
|
{
|
|
size_t cchFile;
|
|
const wchar_t *pchVar;
|
|
|
|
// We don't do absolute paths
|
|
|
|
if ((szFile[0] == L'\\') || (szFile[0] == L'/') || (szFile[1] == L':')) {
|
|
if (wcslen(szFile) >= _MAX_PATH) {
|
|
szActual[0] = L'\0';
|
|
} else {
|
|
wcscpy(szActual, szFile);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
cchFile = wcslen(szFile) + 1;
|
|
|
|
pchVar = pchInclude;
|
|
|
|
while (*pchVar != L'\0') {
|
|
size_t ich;
|
|
|
|
// Copy the next include path component
|
|
|
|
for (ich = 0; *pchVar != L'\0'; pchVar++) {
|
|
if (*pchVar == L';') {
|
|
pchVar++;
|
|
break;
|
|
}
|
|
|
|
if (ich < _MAX_PATH) {
|
|
szActual[ich++] = *pchVar;
|
|
}
|
|
}
|
|
|
|
if ((ich == 0) || (ich == _MAX_PATH)) {
|
|
// Skip empty paths (e.g. ";;")
|
|
// Skip too long paths too
|
|
|
|
continue;
|
|
}
|
|
|
|
// Find end of path string
|
|
|
|
// Check first! this is what _searchenv() messed up!
|
|
|
|
if ((szActual[ich - 1] != L'\\') && (szActual[ich - 1] != L'/')) {
|
|
if (ich < _MAX_PATH) {
|
|
szActual[ich++] = L'\\';
|
|
}
|
|
}
|
|
|
|
// We already know szFile does not start with a drive or abs. dir
|
|
|
|
if ((ich + cchFile) >= _MAX_PATH) {
|
|
continue;
|
|
}
|
|
|
|
wcscpy(szActual + ich, szFile);
|
|
|
|
// Is the file here? szActual already contains name
|
|
|
|
if (!_waccess(szActual, 0)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
szActual[0] = L'\0';
|
|
}
|
|
|
|
|
|
LONG
|
|
GetFileName(
|
|
VOID
|
|
)
|
|
{
|
|
PFILE fh;
|
|
LONG size;
|
|
wchar_t szFilename[_MAX_PATH];
|
|
|
|
SearchInclude(tokenbuf, szFilename);
|
|
|
|
if (szFilename[0] && ((fh = _wfopen(szFilename, L"rb")) != NULL)) {
|
|
size = MySeek(fh, 0, SEEK_END); /* find size of file */
|
|
MySeek(fh, 0, SEEK_SET); /* return to start of file */
|
|
CtlFile(fh);
|
|
return(size);
|
|
}
|
|
|
|
ParseError2(2135, tokenbuf);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* AddStringToBin() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* adds ordinal if non-zero, otherwise adds string. In either case, puts */
|
|
/* it in a field of NCHARS [16] */
|
|
|
|
VOID
|
|
AddStringToBin(
|
|
USHORT ord,
|
|
WCHAR *sz
|
|
)
|
|
{
|
|
USHORT n1 = 0xFFFF;
|
|
|
|
/* Is this an ordinal type? */
|
|
if (ord) {
|
|
MyWrite(fhBin, &n1, sizeof(USHORT)); /* 0xFFFF */
|
|
MyWrite(fhBin, &ord, sizeof(USHORT));
|
|
} else {
|
|
MyWrite(fhBin, sz, (wcslen(sz)+1) * sizeof(WCHAR));
|
|
}
|
|
}
|
|
|
|
|
|
PWCHAR pTypeName[] =
|
|
{
|
|
NULL, // 0
|
|
L"CURSOR", // 1 RT_CURSOR
|
|
L"BITMAP", // 2 RT_BITMAP
|
|
L"ICON", // 3 RT_ICON
|
|
L"MENU", // 4 RT_MENU
|
|
L"DIALOG", // 5 RT_DIALOG
|
|
L"STRING", // 6 RT_STRING
|
|
L"FONTDIR", // 7 RT_FONTDIR
|
|
L"FONT", // 8 RT_FONT
|
|
L"ACCELERATOR", // 9 RT_ACCELERATOR
|
|
L"RCDATA", // 10 RT_RCDATA
|
|
L"MESSAGETABLE", // 11 RT_MESSAGETABLE
|
|
L"GROUP_CURSOR", // 12 RT_GROUP_CURSOR
|
|
NULL, // 13 RT_NEWBITMAP -- according to NT
|
|
L"GROUP_ICON", // 14 RT_GROUP_ICON
|
|
NULL, // 15 RT_NAMETABLE
|
|
L"VERSION", // 16 RT_VERSION
|
|
L"DIALOGEX", // 17 RT_DIALOGEX ;internal
|
|
L"DLGINCLUDE", // 18 RT_DLGINCLUDE
|
|
L"PLUGPLAY", // 19 RT_PLUGPLAY
|
|
L"VXD", // 20 RT_VXD
|
|
L"ANICURSOR", // 21 RT_ANICURSOR ;internal
|
|
L"ANIICON", // 22 RT_ANIICON ;internal
|
|
L"HTML" // 23 RT_HTML
|
|
};
|
|
|
|
// Note: Don't forget to update the same table in rcdump.c
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* AddBinEntry() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* FORMAT: type, name, flags, length, bytes */
|
|
|
|
VOID
|
|
AddBinEntry(
|
|
PTYPEINFO pType,
|
|
PRESINFO pRes,
|
|
PCHAR Array,
|
|
int ArrayCount,
|
|
LONG FileCount
|
|
)
|
|
{
|
|
ULONG hdrSize = sizeof(RESADDITIONAL);
|
|
ULONG t0 = 0;
|
|
ULONG cbPad=0;
|
|
|
|
if (!pRes->size)
|
|
pRes->size = ResourceSize();
|
|
|
|
if (pType->typeord == 0) {
|
|
hdrSize += (wcslen(pType->type) + 1) * sizeof(WCHAR);
|
|
cbPad += (wcslen(pType->type) + 1) * sizeof(WCHAR);
|
|
} else {
|
|
hdrSize += 2 * sizeof(WORD);
|
|
}
|
|
|
|
if (pRes->nameord == 0) {
|
|
hdrSize += (wcslen(pRes->name) + 1) * sizeof(WCHAR);
|
|
cbPad += (wcslen(pRes->name) + 1) * sizeof(WCHAR);
|
|
} else {
|
|
hdrSize += 2 * sizeof(WORD);
|
|
}
|
|
|
|
if (cbPad % 4)
|
|
hdrSize += sizeof(WORD); // could only be off by 2
|
|
|
|
if (fVerbose) {
|
|
if (pType->typeord == 0) {
|
|
if (pRes->nameord == 0)
|
|
swprintf(Msg_Text, L"\nWriting %s:%s,\tlang:0x%x,\tsize %d",
|
|
pType->type, pRes->name, pRes->language, pRes->size);
|
|
else
|
|
swprintf(Msg_Text, L"\nWriting %s:%d,\tlang:0x%x,\tsize %d",
|
|
pType->type, pRes->nameord, pRes->language, pRes->size);
|
|
} else {
|
|
if (pRes->nameord == 0) {
|
|
if (pType->typeord <= (USHORT)(UINT_PTR)RT_LAST)
|
|
swprintf(Msg_Text, L"\nWriting %s:%s,\tlang:0x%x,\tsize %d",
|
|
pTypeName[pType->typeord],
|
|
pRes->name, pRes->language, pRes->size);
|
|
else
|
|
swprintf(Msg_Text, L"\nWriting %d:%s,\tlang:0x%x,\tsize %d",
|
|
pType->typeord,
|
|
pRes->name, pRes->language, pRes->size);
|
|
} else {
|
|
if (pType->typeord <= (USHORT)(UINT_PTR)RT_LAST)
|
|
swprintf(Msg_Text, L"\nWriting %s:%d,\tlang:0x%x,\tsize %d",
|
|
pTypeName[pType->typeord],
|
|
pRes->nameord, pRes->language, pRes->size);
|
|
else
|
|
swprintf(Msg_Text, L"\nWriting %d:%d,\tlang:0x%x,\tsize %d",
|
|
pType->typeord,
|
|
pRes->nameord, pRes->language, pRes->size);
|
|
}
|
|
}
|
|
fputws(Msg_Text, stdout);
|
|
}
|
|
|
|
if (fMacRsrcs) {
|
|
/* record file location for the resource map and dump out
|
|
resource's size */
|
|
DWORD dwT;
|
|
pRes->BinOffset = (long)MySeek(fhBin,0L,1) - MACDATAOFFSET;
|
|
dwT = SwapLong(pRes->size);
|
|
MyWrite(fhBin, &dwT, 4);
|
|
} else {
|
|
/* add type, name, flags, and resource length */
|
|
MyWrite(fhBin, &pRes->size, sizeof(ULONG));
|
|
MyWrite(fhBin, &hdrSize, sizeof(ULONG));
|
|
|
|
AddStringToBin(pType->typeord, pType->type);
|
|
AddStringToBin(pRes->nameord , pRes->name);
|
|
MyAlign(fhBin);
|
|
|
|
MyWrite(fhBin, &t0, sizeof(ULONG)); /* data version */
|
|
MyWrite(fhBin, &pRes->flags, sizeof(WORD));
|
|
MyWrite(fhBin, &pRes->language, sizeof(WORD));
|
|
MyWrite(fhBin, &pRes->version, sizeof(ULONG));
|
|
MyWrite(fhBin, &pRes->characteristics, sizeof(ULONG));
|
|
|
|
/* record file location for the .EXE construction */
|
|
pRes->BinOffset = (LONG)MySeek(fhBin, 0L, SEEK_CUR);
|
|
}
|
|
|
|
/* write array plus contents of resource source file */
|
|
WriteControl(fhBin, Array, ArrayCount, FileCount);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* AddResToResFile(pType, pRes, Array, ArrayCount, FileCount) */
|
|
/* */
|
|
/* Parameters: */
|
|
/* pType : Pointer to Res Type */
|
|
/* pRes : Pointer to resource */
|
|
/* Array : Pointer to array from which some data is to be copied into */
|
|
/* the .RES file. */
|
|
/* This is ignored if ArrayCount is zero. */
|
|
/* ArrayCount : This is the number of bytes to be copied from "Array" */
|
|
/* into the .RES file. This is zero if no copy is required*/
|
|
/* FileCount : This specifies the number of bytes to be copied from */
|
|
/* fhCode into fhOut. If this is -1, the complete input */
|
|
/* file is to be copied into fhOut. */
|
|
/* */
|
|
/*------------------------------------------------------------------------*/
|
|
|
|
VOID
|
|
AddResToResFile(
|
|
PTYPEINFO pType,
|
|
PRESINFO pRes,
|
|
PCHAR Array,
|
|
int ArrayCount,
|
|
LONG FileCount
|
|
)
|
|
{
|
|
PRESINFO p;
|
|
|
|
p = pType->pres;
|
|
|
|
/* add resource to end of resource list for this type */
|
|
if (p) {
|
|
while (p->next)
|
|
p = p->next;
|
|
|
|
p->next = pRes;
|
|
} else {
|
|
pType->pres = pRes;
|
|
}
|
|
|
|
|
|
/* add the resource to the .RES File */
|
|
AddBinEntry(pType, pRes, Array, ArrayCount, FileCount);
|
|
|
|
/* keep track of number of resources and types */
|
|
pType->nres++;
|
|
ResCount++;
|
|
WriteResInfo(pRes, pType, TRUE);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* AddResType() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
PTYPEINFO
|
|
AddResType(
|
|
PWCHAR s,
|
|
LPWSTR l
|
|
)
|
|
{
|
|
PTYPEINFO pType;
|
|
|
|
if ((pType = pTypInfo) != 0) {
|
|
for (; ; ) {
|
|
/* search for resource type, return if already exists */
|
|
if ((s && pType->type && !wcscmp(s, pType->type)) ||
|
|
(!s && l && pType->typeord == (USHORT)l))
|
|
return(pType);
|
|
else if (!pType->next)
|
|
break;
|
|
else
|
|
pType = pType->next;
|
|
}
|
|
|
|
/* if not in list, add space for it */
|
|
pType->next = (PTYPEINFO)MyAlloc(sizeof(TYPEINFO));
|
|
pType = pType->next;
|
|
} else {
|
|
/* allocate space for resource list */
|
|
pTypInfo = (PTYPEINFO)MyAlloc(sizeof(TYPEINFO));
|
|
pType = pTypInfo;
|
|
}
|
|
|
|
/* fill allocated space with name and ordinal, and clear the resources
|
|
of this type */
|
|
pType->type = MyMakeStr(s);
|
|
pType->typeord = (USHORT)l;
|
|
pType->nres = 0;
|
|
pType->pres = NULL;
|
|
|
|
return(pType);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* DGetMemFlags() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
int
|
|
DGetMemFlags (
|
|
PRESINFO pRes
|
|
)
|
|
{
|
|
if (token.type == NUMLIT)
|
|
// this is a numeric value, not a mem flag -- this means we're done
|
|
// processing memory flags
|
|
return(FALSE);
|
|
|
|
/* adjust memory flags of resource */
|
|
switch (token.val) {
|
|
case TKMOVEABLE:
|
|
pRes->flags |= NSMOVE;
|
|
break;
|
|
|
|
case TKFIXED:
|
|
pRes->flags &= ~(NSMOVE | NSDISCARD);
|
|
break;
|
|
|
|
case TKPURE :
|
|
pRes->flags |= NSPURE;
|
|
break;
|
|
|
|
case TKIMPURE :
|
|
pRes->flags &= ~(NSPURE | NSDISCARD);
|
|
break;
|
|
|
|
case TKPRELOAD:
|
|
pRes->flags |= NSPRELOAD;
|
|
break;
|
|
|
|
case TKLOADONCALL:
|
|
pRes->flags &= ~NSPRELOAD;
|
|
break;
|
|
|
|
case TKDISCARD:
|
|
pRes->flags |= NSMOVE | NSPURE | NSDISCARD;
|
|
break;
|
|
|
|
case TKEXSTYLE:
|
|
GetToken(FALSE); /* ignore '=' */
|
|
if (token.type != EQUAL)
|
|
ParseError1(2136);
|
|
GetTokenNoComma(TOKEN_NOEXPRESSION);
|
|
GetFullExpression(&pRes->exstyleT, GFE_ZEROINIT);
|
|
break;
|
|
|
|
/* if current token not memory flag, return FALSE to indicate not
|
|
to continue parsing flags */
|
|
default:
|
|
return(FALSE);
|
|
}
|
|
|
|
GetToken(FALSE);
|
|
|
|
/* TRUE ==> found memory flag */
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* AddDefaultTypes() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
VOID
|
|
AddDefaultTypes(
|
|
VOID
|
|
)
|
|
{
|
|
AddResType(L"CURSOR", RT_GROUP_CURSOR);
|
|
AddResType(L"ICON", RT_GROUP_ICON);
|
|
AddResType(L"BITMAP", RT_BITMAP);
|
|
AddResType(L"MENU", RT_MENU);
|
|
AddResType(L"DIALOG", RT_DIALOG);
|
|
AddResType(L"STRINGTABLE", RT_STRING);
|
|
AddResType(L"FONTDIR", RT_FONTDIR);
|
|
AddResType(L"FONT", RT_FONT);
|
|
AddResType(L"ACCELERATORS", RT_ACCELERATOR);
|
|
AddResType(L"RCDATA", RT_RCDATA);
|
|
AddResType(L"MESSAGETABLE", RT_MESSAGETABLE);
|
|
AddResType(L"VERSIONINFO", RT_VERSION);
|
|
AddResType(L"DLGINCLUDE", RT_DLGINCLUDE);
|
|
AddResType(L"MENUEX", RT_MENUEX);
|
|
AddResType(L"DIALOGEX", RT_DIALOGEX);
|
|
AddResType(L"PLUGPLAY", RT_PLUGPLAY);
|
|
AddResType(L"VXD", RT_VXD);
|
|
|
|
// AFX resource types.
|
|
AddResType(L"DLGINIT", RT_DLGINIT);
|
|
AddResType(L"TOOLBAR", RT_TOOLBAR);
|
|
|
|
AddResType(L"ANIICON", RT_ANIICON);
|
|
AddResType(L"ANICURSOR", RT_ANICURSOR);
|
|
|
|
AddResType(L"HTML", RT_HTML);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* AddFontDir() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
VOID
|
|
AddFontDir(
|
|
VOID
|
|
)
|
|
{
|
|
PRESINFO pRes;
|
|
PTYPEINFO pType;
|
|
PFONTDIR pFont;
|
|
|
|
/* make new resource */
|
|
pRes = (PRESINFO)MyAlloc(sizeof(RESINFO));
|
|
pRes->language = language;
|
|
pRes->version = version;
|
|
pRes->characteristics = characteristics;
|
|
pRes->name = MyMakeStr(L"FONTDIR");
|
|
|
|
/* find or create the type list */
|
|
pType = AddResType(NULL, RT_FONTDIR);
|
|
|
|
CtlInit();
|
|
|
|
WriteWord(nFontsRead);
|
|
|
|
pFont = pFontList;
|
|
|
|
while (pFont) {
|
|
WriteWord(pFont->ordinal);
|
|
WriteBuffer(pFont + 1, pFont->nbyFont);
|
|
pFont = pFont->next;
|
|
}
|
|
|
|
pRes->flags = NSMOVE | NSPRELOAD;
|
|
|
|
/* write to the .RES file */
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
/* */
|
|
/* ReadRF() - */
|
|
/* */
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/* top level parsing function: recognizes an RC script */
|
|
|
|
int
|
|
ReadRF(
|
|
VOID
|
|
)
|
|
{
|
|
PRESINFO pRes;
|
|
PTYPEINFO pType;
|
|
ULONG zero=0;
|
|
WORD ffff=0xffff;
|
|
ULONG hdrSize = sizeof(RESADDITIONAL) + 2 * (sizeof(WORD) * 2);
|
|
|
|
ResCount = 0;
|
|
nFontsRead = 0;
|
|
|
|
/* Initialize data structures. */
|
|
AddDefaultTypes();
|
|
|
|
if (!fMacRsrcs) {
|
|
/* write 32-bit header for empty resource/signature */
|
|
MyWrite(fhBin, &zero, sizeof(ULONG));
|
|
MyWrite(fhBin, &hdrSize, sizeof(ULONG));
|
|
MyWrite(fhBin, &ffff, sizeof(WORD));
|
|
MyWrite(fhBin, &zero, sizeof(WORD));
|
|
MyWrite(fhBin, &ffff, sizeof(WORD));
|
|
MyWrite(fhBin, &zero, sizeof(WORD));
|
|
MyWrite(fhBin, &zero, sizeof(ULONG));
|
|
MyWrite(fhBin, &zero, sizeof(WORD));
|
|
MyWrite(fhBin, &zero, sizeof(WORD));
|
|
MyWrite(fhBin, &zero, sizeof(ULONG));
|
|
MyWrite(fhBin, &zero, sizeof(ULONG));
|
|
}
|
|
|
|
CtlAlloc();
|
|
|
|
if (fAFXSymbols) {
|
|
int n;
|
|
char szMultiByte[_MAX_PATH];
|
|
char *pch = szMultiByte;
|
|
// write out first HWB resource
|
|
|
|
CtlInit();
|
|
pRes = (PRESINFO)MyAlloc(sizeof(RESINFO));
|
|
pRes->language = language;
|
|
pRes->version = version;
|
|
pRes->characteristics = characteristics;
|
|
|
|
pRes->size = sizeof(DWORD);
|
|
pRes->flags = 0;
|
|
pRes->name = 0;
|
|
pRes->nameord = 1;
|
|
WriteLong(0); /* space for file pointer */
|
|
|
|
n = wcslen(inname) + 1;
|
|
n = WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
inname,
|
|
n,
|
|
szMultiByte,
|
|
MAX_PATH,
|
|
NULL,
|
|
NULL);
|
|
|
|
while (*pch) {
|
|
WriteByte(*pch++);
|
|
pRes->size++;
|
|
}
|
|
WriteByte(0);
|
|
pRes->size++;
|
|
|
|
pType = AddResType(L"HWB", 0);
|
|
SaveResFile(pType, pRes);
|
|
lOffIndex = pRes->BinOffset;
|
|
}
|
|
|
|
/* Process the RC file. */
|
|
do {
|
|
token.sym.name[0] = L'\0';
|
|
token.sym.nID = 0;
|
|
|
|
/* Find the beginning of the next resource. */
|
|
if (!GetNameOrd())
|
|
break;
|
|
|
|
if (!wcscmp(tokenbuf, L"LANGUAGE")) {
|
|
language = GetLanguage();
|
|
continue;
|
|
} else if (!wcscmp(tokenbuf, L"VERSION")) {
|
|
GetToken(FALSE);
|
|
if (token.type != NUMLIT)
|
|
ParseError1(2139);
|
|
version = token.longval;
|
|
continue;
|
|
} else if (!wcscmp(tokenbuf, L"CHARACTERISTICS")) {
|
|
GetToken(FALSE);
|
|
if (token.type != NUMLIT)
|
|
ParseError1(2140);
|
|
characteristics = token.longval;
|
|
continue;
|
|
}
|
|
|
|
/* Print a dot for each resource processed. */
|
|
if (fVerbose) {
|
|
wprintf(L".");
|
|
}
|
|
|
|
/* Allocate space for the new resources Info structure. */
|
|
pRes = (PRESINFO)MyAlloc(sizeof(RESINFO));
|
|
pRes->language = language;
|
|
pRes->version = version;
|
|
pRes->characteristics = characteristics;
|
|
|
|
if (token.sym.name[0]) {
|
|
/* token has a real symbol associated with it */
|
|
memcpy(&pRes->sym, &token.sym, sizeof(SYMINFO));
|
|
} else {
|
|
pRes->sym.name[0] = L'\0';
|
|
}
|
|
|
|
if (!token.val) {
|
|
if (wcslen(tokenbuf) > MAXTOKSTR-1) {
|
|
SET_MSG(4206, curFile, token.row);
|
|
SendError(Msg_Text);
|
|
tokenbuf[MAXTOKSTR-1] = L'\0';
|
|
token.val = MAXTOKSTR-2;
|
|
}
|
|
pRes->name = MyMakeStr(tokenbuf);
|
|
} else {
|
|
pRes->nameord = token.val;
|
|
}
|
|
|
|
/* If not a string table, find out what kind of resource follows.
|
|
* The StringTable is a special case since the Name field is the
|
|
* string's ID number mod 16.
|
|
*/
|
|
if ((pRes->name == NULL) || wcscmp(pRes->name, L"STRINGTABLE")) {
|
|
if (!GetNameOrd())
|
|
break;
|
|
|
|
if (!token.val) {
|
|
if (wcslen(tokenbuf) > MAXTOKSTR-1) {
|
|
SET_MSG(4207, curFile, token.row);
|
|
SendError(Msg_Text);
|
|
tokenbuf[MAXTOKSTR-1] = L'\0';
|
|
token.val = MAXTOKSTR-2;
|
|
}
|
|
if (!wcscmp(tokenbuf, L"STRINGTABLE")) {
|
|
// User attempted to create a named string table... Bail
|
|
ParseError1(2255);
|
|
pRes->name = MyMakeStr(tokenbuf);
|
|
goto ItsAStringTable;
|
|
}
|
|
|
|
pType = AddResType(tokenbuf, MAKEINTRESOURCE(0));
|
|
}
|
|
else
|
|
pType = AddResType(NULL, MAKEINTRESOURCE(token.val));
|
|
|
|
if (!pType)
|
|
return(errorCount == 0);
|
|
|
|
/* Parse any user specified memory flags. */
|
|
GetToken(FALSE);
|
|
|
|
switch ((INT_PTR)pType->typeord) {
|
|
/* Calculated resources default to discardable. */
|
|
case (INT_PTR)RT_ICON:
|
|
case (INT_PTR)RT_CURSOR:
|
|
case (INT_PTR)RT_FONT:
|
|
case (INT_PTR)RT_DIALOG:
|
|
case (INT_PTR)RT_MENU:
|
|
case (INT_PTR)RT_DLGINCLUDE:
|
|
case (INT_PTR)RT_DIALOGEX:
|
|
case (INT_PTR)RT_MENUEX:
|
|
pRes->flags = NSMOVE | NSPURE | NSDISCARD;
|
|
break;
|
|
|
|
case (INT_PTR)RT_GROUP_ICON:
|
|
case (INT_PTR)RT_GROUP_CURSOR:
|
|
pRes->flags = NSMOVE | NSDISCARD;
|
|
break;
|
|
|
|
/* All other resources default to moveable. */
|
|
default:
|
|
pRes->flags = NSMOVE | NSPURE;
|
|
break;
|
|
}
|
|
|
|
/* adjust according to the user's specifications
|
|
*/
|
|
while (DGetMemFlags(pRes))
|
|
;
|
|
|
|
// write out start of new resource
|
|
WriteResInfo(pRes, pType, FALSE);
|
|
} else {
|
|
|
|
ItsAStringTable:
|
|
|
|
/* Parse any user specified memory flags. */
|
|
GetToken(FALSE);
|
|
|
|
/* String and Error resources default to discardable. */
|
|
pRes->flags = NSMOVE | NSPURE | NSDISCARD;
|
|
while (DGetMemFlags(pRes))
|
|
;
|
|
|
|
pType = NULL;
|
|
}
|
|
|
|
if (!pType) {
|
|
/* parse the string table, if that's what it is */
|
|
if ((pRes->name != NULL) && (!wcscmp(pRes->name, L"STRINGTABLE"))) {
|
|
if (GetTable(pRes) == NULL)
|
|
break;
|
|
} else {
|
|
ParseError1(2141);
|
|
}
|
|
} else {
|
|
CtlInit();
|
|
pRes->size = 0L;
|
|
|
|
/* call parsing and generating functions specific to the various
|
|
resource types */
|
|
switch ((INT_PTR)pType->typeord) {
|
|
case (INT_PTR)RT_DIALOGEX:
|
|
/* allocate dialog memory */
|
|
pLocDlg = (PDLGHDR) MyAlloc(sizeof(DLGHDR));
|
|
|
|
/* parse dialog box */
|
|
GetDlg(pRes, pLocDlg, TRUE);
|
|
|
|
/* write dialog box */
|
|
SaveResFile(AddResType(L"DIALOG", 0), pRes);
|
|
|
|
/* free dialog memory */
|
|
MyFree(pLocDlg);
|
|
break;
|
|
|
|
case (INT_PTR)RT_DIALOG:
|
|
/* allocate dialog memory */
|
|
pLocDlg = (PDLGHDR) MyAlloc(sizeof(DLGHDR));
|
|
|
|
/* parse dialog box */
|
|
GetDlg(pRes, pLocDlg, FALSE);
|
|
|
|
/* write dialog box */
|
|
SaveResFile(pType, pRes);
|
|
|
|
/* free dialog memory */
|
|
MyFree(pLocDlg);
|
|
break;
|
|
|
|
case (INT_PTR)RT_ACCELERATOR:
|
|
GetAccelerators(pRes);
|
|
SaveResFile(pType, pRes);
|
|
break;
|
|
|
|
case (INT_PTR)RT_MENUEX:
|
|
WriteWord(MENUITEMTEMPLATEVERSIONNUMBER);
|
|
WriteWord(MENUITEMTEMPLATEBYTESINHEADER);
|
|
ParseMenu(FALSE, pRes);
|
|
SaveResFile(AddResType(L"MENU", 0), pRes);
|
|
break;
|
|
|
|
case (INT_PTR)RT_MENU:
|
|
WriteWord(OLDMENUITEMTEMPLATEVERSIONNUMBER);
|
|
WriteWord(OLDMENUITEMTEMPLATEBYTESINHEADER);
|
|
ParseOldMenu(FALSE, pRes);
|
|
SaveResFile(pType, pRes);
|
|
break;
|
|
|
|
case (INT_PTR)RT_ICON:
|
|
case (INT_PTR)RT_CURSOR:
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
if (FileIsAnimated(pRes->size)) {
|
|
goto ani;
|
|
} else {
|
|
pRes->size = GetIcon(pRes->size);
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR) RT_ANIICON:
|
|
case (INT_PTR) RT_ANICURSOR:
|
|
ani:
|
|
{
|
|
USHORT iLastTypeOrd = pType->typeord;
|
|
|
|
// Strictly speaking, ANIICON and ANICURSOR are not allowed. However,
|
|
// we'll keep them around for the time being. BryanT 8/14/96.
|
|
if ((pType->typeord == (USHORT)(INT_PTR)RT_ICON) ||
|
|
(pType->typeord == (USHORT)(INT_PTR)RT_GROUP_ICON))
|
|
{
|
|
pType->typeord = (USHORT)(INT_PTR)RT_ANIICON;
|
|
} else
|
|
if ((pType->typeord == (USHORT)(INT_PTR) RT_CURSOR) ||
|
|
(pType->typeord == (USHORT)(INT_PTR) RT_GROUP_CURSOR))
|
|
{
|
|
pType->typeord = (USHORT)(INT_PTR)RT_ANICURSOR;
|
|
}
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
pRes->size = GetAniIconsAniCursors(pRes->size);
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
|
|
pType->typeord = iLastTypeOrd;
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_BITMAP:
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
/* Bitmap in DIB format */
|
|
pRes ->size = GetNewBitmap();
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_GROUP_ICON:
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
if (FileIsAnimated(pRes->size)) {
|
|
goto ani;
|
|
} else {
|
|
if (fMacRsrcs)
|
|
GetMacIcon(pType, pRes);
|
|
else
|
|
GetNewIconsCursors(pType, pRes, RT_ICON);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_GROUP_CURSOR:
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
if (FileIsAnimated(pRes->size)) {
|
|
goto ani;
|
|
} else {
|
|
if (fMacRsrcs)
|
|
GetMacCursor(pType, pRes);
|
|
else
|
|
GetNewIconsCursors(pType, pRes, RT_CURSOR);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_FONT:
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
pRes->size = GetFileName();
|
|
if (pRes->name)
|
|
ParseError1(2143);
|
|
if (AddFontRes(pRes)) {
|
|
nFontsRead++;
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_FONTDIR:
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
fFontDirRead = TRUE;
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_MESSAGETABLE:
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
SaveResFile(pType, pRes);
|
|
}
|
|
break;
|
|
|
|
case (INT_PTR)RT_VERSION:
|
|
VersionParse();
|
|
SaveResFile(pType, pRes);
|
|
break;
|
|
|
|
case (INT_PTR)RT_DLGINCLUDE:
|
|
DlgIncludeParse(pRes);
|
|
SaveResFile(pType, pRes);
|
|
break;
|
|
|
|
case (INT_PTR)RT_TOOLBAR:
|
|
GetToolbar(pRes);
|
|
SaveResFile(pType, pRes);
|
|
break;
|
|
|
|
case (INT_PTR)RT_RCDATA:
|
|
case (INT_PTR)RT_DLGINIT:
|
|
default:
|
|
if (token.type != BEGIN) {
|
|
pRes->size = GetFileName();
|
|
if (pRes->size) {
|
|
WriteFileInfo(pRes, pType, tokenbuf);
|
|
}
|
|
} else {
|
|
RESINFO_PARSE rip;
|
|
|
|
bExternParse = FALSE;
|
|
|
|
// Check to see if caller wants to parse this.
|
|
if ((lpfnParseCallbackA != 0) || (lpfnParseCallbackW != 0)) {
|
|
rip.size = 0L;
|
|
rip.type = pType->type;
|
|
rip.typeord = pType->typeord;
|
|
rip.name = pRes->name;
|
|
rip.nameord = pRes->nameord;
|
|
rip.flags = pRes->flags;
|
|
rip.language = pRes->language;
|
|
rip.version = pRes->version;
|
|
rip.characteristics = pRes->characteristics;
|
|
|
|
if (lpfnParseCallbackW != 0) {
|
|
bExternParse = (*lpfnParseCallbackW)(&rip, NULL, NULL);
|
|
} else {
|
|
bExternParse = (*lpfnParseCallbackA)(&rip, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
if (!bExternParse) {
|
|
GetRCData(pRes);
|
|
} else {
|
|
union {
|
|
CONTEXTINFO_PARSE cipA;
|
|
CONTEXTINFO_PARSEW cipW;
|
|
} cip;
|
|
|
|
extern PCHAR CodeArray;
|
|
extern int CodeSize;
|
|
extern int CCount;
|
|
|
|
int nBegins = 1;
|
|
int nCountSave; // CCount before END token reached
|
|
|
|
cip.cipW.hHeap = hHeap;
|
|
cip.cipW.hWndCaller = hWndCaller;
|
|
cip.cipW.line = token.row;
|
|
|
|
// Collect data for caller to parse.
|
|
while(nBegins > 0) {
|
|
nCountSave = CCount;
|
|
GetToken(FALSE);
|
|
|
|
if (token.type == BEGIN) {
|
|
nBegins++;
|
|
} else if (token.type == END) {
|
|
nBegins--;
|
|
}
|
|
}
|
|
|
|
bExternParse = FALSE;
|
|
|
|
if ((rip.size = nCountSave) > 0) {
|
|
BOOL b;
|
|
|
|
if (lpfnParseCallbackW != 0) {
|
|
wchar_t mbuff[512]; // REVIEW: Long filenames?? See error.c also.
|
|
|
|
cip.cipW.lpfnMsg = lpfnMessageCallbackW;
|
|
|
|
swprintf(mbuff, L"%s(%%d) : %%s", curFile);
|
|
cip.cipW.format = mbuff;
|
|
|
|
b = (*lpfnParseCallbackW)(&rip, (void **) &CodeArray, &cip.cipW);
|
|
} else {
|
|
char mbuff[512]; // REVIEW: Long filenames?? See error.c also.
|
|
|
|
cip.cipA.lpfnMsg = lpfnMessageCallbackA;
|
|
|
|
sprintf(mbuff, "%S(%%d) : %%s", curFile);
|
|
cip.cipA.format = mbuff;
|
|
|
|
b = (*lpfnParseCallbackA)(&rip, (void **) &CodeArray, &cip.cipA);
|
|
}
|
|
|
|
if (!b) {
|
|
// Assume caller gave error message, and quit.
|
|
|
|
quit(NULL);
|
|
}
|
|
}
|
|
|
|
pRes->size = CCount = CodeSize = rip.size;
|
|
}
|
|
}
|
|
|
|
SaveResFile(pType, pRes);
|
|
break;
|
|
}
|
|
// write out end of new resource
|
|
WriteResInfo(NULL, NULL, FALSE);
|
|
}
|
|
} while (token.type != EOFMARK);
|
|
|
|
/* if we added fonts without a font directory, add one */
|
|
if (!fFontDirRead && nFontsRead)
|
|
AddFontDir();
|
|
|
|
/* write string table */
|
|
if (pResString != NULL)
|
|
WriteTable(pResString);
|
|
|
|
/* write Mac resource map */
|
|
if (fMacRsrcs)
|
|
WriteMacMap();
|
|
|
|
CtlFree();
|
|
|
|
if (fVerbose) {
|
|
wprintf(L"\n");
|
|
}
|
|
return(errorCount == 0);
|
|
}
|
|
|
|
|
|
WORD
|
|
GetLanguage()
|
|
{
|
|
WORD L_language;
|
|
|
|
GetToken(FALSE);
|
|
if (token.type != NUMLIT) {
|
|
ParseError1(2144);
|
|
return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
}
|
|
if (token.flongval) {
|
|
ParseError1(2145);
|
|
return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
}
|
|
L_language = token.val;
|
|
GetToken(FALSE);
|
|
if (token.type != COMMA) {
|
|
ParseError1(2146);
|
|
return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
}
|
|
GetToken(FALSE);
|
|
if (token.type != NUMLIT) {
|
|
ParseError1(2147);
|
|
return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
}
|
|
if (token.flongval) {
|
|
ParseError1(2148);
|
|
return MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
|
|
}
|
|
|
|
return MAKELANGID(L_language, token.val);
|
|
}
|