1452 lines
41 KiB
C
1452 lines
41 KiB
C
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* RCTP.C - */
|
||
|
/* */
|
||
|
/* Windows 3.0 Resource Compiler - Resource Parser */
|
||
|
/* */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
|
||
|
#include "rc.h"
|
||
|
|
||
|
|
||
|
static BOOL fComma;
|
||
|
|
||
|
/* Dialog template format :
|
||
|
|
||
|
dialogName DIALOGEX x, y, cx, cy [, helpID]
|
||
|
[style ...]
|
||
|
[exStyle ...]
|
||
|
[FONT height, name [, [weight] [, [italic [, [charset]]]]]]
|
||
|
[caption ...]
|
||
|
[menu ...]
|
||
|
[memFlags [pure] [discard n] [preload]]
|
||
|
BEGIN
|
||
|
[CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
|
||
|
[FONT height, name [, [weight] [, [italic]]]]
|
||
|
[BEGIN
|
||
|
data-element-1 [,
|
||
|
data-element-2 [,
|
||
|
... ]]
|
||
|
END]
|
||
|
|
||
|
[LTEXT "text", id, x, y, cx, cy]
|
||
|
[RTEXT "text", id, x, y, cx, cy]
|
||
|
[CTEXT "text", id, x, y, cx, cy]
|
||
|
|
||
|
[AUTO3STATE "text", id, x, y, cx, cy]
|
||
|
[AUTOCHECKBOX "text", id, x, y, cx, cy]
|
||
|
[AUTORADIOBUTTON "text", id, x, y, cx, cy]
|
||
|
[CHECKBOX "text", id, x, y, cx, cy]
|
||
|
[PUSHBOX "text", id, x, y, cx, cy]
|
||
|
[PUSHBUTTON "text", id, x, y, cx, cy]
|
||
|
[RADIOBUTTON "text", id, x, y, cx, cy]
|
||
|
[STATE3 "text", id, x, y, cx, cy]
|
||
|
[USERBUTTON "text", id, x, y, cx, cy]
|
||
|
|
||
|
[EDITTEXT id, x, y, cx, cy]
|
||
|
[BEDIT id, x, y, cx, cy]
|
||
|
[HEDIT id, x, y, cx, cy]
|
||
|
[IEDIT id, x, y, cx, cy]
|
||
|
...
|
||
|
END
|
||
|
|
||
|
MenuName MENUEX
|
||
|
BEGIN
|
||
|
[MENUITEM "text" [, [id] [, [type] [, [state]]]]]
|
||
|
[POPUP "text" [, [id] [, [type] [, [state] [, [help id]]]]]
|
||
|
BEGIN
|
||
|
[MENUITEM "text" [, [id] [, [type] [, [state]]]]]
|
||
|
...
|
||
|
END]
|
||
|
...
|
||
|
END
|
||
|
|
||
|
Menu template format
|
||
|
|
||
|
MenuName MENU
|
||
|
BEGIN
|
||
|
[MENUITEM "text", id [option, ...]]
|
||
|
[POPUP "text" [, option, ...]
|
||
|
BEGIN
|
||
|
[MENUITEM "text", id [option, ...]]
|
||
|
...
|
||
|
END ]
|
||
|
...
|
||
|
END
|
||
|
*/
|
||
|
|
||
|
/* Dialog template format :
|
||
|
|
||
|
dialogname DIALOG x, y, cx, cy
|
||
|
[language ...]
|
||
|
[style ...]
|
||
|
[caption ... ]
|
||
|
[menu ... ]
|
||
|
[memflags [pure] [discard n] [preload]]
|
||
|
begin
|
||
|
[CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
|
||
|
|
||
|
[LTEXT "text", id, x, y, cx, cy]
|
||
|
[RTEXT "text", id, x, y, cx, cy]
|
||
|
[CTEXT "text", id, x, y, cx, cy]
|
||
|
|
||
|
[CHECKBOX "text", id, x, y, cx, cy]
|
||
|
[PUSHBUTTON "text", id, x, y, cx, cy]
|
||
|
[RADIOBUTTON "text", id, x, y, cx, cy]
|
||
|
|
||
|
[EDITTEXT id, x, y, cx, cy]
|
||
|
...
|
||
|
end
|
||
|
|
||
|
Menu template format
|
||
|
|
||
|
MenuName MENU
|
||
|
BEGIN
|
||
|
[MENUITEM "text", id [option, ...]]
|
||
|
[POPUP "text" [, option, ...]
|
||
|
BEGIN
|
||
|
[MENUITEM "text", id [option, ...]]
|
||
|
...
|
||
|
END ]
|
||
|
...
|
||
|
END
|
||
|
*/
|
||
|
|
||
|
|
||
|
#define CTLSTYLE(s) (WS_CHILD | WS_VISIBLE | (s))
|
||
|
|
||
|
/* list of control id's to check for duplicates */
|
||
|
PDWORD pid;
|
||
|
int cidMac;
|
||
|
int cidMax;
|
||
|
|
||
|
BOOL
|
||
|
CheckStr(
|
||
|
PWCHAR pStr
|
||
|
)
|
||
|
{
|
||
|
if (token.type == STRLIT || token.type == LSTRLIT) {
|
||
|
if (token.val > MAXTOKSTR-1) {
|
||
|
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(4208), curFile, token.row);
|
||
|
SendError(Msg_Text);
|
||
|
tokenbuf[MAXTOKSTR-1] = TEXT('\0');
|
||
|
token.val = MAXTOKSTR-2;
|
||
|
}
|
||
|
memcpy(pStr, tokenbuf, (token.val+1)*sizeof(WCHAR));
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// GetDlgValue
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
SHORT
|
||
|
GetDlgValue(
|
||
|
void
|
||
|
)
|
||
|
{
|
||
|
SHORT sVal;
|
||
|
|
||
|
if (!GetFullExpression(&sVal, GFE_ZEROINIT | GFE_SHORT))
|
||
|
ParseError1(2109); //"Expected Numerical Dialog constant"
|
||
|
|
||
|
return(sVal);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
GetCoords(
|
||
|
PSHORT x,
|
||
|
PSHORT y,
|
||
|
PSHORT cx,
|
||
|
PSHORT cy
|
||
|
)
|
||
|
{
|
||
|
*x = GetDlgValue();
|
||
|
if (token.type == COMMA)
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
*y = GetDlgValue();
|
||
|
if (token.type == COMMA)
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
*cx= GetDlgValue();
|
||
|
if (token.type == COMMA)
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
*cy= GetDlgValue();
|
||
|
}
|
||
|
|
||
|
typedef struct tagCTRLTYPE {
|
||
|
WORD type;
|
||
|
DWORD dwStyle;
|
||
|
BYTE bCode;
|
||
|
BYTE fHasText;
|
||
|
} CTRLTYPE;
|
||
|
|
||
|
CTRLTYPE ctrlTypes[] = {
|
||
|
{ TKGROUPBOX, BS_GROUPBOX, BUTTONCODE, TRUE },
|
||
|
{ TKPUSHBUTTON, BS_PUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKDEFPUSHBUTTON, BS_DEFPUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKCHECKBOX, BS_CHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKRADIOBUTTON, BS_RADIOBUTTON, BUTTONCODE, TRUE },
|
||
|
{ TKAUTO3, BS_AUTO3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKAUTOCHECK, BS_AUTOCHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKAUTORADIO, BS_AUTORADIOBUTTON, BUTTONCODE, TRUE },
|
||
|
{ TKPUSHBOX, BS_PUSHBOX | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TK3STATE, BS_3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKUSERBUTTON, BS_USERBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
|
||
|
{ TKLTEXT, ES_LEFT | WS_GROUP, STATICCODE, TRUE },
|
||
|
{ TKRTEXT, ES_RIGHT | WS_GROUP, STATICCODE, TRUE },
|
||
|
{ TKCTEXT, ES_CENTER | WS_GROUP, STATICCODE, TRUE },
|
||
|
{ TKICON, SS_ICON, STATICCODE, TRUE },
|
||
|
{ TKBEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
|
||
|
{ TKHEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
|
||
|
{ TKIEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
|
||
|
{ TKEDITTEXT, ES_LEFT | WS_BORDER | WS_TABSTOP, EDITCODE, FALSE },
|
||
|
{ TKLISTBOX, WS_BORDER | LBS_NOTIFY, LISTBOXCODE, FALSE },
|
||
|
{ TKCOMBOBOX, 0, COMBOBOXCODE, FALSE },
|
||
|
{ TKSCROLLBAR, 0, SCROLLBARCODE, FALSE }
|
||
|
};
|
||
|
|
||
|
#define C_CTRLTYPES (sizeof(ctrlTypes) / sizeof(CTRLTYPE))
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// GetDlgItems(fDlgEx) -
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
int
|
||
|
GetDlgItems(
|
||
|
BOOL fDlgEx
|
||
|
)
|
||
|
{
|
||
|
CTRL ctrl;
|
||
|
int i;
|
||
|
|
||
|
cidMac = 0;
|
||
|
cidMax = 100;
|
||
|
pid = (PDWORD) MyAlloc(sizeof(DWORD)*cidMax);
|
||
|
if (!pid)
|
||
|
return FALSE;
|
||
|
|
||
|
GetToken(TRUE);
|
||
|
|
||
|
/* read all the controls in the dialog */
|
||
|
|
||
|
ctrl.id = 0L; // initialize the control's id to 0
|
||
|
|
||
|
while (token.type != END) {
|
||
|
ctrl.dwHelpID = 0L;
|
||
|
ctrl.dwExStyle = 0L;
|
||
|
ctrl.dwStyle = WS_CHILD | WS_VISIBLE;
|
||
|
ctrl.text[0] = 0;
|
||
|
ctrl.fOrdinalText = FALSE;
|
||
|
|
||
|
if (token.type == TKCONTROL) {
|
||
|
ParseCtl(&ctrl, fDlgEx);
|
||
|
} else {
|
||
|
for (i = 0; i < C_CTRLTYPES; i++)
|
||
|
if (token.type == ctrlTypes[i].type)
|
||
|
break;
|
||
|
|
||
|
if (i == C_CTRLTYPES) {
|
||
|
ParseError1(2111); //"Invalid Control type : ", tokenbuf
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
ctrl.dwStyle |= ctrlTypes[i].dwStyle;
|
||
|
if (fMacRsrcs &&
|
||
|
(token.type == TKPUSHBUTTON ||
|
||
|
token.type == TKDEFPUSHBUTTON ||
|
||
|
token.type == TKCHECKBOX ||
|
||
|
token.type == TKAUTO3 ||
|
||
|
token.type == TKAUTOCHECK ||
|
||
|
token.type == TKPUSHBOX ||
|
||
|
token.type == TK3STATE ||
|
||
|
token.type == TKUSERBUTTON))
|
||
|
{
|
||
|
ctrl.dwStyle &= ~WS_TABSTOP;
|
||
|
}
|
||
|
if (ctrlTypes[i].bCode) {
|
||
|
ctrl.Class[0] = 0xFFFF;
|
||
|
ctrl.Class[1] = ctrlTypes[i].bCode;
|
||
|
} else {
|
||
|
CheckStr(ctrl.Class);
|
||
|
}
|
||
|
|
||
|
if (ctrlTypes[i].fHasText)
|
||
|
GetCtlText(&ctrl);
|
||
|
|
||
|
// find the ID and the coordinates
|
||
|
GetCtlID(&ctrl, fDlgEx);
|
||
|
GetCoords(&ctrl.x, &ctrl.y, &ctrl.cx, &ctrl.cy);
|
||
|
|
||
|
// get optional style, exstyle, and helpid
|
||
|
if (token.type == COMMA) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&ctrl.dwStyle, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (token.type == COMMA) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&ctrl.dwExStyle, 0);
|
||
|
|
||
|
if (fDlgEx && (token.type == COMMA)) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&ctrl.dwHelpID, GFE_ZEROINIT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SetUpItem(&ctrl, fDlgEx); /* gen the code for it */
|
||
|
|
||
|
if (fDlgEx && (token.type == BEGIN)) {
|
||
|
/* align any CreateParams are there */
|
||
|
//WriteAlign(); not yet!!!
|
||
|
|
||
|
// we're ok passing NULL in for pRes here because PreBeginParse
|
||
|
// won't have to use pRes
|
||
|
// Note that passing fDlgEx is actually redundant since it
|
||
|
// will always be TRUE here, but we'll do it in case someone
|
||
|
// else ever calls SetItemExtraCount
|
||
|
SetItemExtraCount(GetRCData(NULL), fDlgEx);
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
}
|
||
|
}
|
||
|
MyFree(pid);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetDlg() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
int
|
||
|
GetDlg(
|
||
|
PRESINFO pRes,
|
||
|
PDLGHDR pDlg,
|
||
|
BOOL fDlgEx
|
||
|
)
|
||
|
{
|
||
|
/* initialize and defaults */
|
||
|
pDlg->dwExStyle = pRes->exstyleT;
|
||
|
pDlg->dwStyle = WS_POPUPWINDOW | WS_SYSMENU;
|
||
|
pDlg->MenuName[0] = 0;
|
||
|
pDlg->Title[0] = 0;
|
||
|
pDlg->Class[0] = 0;
|
||
|
pDlg->fOrdinalMenu = FALSE;
|
||
|
pDlg->fClassOrdinal = FALSE;
|
||
|
pDlg->pointsize = 0;
|
||
|
|
||
|
// get x, y, cx, cy
|
||
|
GetCoords(&pDlg->x, &pDlg->y, &pDlg->cx, &pDlg->cy);
|
||
|
|
||
|
/* get optional parameters */
|
||
|
if (!DLexOptionalArgs(pRes, pDlg, fDlgEx))
|
||
|
return FALSE;
|
||
|
|
||
|
if (pDlg->pointsize)
|
||
|
pDlg->dwStyle |= DS_SETFONT;
|
||
|
else
|
||
|
pDlg->dwStyle &= ~DS_SETFONT;
|
||
|
|
||
|
/* output header to the resource buffer */
|
||
|
SetUpDlg(pDlg, fDlgEx);
|
||
|
|
||
|
/* make sure we have a BEGIN */
|
||
|
if (token.type != BEGIN)
|
||
|
ParseError1(2112); //"BEGIN expected in Dialog"
|
||
|
|
||
|
/* get the dialog items */
|
||
|
GetDlgItems(fDlgEx);
|
||
|
|
||
|
if (fMacRsrcs)
|
||
|
SwapItemCount();
|
||
|
|
||
|
/* make sure this ended on an END */
|
||
|
if (token.type != END)
|
||
|
ParseError1(2113); //"END expected in Dialog"
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
typedef struct tagCTRLNAME {
|
||
|
BYTE bCode;
|
||
|
WORD wType;
|
||
|
PWCHAR pszName;
|
||
|
} CTRLNAME;
|
||
|
|
||
|
CTRLNAME ctrlNames[] = {
|
||
|
{ BUTTONCODE, TKBUTTON, L"button" },
|
||
|
{ EDITCODE, TKEDIT, L"edit" },
|
||
|
{ STATICCODE, TKSTATIC, L"static" },
|
||
|
{ LISTBOXCODE, TKLISTBOX, L"listbox" },
|
||
|
{ SCROLLBARCODE, TKSCROLLBAR, L"scrollbar" },
|
||
|
{ COMBOBOXCODE, TKCOMBOBOX, L"combobox" }
|
||
|
};
|
||
|
|
||
|
#define C_CTRLNAMES (sizeof(ctrlNames) / sizeof(CTRLNAME))
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ParseCtl() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
// for a control of the form CTL
|
||
|
|
||
|
void
|
||
|
ParseCtl(
|
||
|
PCTRL LocCtl,
|
||
|
BOOL fDlgEx
|
||
|
)
|
||
|
{ /* by now we've read the CTL */
|
||
|
int i;
|
||
|
|
||
|
/* get the control text and identifier */
|
||
|
GetCtlText(LocCtl);
|
||
|
GetCtlID(LocCtl, fDlgEx);
|
||
|
|
||
|
if (token.type == NUMLIT) {
|
||
|
LocCtl->Class[0] = (char) token.val;
|
||
|
LocCtl->Class[1] = 0;
|
||
|
} else if (token.type == LSTRLIT) {
|
||
|
// We will now convert class name strings to short form magic
|
||
|
// numbers. These magic numbers are order dependent as defined in
|
||
|
// USER. This provides some space savings in resource files.
|
||
|
for (i = C_CTRLNAMES; i; ) {
|
||
|
if (!_wcsicmp(tokenbuf, ctrlNames[--i].pszName))
|
||
|
goto Found1;
|
||
|
}
|
||
|
CheckStr(LocCtl->Class);
|
||
|
} else {
|
||
|
for (i = C_CTRLNAMES; i; ) {
|
||
|
if (token.type == ctrlNames[--i].wType)
|
||
|
goto Found1;
|
||
|
}
|
||
|
ParseError1(2114); //"Expected control class name"
|
||
|
|
||
|
Found1:
|
||
|
LocCtl->Class[0] = 0xFFFF;
|
||
|
LocCtl->Class[1] = ctrlNames[i].bCode;
|
||
|
}
|
||
|
|
||
|
/* get the style bits */
|
||
|
GetTokenNoComma(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&LocCtl->dwStyle, 0);
|
||
|
|
||
|
/* get the coordinates of the control */
|
||
|
ICGetTok();
|
||
|
GetCoords(&LocCtl->x, &LocCtl->y, &LocCtl->cx, &LocCtl->cy);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetCtlText() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
GetCtlText(
|
||
|
PCTRL pLocCtl
|
||
|
)
|
||
|
{
|
||
|
GetTokenNoComma(TOKEN_NOEXPRESSION);
|
||
|
if (CheckStr(pLocCtl->text)) {
|
||
|
pLocCtl->fOrdinalText = FALSE;
|
||
|
token.sym.name[0] = L'\0';
|
||
|
token.sym.nID = 0;
|
||
|
} else if (token.type == NUMLIT) {
|
||
|
wcsitow(token.val, pLocCtl->text, 10);
|
||
|
pLocCtl->fOrdinalText = TRUE;
|
||
|
WriteSymbolUse(&token.sym);
|
||
|
} else {
|
||
|
ParseError1(2115); //"Text string or ordinal expected in Control"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetCtlID() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
GetCtlID(
|
||
|
PCTRL pLocCtl,
|
||
|
BOOL fDlgEx
|
||
|
)
|
||
|
{
|
||
|
WORD wGFE = GFE_ZEROINIT;
|
||
|
int i;
|
||
|
|
||
|
ICGetTok();
|
||
|
|
||
|
WriteSymbolUse(&token.sym);
|
||
|
|
||
|
if (!fDlgEx)
|
||
|
wGFE |= GFE_SHORT;
|
||
|
|
||
|
if (GetFullExpression(&pLocCtl->id, wGFE)) {
|
||
|
if (!fDlgEx && pLocCtl->id != (DWORD)(WORD)-1 ||
|
||
|
fDlgEx && pLocCtl->id != (DWORD)-1) {
|
||
|
for (i=0 ; i<cidMac ; i++) {
|
||
|
if (pLocCtl->id == *(pid+i) && !fSkipDuplicateCtlIdWarning) {
|
||
|
i = (int)pLocCtl->id;
|
||
|
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(2182),
|
||
|
curFile, token.row, i);
|
||
|
SendError(Msg_Text);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (cidMac == cidMax) {
|
||
|
PDWORD pidNew;
|
||
|
|
||
|
cidMax += 100;
|
||
|
pidNew = (PDWORD) MyAlloc(cidMax*sizeof(DWORD));
|
||
|
memcpy(pidNew, pid, cidMac*sizeof(DWORD));
|
||
|
MyFree(pid);
|
||
|
pid = pidNew;
|
||
|
}
|
||
|
*(pid+cidMac++) = pLocCtl->id;
|
||
|
}
|
||
|
} else {
|
||
|
ParseError1(2116); //"Expecting number for ID"
|
||
|
}
|
||
|
|
||
|
if (token.type == COMMA)
|
||
|
ICGetTok();
|
||
|
}
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DLexOptionArgs(pRes, fDlgEx) -
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
BOOL
|
||
|
DLexOptionalArgs(
|
||
|
PRESINFO pRes,
|
||
|
PDLGHDR pDlg,
|
||
|
BOOL fDlgEx
|
||
|
)
|
||
|
{
|
||
|
/* read all the optional dialog items */
|
||
|
|
||
|
if (fDlgEx && (token.type == COMMA)) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&pDlg->dwHelpID, GFE_ZEROINIT);
|
||
|
}
|
||
|
|
||
|
while (token.type != BEGIN) {
|
||
|
switch (token.type) {
|
||
|
case TKLANGUAGE:
|
||
|
pRes->language = GetLanguage();
|
||
|
GetToken(FALSE);
|
||
|
break;
|
||
|
|
||
|
case TKVERSION:
|
||
|
GetToken(FALSE);
|
||
|
if (token.type != NUMLIT)
|
||
|
ParseError1(2139);
|
||
|
pRes->version = token.longval;
|
||
|
GetToken(FALSE);
|
||
|
break;
|
||
|
|
||
|
case TKCHARACTERISTICS:
|
||
|
GetToken(FALSE);
|
||
|
if (token.type != NUMLIT)
|
||
|
ParseError1(2140);
|
||
|
pRes->characteristics = token.longval;
|
||
|
GetToken(FALSE);
|
||
|
break;
|
||
|
|
||
|
case TKSTYLE:
|
||
|
// If CAPTION statement preceded STYLE statement, then we
|
||
|
// already must have WS_CAPTION bits set in the "style"
|
||
|
// field and we must not lose it;
|
||
|
|
||
|
if ((pDlg->dwStyle & WS_CAPTION) == WS_CAPTION)
|
||
|
pDlg->dwStyle = WS_CAPTION;
|
||
|
else
|
||
|
pDlg->dwStyle = 0;
|
||
|
|
||
|
GetTokenNoComma(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&pDlg->dwStyle, 0);
|
||
|
break;
|
||
|
|
||
|
case TKEXSTYLE:
|
||
|
GetTokenNoComma(TOKEN_NOEXPRESSION);
|
||
|
GetFullExpression(&pDlg->dwExStyle, 0);
|
||
|
break;
|
||
|
|
||
|
case TKCAPTION:
|
||
|
DGetTitle(pDlg);
|
||
|
break;
|
||
|
|
||
|
case TKMENU:
|
||
|
DGetMenuName(pDlg);
|
||
|
break;
|
||
|
|
||
|
case TKCLASS:
|
||
|
DGetClassName(pDlg);
|
||
|
break;
|
||
|
|
||
|
case TKFONT:
|
||
|
DGetFont(pDlg, fDlgEx);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ParseError1(2112); //"BEGIN expected in dialog");
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* DGetFont() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
void
|
||
|
DGetFont(
|
||
|
PDLGHDR pDlg,
|
||
|
BOOL fDlgEx
|
||
|
)
|
||
|
{
|
||
|
WORD w;
|
||
|
int i;
|
||
|
|
||
|
GetToken(TRUE);
|
||
|
if (!GetFullExpression(&pDlg->pointsize, GFE_ZEROINIT | GFE_SHORT))
|
||
|
ParseError1(2117); //"Expected numeric point size"
|
||
|
|
||
|
if (token.type == COMMA)
|
||
|
ICGetTok();
|
||
|
|
||
|
if (!CheckStr(pDlg->Font))
|
||
|
ParseError1(2118); //"Expected font face name"
|
||
|
|
||
|
if (_wcsicmp(pDlg->Font, L"System") &&
|
||
|
szSubstituteFontName[0] != UNICODE_NULL) {
|
||
|
for (i=0; i<nBogusFontNames; i++) {
|
||
|
if (!_wcsicmp(pszBogusFontNames[i], pDlg->Font)) {
|
||
|
GenWarning4(4510, (PCHAR)pDlg->Font, (PCHAR)szSubstituteFontName, 0 ); // Warning for hard coded fonts
|
||
|
wcscpy(pDlg->Font, szSubstituteFontName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GetToken(TRUE);
|
||
|
|
||
|
pDlg->bCharSet = DEFAULT_CHARSET;
|
||
|
|
||
|
if (fDlgEx && (token.type == COMMA)) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
if (GetFullExpression(&w, GFE_ZEROINIT | GFE_SHORT))
|
||
|
pDlg->wWeight = w;
|
||
|
|
||
|
if (token.type == COMMA) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
if (token.type == NUMLIT) {
|
||
|
pDlg->bItalic = (token.val) ? TRUE : FALSE;
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
|
||
|
if (token.type == COMMA) {
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
if (GetFullExpression(&w, GFE_ZEROINIT | GFE_SHORT))
|
||
|
pDlg->bCharSet = (UCHAR) w;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* DGetMenuName() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
/* gets the unquoted string of the name of the optional menu associated */
|
||
|
/* with the dialog. */
|
||
|
|
||
|
VOID
|
||
|
DGetMenuName(
|
||
|
PDLGHDR pDlg
|
||
|
)
|
||
|
{
|
||
|
if (GetGenText()) {
|
||
|
/* copy the menu name */
|
||
|
token.type = LSTRLIT;
|
||
|
CheckStr(pDlg->MenuName);
|
||
|
|
||
|
/* check if menu name is an ordinal */
|
||
|
if (wcsdigit(pDlg->MenuName[0]))
|
||
|
pDlg->fOrdinalMenu = TRUE;
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* DGetTitle() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
DGetTitle(
|
||
|
PDLGHDR pDlg
|
||
|
)
|
||
|
{
|
||
|
GetToken(TRUE);
|
||
|
|
||
|
if (CheckStr(pDlg->Title))
|
||
|
pDlg->dwStyle |= WS_CAPTION;
|
||
|
else
|
||
|
ParseError1(2119); //"Expecting quoted string in dialog title"
|
||
|
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* DGetClassName() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
DGetClassName(
|
||
|
PDLGHDR pDlg
|
||
|
)
|
||
|
{
|
||
|
GetToken(TRUE);
|
||
|
if (!CheckStr(pDlg->Class)) {
|
||
|
if (token.type == NUMLIT) {
|
||
|
wcsitow(token.val, pDlg->Class, 10);
|
||
|
pDlg->fClassOrdinal = TRUE;
|
||
|
} else {
|
||
|
ParseError1(2120); //"Expecting quoted string in dialog class"
|
||
|
}
|
||
|
}
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* Gets a token, ignoring commas. Returns the token type. */
|
||
|
/* */
|
||
|
/* ICGetTok() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Get token, but ignore commas */
|
||
|
|
||
|
USHORT
|
||
|
ICGetTok(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
fComma = FALSE; // NT added the use of this fComma flag
|
||
|
GetToken(TRUE);
|
||
|
while (token.type == COMMA) {
|
||
|
GetToken(TRUE);
|
||
|
fComma = TRUE; // and they set it here
|
||
|
}
|
||
|
return (USHORT)token.type;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* GetTokenNoComma
|
||
|
* This function replaces ICGetTok() but has a flag to support
|
||
|
* the turning off of expression parsing.
|
||
|
*/
|
||
|
|
||
|
USHORT
|
||
|
GetTokenNoComma(
|
||
|
USHORT wFlags
|
||
|
)
|
||
|
{
|
||
|
/* Get a token */
|
||
|
GetToken(TRUE | wFlags);
|
||
|
|
||
|
/* Ignore any commas */
|
||
|
while (token.type == COMMA)
|
||
|
GetToken(TRUE | wFlags);
|
||
|
|
||
|
return (USHORT)token.type;
|
||
|
}
|
||
|
|
||
|
|
||
|
/************* Menu Parsing Routines *********************/
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* IsmnOption() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
int
|
||
|
IsmnOption(
|
||
|
UINT arg,
|
||
|
PMENUITEM pmn
|
||
|
)
|
||
|
{
|
||
|
/* if we have a valid flag, or it into the menu flags */
|
||
|
switch (arg) {
|
||
|
case TKOWNERDRAW:
|
||
|
pmn->OptFlags |= OPOWNERDRAW;
|
||
|
break;
|
||
|
|
||
|
case TKCHECKED:
|
||
|
pmn->OptFlags |= OPCHECKED;
|
||
|
break;
|
||
|
|
||
|
case TKGRAYED:
|
||
|
pmn->OptFlags |= OPGRAYED;
|
||
|
break;
|
||
|
|
||
|
case TKINACTIVE:
|
||
|
pmn->OptFlags |= OPINACTIVE;
|
||
|
break;
|
||
|
|
||
|
case TKBREAKWBAR:
|
||
|
pmn->OptFlags |= OPBREAKWBAR;
|
||
|
break;
|
||
|
|
||
|
case TKBREAK:
|
||
|
pmn->OptFlags |= OPBREAK;
|
||
|
break;
|
||
|
|
||
|
case TKHELP:
|
||
|
pmn->OptFlags |= OPHELP;
|
||
|
break;
|
||
|
|
||
|
case TKBITMAP:
|
||
|
pmn->OptFlags |= OPBITMAP;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return(FALSE);
|
||
|
}
|
||
|
return(TRUE);
|
||
|
|
||
|
#if 0
|
||
|
if ((arg == OPBREAKWBAR) || (arg == OPHELP ) || (arg == OPGRAYED) ||
|
||
|
(arg == OPUSECHECKBITMAPS) || (arg == OPCHECKED) || (arg == OPBITMAP) ||
|
||
|
(arg == OPOWNERDRAW) || (arg == OPBREAK ) || (arg == OPINACTIVE))
|
||
|
{
|
||
|
pmn->OptFlags |= arg;
|
||
|
return TRUE;
|
||
|
}
|
||
|
#if 0
|
||
|
if (arg == OPHELP) {
|
||
|
pmn->OptFlags |= OPPOPHELP;
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|
||
|
return FALSE;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// ----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DoOldMenuItem() -
|
||
|
//
|
||
|
// ----------------------------------------------------------------------------
|
||
|
|
||
|
WORD
|
||
|
DoOldMenuItem(
|
||
|
int fPopup
|
||
|
)
|
||
|
{
|
||
|
MENUITEM mnTemp;
|
||
|
|
||
|
mnTemp.PopFlag = (UCHAR)fPopup;
|
||
|
GetToken(TRUE);
|
||
|
|
||
|
/* menu choice string */
|
||
|
if (CheckStr(mnTemp.szText)) {
|
||
|
mnTemp.OptFlags = OPPOPUP;
|
||
|
ICGetTok();
|
||
|
if (!fPopup) {
|
||
|
/* change the flag and get the ID if not a popup */
|
||
|
mnTemp.OptFlags = 0;
|
||
|
|
||
|
WriteSymbolUse(&token.sym);
|
||
|
if (!GetFullExpression(&mnTemp.id, GFE_ZEROINIT | GFE_SHORT))
|
||
|
ParseError1(2125); //"Expected ID value for Menuitem"
|
||
|
|
||
|
if (token.type == COMMA)
|
||
|
GetToken(TOKEN_NOEXPRESSION);
|
||
|
}
|
||
|
|
||
|
/* read the menu option flags */
|
||
|
while (IsmnOption(token.type, &mnTemp))
|
||
|
ICGetTok();
|
||
|
} else if (token.type == TKSEPARATOR) {
|
||
|
mnTemp.szText[0] = 0; // MENUITEM SEPARATOR
|
||
|
mnTemp.id = 0;
|
||
|
mnTemp.OptFlags = 0;
|
||
|
ICGetTok();
|
||
|
} else {
|
||
|
ParseError1(2126); //"Expected Menu String"
|
||
|
}
|
||
|
|
||
|
/* set it up in the buffer (?) */
|
||
|
return(SetUpOldMenu(&mnTemp));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ParseOldMenu() - */
|
||
|
/* */
|
||
|
/*---------------------------------------------------------------------------*/
|
||
|
|
||
|
int
|
||
|
ParseOldMenu(
|
||
|
int fRecursing,
|
||
|
PRESINFO pRes // 8 char proc name limitation!
|
||
|
)
|
||
|
{
|
||
|
BOOL bItemRead = FALSE;
|
||
|
WORD wEndFlagLoc = 0;
|
||
|
|
||
|
if (!fRecursing) {
|
||
|
PreBeginParse(pRes, 2121);
|
||
|
} else {
|
||
|
/* make sure its really a menu */
|
||
|
if (token.type != BEGIN)
|
||
|
ParseError1(2121); //"BEGIN expected in menu"
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
|
||
|
/* get the individual menu items */
|
||
|
while (token.type != END) {
|
||
|
switch (token.type) {
|
||
|
case TKMENUITEM:
|
||
|
bItemRead = TRUE;
|
||
|
wEndFlagLoc = DoOldMenuItem(FALSE);
|
||
|
break;
|
||
|
|
||
|
case TKPOPUP:
|
||
|
bItemRead = TRUE;
|
||
|
wEndFlagLoc = DoOldMenuItem(TRUE);
|
||
|
ParseOldMenu(TRUE, pRes);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ParseError1(2122); //"Unknown Menu SubType :"
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* did we die on an END? */
|
||
|
if (token.type != END)
|
||
|
ParseError1(2123); //"END expected in menu"
|
||
|
|
||
|
/* make sure we have a menu item */
|
||
|
if (!bItemRead)
|
||
|
ParseError1(2124); //"Empty menus not allowed"
|
||
|
|
||
|
/* Get next token if this was NOT the last END*/
|
||
|
if (fRecursing)
|
||
|
GetToken(TRUE);
|
||
|
|
||
|
/* mark the last item in the menu */
|
||
|
FixOldMenuPatch(wEndFlagLoc);
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* ----- Version resource stuff ----- */
|
||
|
|
||
|
/* VersionParse
|
||
|
* Parses the VERSION resource and places it in the global buffer
|
||
|
* so it can be written out by SaveResFile().
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
VersionParse(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
int Index;
|
||
|
|
||
|
/* Get the fixed structure entries */
|
||
|
/* Note that VersionParseFixed doesn't actually fail! */
|
||
|
/* This is because VersionBlockStruct doesn't fail. */
|
||
|
Index = VersionParseFixed();
|
||
|
|
||
|
/* Put the following blocks in as sub-blocks. Fix up the length when
|
||
|
* we're done.
|
||
|
*/
|
||
|
SetItemCount(Index, (USHORT)(GetItemCount(Index) + VersionParseBlock()));
|
||
|
|
||
|
/* The return data buffer is global */
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* VersionParseFixed
|
||
|
* Parses the fixed portion of the version resource. Returns a pointer
|
||
|
* to the length word of the block. This word has the length of
|
||
|
* the fixed portion precomputed and remains to have the variable
|
||
|
* portion added in.
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
VersionParseFixed(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
VS_FIXEDFILEINFO FixedInfo;
|
||
|
|
||
|
/* Initialize the structure fields */
|
||
|
memset((PCHAR)&FixedInfo, 0, sizeof(FixedInfo));
|
||
|
FixedInfo.dwSignature = 0xfeef04bdL;
|
||
|
FixedInfo.dwStrucVersion = 0x00010000L;
|
||
|
FixedInfo.dwFileDateMS = 0L;
|
||
|
FixedInfo.dwFileDateLS = 0L;
|
||
|
|
||
|
/* Loop through tokens until we get the "BEGIN" token which
|
||
|
* must be present to terminate the fixed portion of the VERSIONINFO
|
||
|
* resource.
|
||
|
*/
|
||
|
while (token.type != BEGIN) {
|
||
|
switch (token.type) {
|
||
|
/* The following have four WORDS scrambled into two DWORDS */
|
||
|
case TKFILEVERSION:
|
||
|
VersionGet4Words(&FixedInfo.dwFileVersionMS);
|
||
|
break;
|
||
|
|
||
|
case TKPRODUCTVERSION:
|
||
|
VersionGet4Words(&FixedInfo.dwProductVersionMS);
|
||
|
break;
|
||
|
|
||
|
/* The following have just one DWORD */
|
||
|
case TKFILEFLAGSMASK:
|
||
|
VersionGetDWord(&FixedInfo.dwFileFlagsMask);
|
||
|
break;
|
||
|
|
||
|
case TKFILEFLAGS:
|
||
|
VersionGetDWord(&FixedInfo.dwFileFlags);
|
||
|
break;
|
||
|
|
||
|
case TKFILEOS:
|
||
|
VersionGetDWord(&FixedInfo.dwFileOS);
|
||
|
break;
|
||
|
|
||
|
case TKFILETYPE:
|
||
|
VersionGetDWord(&FixedInfo.dwFileType);
|
||
|
break;
|
||
|
|
||
|
case TKFILESUBTYPE:
|
||
|
VersionGetDWord(&FixedInfo.dwFileSubtype);
|
||
|
break;
|
||
|
|
||
|
/* Other tokens are unknown */
|
||
|
default:
|
||
|
ParseError1(2167); //"Unrecognized VERSIONINFO field;"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Write the block out and return the pointer to the length */
|
||
|
return VersionBlockStruct(L"VS_VERSION_INFO", (PCHAR)&FixedInfo,
|
||
|
sizeof(FixedInfo));
|
||
|
}
|
||
|
|
||
|
|
||
|
/* VersionGet4Words
|
||
|
* Reads a version number from the source file and scrambles them
|
||
|
* to fit in two DWORDs. We force them to put commas in here so
|
||
|
* that if they don't put in enough values we can fill in zeros.
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
VersionGet4Words(
|
||
|
ULONG *pdw
|
||
|
)
|
||
|
{
|
||
|
// static CHAR szParseError[] = "Version WORDs separated by commas expected";
|
||
|
|
||
|
/* Get the first number */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != NUMLIT || token.flongval)
|
||
|
ParseError1(2127); //szParseError
|
||
|
*pdw = ((LONG)token.val) << 16;
|
||
|
|
||
|
/* Get the comma. If none, we're done, so fill the rest with zeros */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != COMMA) {
|
||
|
*++pdw = 0L;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Get the second number */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != NUMLIT || token.flongval)
|
||
|
ParseError1(2127); //szParseError
|
||
|
*(PUSHORT)pdw = token.val;
|
||
|
|
||
|
/* Get the comma. If none, we're done, so fill the rest with zeros */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != COMMA) {
|
||
|
*++pdw = 0L;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/* Get the third number */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != NUMLIT || token.flongval)
|
||
|
ParseError1(2127); //szParseError
|
||
|
*++pdw = ((LONG)token.val) << 16;
|
||
|
|
||
|
/* Get the comma. If none, we're done */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != COMMA)
|
||
|
return;
|
||
|
|
||
|
/* Get the fourth number */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != NUMLIT || token.flongval)
|
||
|
ParseError1(2127); //szParseError
|
||
|
*(PUSHORT)pdw = token.val;
|
||
|
|
||
|
/* Get the next token for the loop */
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* VersionGetDWord
|
||
|
* Reads a single DWORD from the source file into the given variable.
|
||
|
*/
|
||
|
|
||
|
VOID
|
||
|
VersionGetDWord(
|
||
|
ULONG *pdw
|
||
|
)
|
||
|
{
|
||
|
/* Get the token */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != NUMLIT)
|
||
|
ParseError1(2128); //"DWORD expected"
|
||
|
*pdw = token.longval;
|
||
|
|
||
|
/* Get the next token for the loop */
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* VersionParseBlock
|
||
|
* Parses a block of version information. Note that this block may
|
||
|
* contain one or more additional blocks, causing this function to
|
||
|
* be called recursively. Returns the length of the block which can
|
||
|
* be added to the length of the current block. Returns 0xffff on error.
|
||
|
*/
|
||
|
|
||
|
USHORT
|
||
|
VersionParseBlock(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
USHORT wLen;
|
||
|
int IndexLen;
|
||
|
USHORT wType;
|
||
|
|
||
|
/* Get the current position in the buffer */
|
||
|
wLen = GetBufferLen();
|
||
|
|
||
|
/* The token has already been read. This should be a BEGIN */
|
||
|
if (token.type != BEGIN)
|
||
|
ParseError1(2129); //"BEGIN expected in VERSIONINFO resource"
|
||
|
|
||
|
/* Get the first token. From here on, the VersionBlockVariable()
|
||
|
* routine gets the tokens as it searches for the end of the value
|
||
|
* field.
|
||
|
*/
|
||
|
GetToken(TRUE);
|
||
|
|
||
|
/* Loop until we get to the END for this BEGIN */
|
||
|
for (; ; ) {
|
||
|
/* Get and decode the next line type */
|
||
|
switch (token.type) {
|
||
|
case TKVALUE:
|
||
|
case TKBLOCK:
|
||
|
/* Save the type of this token */
|
||
|
wType = token.type;
|
||
|
|
||
|
/* Get the key string */
|
||
|
GetToken(TRUE);
|
||
|
if (token.type != LSTRLIT)
|
||
|
ParseError1(2131); //"Expecting quoted string for key"
|
||
|
|
||
|
/* Now feed in the key string and value items */
|
||
|
IndexLen = VersionBlockVariable(tokenbuf);
|
||
|
|
||
|
/* A "BLOCK" item causes recursion. Current token should be
|
||
|
* "BEGIN"
|
||
|
*/
|
||
|
if (wType == TKBLOCK) {
|
||
|
SetItemCount(IndexLen, (USHORT)(GetItemCount(IndexLen) + VersionParseBlock()));
|
||
|
GetToken(TRUE);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case END:
|
||
|
/* We're done with this block. Get the next token
|
||
|
* (read past the "END") and return the length of the block.
|
||
|
*/
|
||
|
return GetBufferLen() - wLen;
|
||
|
|
||
|
default:
|
||
|
ParseError1(2132); //"Expected VALUE, BLOCK, or, END keyword."
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#define DWORDALIGN(w) \
|
||
|
(((w) + (sizeof(ULONG) - 1)) & ~(USHORT)(sizeof(ULONG) - 1))
|
||
|
|
||
|
/* VersionBlockStruct
|
||
|
* Writes a version block without sub-blocks. Sub-blocks are to
|
||
|
* be written directly after this header. To facilitate this,
|
||
|
* a pointer to the block length is returned so that it can be modified.
|
||
|
* This call uses a pre-parsed value item. Use VersionBlockVariable()
|
||
|
* to parse the value items instead.
|
||
|
* Note that this actually can't fail!
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
VersionBlockStruct(
|
||
|
PWCHAR pstrKey,
|
||
|
PCHAR pstrValue,
|
||
|
USHORT wLenValue
|
||
|
)
|
||
|
{
|
||
|
USHORT wLen;
|
||
|
int Index;
|
||
|
ULONG dwPadding = 0L;
|
||
|
USHORT wAlign;
|
||
|
|
||
|
/* Pad the block data to DWORD align */
|
||
|
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
|
||
|
if (wAlign)
|
||
|
WriteBuffer((PCHAR)&dwPadding, wAlign);
|
||
|
|
||
|
/* Save the current length so we can compute the new block length later */
|
||
|
wLen = GetBufferLen();
|
||
|
|
||
|
/* Write a zero for the length for now */
|
||
|
Index = GetBufferLen();
|
||
|
WriteWord(0);
|
||
|
|
||
|
/* Write the length of the value field */
|
||
|
WriteWord(wLenValue);
|
||
|
|
||
|
/* data is binary */
|
||
|
WriteWord(0);
|
||
|
|
||
|
/* Write the key string now */
|
||
|
WriteString(pstrKey, TRUE);
|
||
|
|
||
|
/* Write the value data if there is any */
|
||
|
if (wLenValue) {
|
||
|
/* Now we have to DWORD align the value data */
|
||
|
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
|
||
|
if (wAlign)
|
||
|
WriteBuffer((PSTR)&dwPadding, wAlign);
|
||
|
|
||
|
/* Write it to the buffer */
|
||
|
WriteBuffer((PSTR)pstrValue, wLenValue);
|
||
|
}
|
||
|
|
||
|
/* Now fix up the block length and return a pointer to it */
|
||
|
SetItemCount(Index, (USHORT)(GetBufferLen() - wLen));
|
||
|
|
||
|
return Index;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* VersionBlockVariable
|
||
|
* Writes a version block without sub-blocks. Sub-blocks are to
|
||
|
* bre written directly after this header. To facilitate this,
|
||
|
* a pointer to the block length is returned so that it can be modified.
|
||
|
* VersionBlockVariable() gets the value items by parsing the
|
||
|
* RC script as RCDATA.
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
VersionBlockVariable(
|
||
|
PWCHAR pstrKey
|
||
|
)
|
||
|
{
|
||
|
USHORT wLen;
|
||
|
int IndexLen;
|
||
|
int IndexType;
|
||
|
int IndexValueLen;
|
||
|
ULONG dwPadding = 0L;
|
||
|
USHORT wAlign;
|
||
|
|
||
|
/* Pad the block data to DWORD align */
|
||
|
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
|
||
|
if (wAlign)
|
||
|
WriteBuffer((PCHAR)&dwPadding, wAlign);
|
||
|
|
||
|
/* Save the current length so we can compute the new block length later */
|
||
|
wLen = GetBufferLen();
|
||
|
|
||
|
/* Write a zero for the length for now */
|
||
|
IndexLen = GetBufferLen();
|
||
|
WriteWord(0);
|
||
|
|
||
|
/* Write the length of the value field. We fill this in later */
|
||
|
IndexValueLen = GetBufferLen();
|
||
|
WriteWord(0);
|
||
|
|
||
|
/* Assume string data */
|
||
|
IndexType = GetBufferLen();
|
||
|
WriteWord(1);
|
||
|
|
||
|
/* Write the key string now */
|
||
|
WriteString(pstrKey, TRUE);
|
||
|
|
||
|
/* Parse and write the value data if there is any */
|
||
|
SetItemCount(IndexValueLen, VersionParseValue(IndexType));
|
||
|
|
||
|
/* Now fix up the block length and return a pointer to it */
|
||
|
SetItemCount(IndexLen, (USHORT)(GetBufferLen() - wLen));
|
||
|
|
||
|
return IndexLen;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/* VersionParseValue
|
||
|
* Parses the fields following either BLOCK or VALUE and following
|
||
|
* their key string which is parsed by VersionParseBlock().
|
||
|
* Before writing the first value item out, the field has to be
|
||
|
* DWORD aligned. Returns the length of the value block.
|
||
|
*/
|
||
|
|
||
|
USHORT
|
||
|
VersionParseValue(
|
||
|
int IndexType
|
||
|
)
|
||
|
{
|
||
|
USHORT wFirst = FALSE;
|
||
|
USHORT wToken;
|
||
|
USHORT wAlign;
|
||
|
ULONG dwPadding = 0L;
|
||
|
USHORT wLen = 0;
|
||
|
|
||
|
/* Decode all tokens until we get to the end of this item */
|
||
|
for (; ; ) {
|
||
|
/* ICGetTok is GetToken(TRUE) ignoring commas */
|
||
|
wToken = ICGetTok();
|
||
|
|
||
|
/* If this is the first item, DWORD align it. Since empty value
|
||
|
* sections are legal, we have to wait until we actually have data
|
||
|
* to do this.
|
||
|
*/
|
||
|
if (!wFirst) {
|
||
|
wFirst = TRUE;
|
||
|
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
|
||
|
if (wAlign)
|
||
|
WriteBuffer((PCHAR)&dwPadding, wAlign);
|
||
|
}
|
||
|
|
||
|
switch (wToken) {
|
||
|
case TKVALUE:
|
||
|
case TKBLOCK:
|
||
|
case BEGIN:
|
||
|
case END:
|
||
|
return wLen;
|
||
|
|
||
|
case LSTRLIT: /* String, write characters */
|
||
|
if (tokenbuf[0] == L'\0') /* ignore null strings */
|
||
|
break;
|
||
|
|
||
|
/* remove extra nuls */
|
||
|
while (tokenbuf[token.val-1] == L'\0')
|
||
|
token.val--;
|
||
|
|
||
|
wAlign = token.val + 1; /* want the character count */
|
||
|
wLen += wAlign;
|
||
|
if (fComma) {
|
||
|
WriteString(tokenbuf, TRUE);
|
||
|
} else {
|
||
|
AppendString(tokenbuf, TRUE);
|
||
|
wLen--;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case NUMLIT: /* Write the computed number out */
|
||
|
SetItemCount(IndexType, 0); /* mark data binary */
|
||
|
if (token.flongval) {
|
||
|
WriteLong(token.longval);
|
||
|
wLen += sizeof(LONG);
|
||
|
} else {
|
||
|
WriteWord(token.val);
|
||
|
wLen += sizeof(WORD);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ParseError1(2133); //"Unexpected value in value data"
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DlgIncludeParse(
|
||
|
PRESINFO pRes
|
||
|
)
|
||
|
{
|
||
|
INT i;
|
||
|
INT nbytes;
|
||
|
char * lpbuf;
|
||
|
|
||
|
if (token.type != LSTRLIT) {
|
||
|
ParseError1(2165);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// the DLGINCLUDE statement must be written in ANSI (8-bit) for compatibility
|
||
|
// WriteString(tokenbuf);
|
||
|
nbytes = WideCharToMultiByte (CP_ACP, 0, tokenbuf, -1, NULL, 0, NULL, NULL);
|
||
|
lpbuf = (char *) MyAlloc (nbytes);
|
||
|
WideCharToMultiByte (CP_ACP, 0, tokenbuf, -1, lpbuf, nbytes, NULL, NULL);
|
||
|
|
||
|
for (i = 0; i < nbytes; i++)
|
||
|
WriteByte (lpbuf[i]);
|
||
|
|
||
|
MyFree(lpbuf);
|
||
|
return;
|
||
|
}
|