|
|
/***********************************************************************
* Microsoft (R) Windows (R) Resource Compiler * * Copyright (c) Microsoft Corporation. All rights reserved. * * File Comments: * * ***********************************************************************/
#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(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(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, pDlg->Font, 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; }
|