|
|
//---------------------------------------------------------------------------
// Parser.cpp - parses a "themes.ini" file and builds the ThemeInfo entries
//---------------------------------------------------------------------------
#include "stdafx.h"
#include "scanner.h"
#include "Parser.h"
#include "Utils.h"
#include "TmUtils.h"
#include "TmSchema.h"
#include "TmReg.h"
//---------------------------------------------------------------------------
//#include "NtlParse.h"
#define SYSCOLOR_STRINGS
#include "SysColors.h"
//---------------------------------------------------------------------------
#define SCHEMA_STRINGS
#include "TmSchema.h" // implements GetSchemaInfo()
static HBITMAP (*s_pfnSetBitmapAttributes)(HBITMAP, DWORD) = NULL; static HBITMAP (*s_pfnClearBitmapAttributes)(HBITMAP, DWORD) = NULL;
//--------------------------------------------------------------------
CThemeParser::CThemeParser(BOOL fGlobalTheme) { _pCallBackObj = NULL; _pNameCallBack = NULL; _fGlobalsDefined = FALSE; _fClassSectionDefined = FALSE; _fDefiningColorScheme = FALSE; _fUsingResourceProperties = FALSE; _fDefiningMetrics = FALSE; _fMetricsDefined = FALSE; _fGlobalTheme = FALSE; _crBlend = RGB(0, 0, 0xFF); // Hard code to blue
*_szResPropValue = 0; // not yet set
#ifdef DEBUG
// Provide a means of disabling stock bitmaps
BOOL fStock = TRUE; GetCurrentUserThemeInt(L"StockBitmaps", TRUE, &fStock);
if (fStock && fGlobalTheme) #else
if (fGlobalTheme) #endif
{ // Just don't use stock bitmaps when not running on Whistler
if (s_pfnSetBitmapAttributes != NULL) { _fGlobalTheme = TRUE; } else { HMODULE hMod = ::LoadLibrary(L"GDI32.DLL"); // No need to free
if (hMod) { s_pfnSetBitmapAttributes = (HBITMAP (*)(HBITMAP, DWORD)) ::GetProcAddress(hMod, "SetBitmapAttributes"); s_pfnClearBitmapAttributes = (HBITMAP (*)(HBITMAP, DWORD)) ::GetProcAddress(hMod, "ClearBitmapAttributes");
if ((s_pfnSetBitmapAttributes != NULL) && (s_pfnClearBitmapAttributes != NULL)) { _fGlobalTheme = TRUE; } } } } *_szBaseSectionName = 0; *_szFullSectionName = 0;
_iColorCount = 0; _iHueCount = 0;
_uCharSet = DEFAULT_CHARSET; _iFontNumber = 0; _hinstThemeDll = NULL; } //---------------------------------------------------------------------------
HRESULT CThemeParser::SourceError(int iMsgResId, LPCWSTR pszParam1, LPCWSTR pszParam2) { LPCWSTR pszSrcLine = _scan._szLineBuff; LPCWSTR pszFileName = _scan._szFileName; int iLineNum = _scan._iLineNum;
if (*_szResPropValue) // error in localizable property value
{ pszSrcLine = _szResPropValue; pszFileName = L"StringTable#"; iLineNum = _iResPropId; }
HRESULT hr = MakeParseError(iMsgResId, pszParam1, pszParam2, pszFileName, pszSrcLine, iLineNum); return hr; } //---------------------------------------------------------------------------
int CThemeParser::GetSymbolIndex(LPCWSTR pszName) { int symcnt = _Symbols.GetSize();
for (int i=0; i < symcnt; i++) { if (AsciiStrCmpI(_Symbols[i].csName, pszName)==0) return i; }
return -1; } //---------------------------------------------------------------------------
HRESULT CThemeParser::AddSymbol(LPCWSTR pszName, SHORT sTypeNum, PRIMVAL ePrimVal) { //---- ensure symbol doesn't already exist ----
for (int i = 0; i < _Symbols.m_nSize; i++) { if (AsciiStrCmpI(_Symbols.m_aT[i].csName, pszName)==0) return SourceError(PARSER_IDS_TYPE_DEFINED_TWICE, pszName); }
if (sTypeNum == -1) sTypeNum = (SHORT)_Symbols.GetSize();
SYMBOL symbol; symbol.csName = pszName; symbol.sTypeNum = sTypeNum; symbol.ePrimVal = ePrimVal; _Symbols.Add(symbol);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::InitializeSymbols() { _Symbols.RemoveAll(); _StockBitmapCleanupList.RemoveAll(); //---- get tm & comctl symbols ----
const TMSCHEMAINFO *si = GetSchemaInfo(); int cnt = si->iPropCount; const TMPROPINFO *pi = si->pPropTable;
//---- first pass - add all symbols except ENUM definitions ----
for (int i=0; i < cnt; i++) { if (pi[i].bPrimVal == TMT_ENUMDEF) continue;
if (pi[i].bPrimVal == TMT_ENUMVAL) continue;
HRESULT hr = AddSymbol(pi[i].pszName, pi[i].sEnumVal, pi[i].bPrimVal); if (FAILED(hr)) return hr; }
//---- second pass - add ENUM definitions ----
int iEnumPropNum = -1;
for (int i=0; i < cnt; i++) { if (pi[i].bPrimVal == TMT_ENUMDEF) { int iSymIndex = GetSymbolIndex(pi[i].pszName);
if (iSymIndex == -1) // not found - add it as a non-property enum symbol
{ HRESULT hr = AddSymbol(pi[i].pszName, -1, TMT_ENUM); if (FAILED(hr)) return hr; iSymIndex = GetSymbolIndex(pi[i].pszName); }
if (iSymIndex > -1) iEnumPropNum = _Symbols[iSymIndex].sTypeNum; else iEnumPropNum = -1;
} else if (pi[i].bPrimVal == TMT_ENUMVAL) { ENUMVAL enumval; enumval.csName = pi[i].pszName; enumval.iSymbolIndex = iEnumPropNum; enumval.iValue = pi[i].sEnumVal;
_EnumVals.Add(enumval); } }
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseDocSection() { _scan.ForceNextLine(); // get line after section line
//---- just skip over all lines in this section ----
while (1) { WCHAR szNameBuff[_MAX_PATH+1];
if (_scan.GetChar('[')) // start of new section
break;
if (! _scan.GetId(szNameBuff)) return SourceError(PARSER_IDS_EXPECTED_PROP_NAME);
if (! _scan.GetChar('=')) return SourceError(PARSER_IDS_EXPECTED_EQUALS_SIGN);
int cnt = _Symbols.GetSize();
for (int i=0; i < cnt; i++) { if (AsciiStrCmpI(_Symbols[i].csName, szNameBuff)==0) break; }
int symtype;
if (i == cnt) symtype = TMT_STRING; // unknown string property
else symtype = _Symbols[i].sTypeNum;
HRESULT hr;
//---- check to see if caller is querying for a doc property ----
if ((_dwParseFlags & PTF_QUERY_DOCPROPERTY) && (lstrcmpi(_pszDocProperty, szNameBuff)==0)) hr = ParseStringValue(symtype, _pszResult, _dwMaxResultChars); else hr = ParseStringValue(symtype); if (FAILED(hr)) return hr;
_scan.ForceNextLine(); }
//---- done with [documentation] section - turn off callback flag for properties ----
_dwParseFlags &= (~PTF_CALLBACK_DOCPROPERTIES);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseClassSectionName(LPCWSTR pszFirstName, LPWSTR szAppSym, ULONG cchAppSym) { //---- validate section name ----
//
// optional: szAppSym::
// _szClassName
// optional: .partsym
WCHAR szPartSym[_MAX_PATH+1]; WCHAR szStateSym[_MAX_PATH+1];
*szAppSym = 0; *szPartSym = 0;
_iPartId = -1; _iStateId = -1;
//---- copy the section name for callbacks ----
StringCchPrintfW(_szFullSectionName, ARRAYSIZE(_szFullSectionName), L"%s%s", pszFirstName, _scan._p); WCHAR *p = wcschr(_szFullSectionName, ']'); if (p) *p = 0;
HRESULT hr; hr = SafeStringCchCopyW(_szClassName, ARRAYSIZE(_szClassName), pszFirstName); if (FAILED(hr)) return hr;
if (_scan.GetChar(':')) { hr = SafeStringCchCopyW(szAppSym, cchAppSym, _szClassName); if (FAILED(hr)) return hr;
if (! _scan.GetChar(':')) return SourceError(PARSER_IDS_EXPECTED_DOUBLE_COLON); if (! _scan.GetId(_szClassName)) return SourceError(PARSER_IDS_MISSING_SECT_HDR_NAME); } else *szAppSym = 0;
_fDefiningMetrics = (AsciiStrCmpI(_szClassName, L"SysMetrics")==0);
if ((_fDefiningMetrics) && (*szAppSym)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS);
if (_scan.GetChar('.')) // an optional part id
{ //---- ensure a enum exists: <classname>Parts ----
WCHAR classparts[_MAX_PATH+1]; StringCchPrintfW(classparts, ARRAYSIZE(classparts), L"%sParts", _szClassName);
int iSymIndex = GetSymbolIndex(classparts); if (iSymIndex == -1) // doesn't exist
return SourceError(PARSER_IDS_PARTS_NOT_DEFINED, _szClassName);
//---- _scan the part name ----
if (! _scan.GetId(szPartSym)) return SourceError(PARSER_IDS_MISSING_SECT_HDR_PART);
//---- validate that it is a value for the <classname>Parts ----
hr = ValidateEnumSymbol(szPartSym, iSymIndex, &_iPartId); if (FAILED(hr)) return hr; }
if (_scan.GetChar('(')) // an optional state
{ //---- ensure a enum exists: <class or part name>States ----
WCHAR statesname[_MAX_PATH+1]; WCHAR *pszBaseName;
if (_iPartId == -1) pszBaseName = _szClassName; else pszBaseName = szPartSym;
StringCchPrintfW(statesname, ARRAYSIZE(statesname), L"%sStates", pszBaseName);
int iSymIndex = GetSymbolIndex(statesname); if (iSymIndex == -1) return SourceError(PARSER_IDS_STATES_NOT_DEFINED, pszBaseName);
if (! _scan.GetId(szStateSym)) return SourceError(PARSER_IDS_MISSING_SECT_HDR_STATE);
hr = ValidateEnumSymbol(szStateSym, iSymIndex, &_iStateId); if (FAILED(hr)) return hr;
if (! _scan.GetChar(')')) return SourceError(PARSER_IDS_EXPECTED_RPAREN); }
if (_iPartId > -1) { _iPartId = _EnumVals[_iPartId].iValue; StringCchCopyW(_szBaseSectionName, ARRAYSIZE(_szBaseSectionName), szPartSym); } else // not specified
{ StringCchCopyW(_szBaseSectionName, ARRAYSIZE(_szBaseSectionName), _szClassName); _iPartId = 0; }
if (_iStateId > -1) _iStateId = _EnumVals[_iStateId].iValue; else _iStateId = 0; if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_EXPECTED_END_OF_SECTION);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ValidateEnumSymbol(LPCWSTR pszName, int iSymType, int *pIndex) { for (int i = 0; i < _EnumVals.m_nSize; i++) { if (AsciiStrCmpI(_EnumVals.m_aT[i].csName, pszName)==0) { if (_EnumVals.m_aT[i].iSymbolIndex == iSymType) { if (pIndex) *pIndex = i; return S_OK; } } }
return SourceError(PARSER_IDS_NOT_ENUM_VALNAME, pszName, (LPCWSTR)_Symbols[iSymType].csName); } //---------------------------------------------------------------------------
HRESULT CThemeParser::AddThemeData(int iTypeNum, PRIMVAL ePrimVal, const void *pData, DWORD dwLen) { //Log("AddThemeData: typenum=%d, len=%d, data=0x%x", iTypeNum, dwLen, pData);
if (! _pCallBackObj) return S_FALSE;
HRESULT hr = _pCallBackObj->AddData((SHORT)iTypeNum, ePrimVal, pData, dwLen); if (FAILED(hr)) return SourceError(PARSER_IDS_THEME_TOO_BIG);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseEnumValue(int iSymType) { WCHAR valbuff[_MAX_PATH+1]; HRESULT hr; int value;
if (! _scan.GetId(valbuff)) return SourceError(PARSER_IDS_ENUM_VALNAME_EXPECTED);
int index; hr = ValidateEnumSymbol(valbuff, iSymType, &index); if (FAILED(hr)) return hr;
value = _EnumVals[index].iValue;
hr = AddThemeData(iSymType, TMT_ENUM, &value, sizeof(value)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseStringValue(int iSymType, LPWSTR pszBuff, DWORD cchBuff) { HRESULT hr;
//---- just store the raw string ----
_scan.SkipSpaces();
if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTSTRING) || (iSymType > TMT_LASTSTRING)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); }
if (pszBuff) // special call
{ hr = SafeStringCchCopyW(pszBuff, cchBuff, _scan._p); if (FAILED(hr)) return hr; } else { int len = 1 + lstrlen(_scan._p);
hr = AddThemeData(iSymType, TMT_STRING, _scan._p, len*sizeof(WCHAR)); if (FAILED(hr)) return hr; }
if ((iSymType >= TMT_FIRST_RCSTRING_NAME) && (iSymType <= TMT_LAST_RCSTRING_NAME)) { if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_DOCPROPERTIES)) { int index = iSymType - TMT_FIRST_RCSTRING_NAME;
BOOL fContinue = (*_pNameCallBack)(TCB_DOCPROPERTY, _scan._p, NULL, NULL, index, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } }
//---- advance _scanner to end of line ----
_scan._p += lstrlen(_scan._p);
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseIntValue(int iSymType, int *piValue) { int value; if (! _scan.GetNumber(&value)) return SourceError(PARSER_IDS_INT_EXPECTED);
if (piValue) // special call
*piValue = value; else { HRESULT hr = AddThemeData(iSymType, TMT_INT, &value, sizeof(value)); if (FAILED(hr)) return hr; }
if (iSymType == TMT_CHARSET) { if (_iFontNumber) return SourceError(PARSER_IDS_CHARSETFIRST);
if (_fGlobalsDefined) return SourceError(PARSER_IDS_CHARSET_GLOBALS_ONLY);
_uCharSet = (UCHAR) value; }
if (iSymType == TMT_MINCOLORDEPTH) { if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_MINCOLORDEPTH)) { BOOL fContinue = (*_pNameCallBack)(TCB_MINCOLORDEPTH, _scan._szFileName, NULL, NULL, value, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } } return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseBoolValue(int iSymType, LPCWSTR pszPropertyName) { WCHAR valbuff[_MAX_PATH+1]; BYTE bBoolVal;
if (! _scan.GetId(valbuff)) return SourceError(PARSER_IDS_BOOL_EXPECTED);
if (AsciiStrCmpI(valbuff, L"true")==0) bBoolVal = 1; else if (AsciiStrCmpI(valbuff, L"false")==0) bBoolVal = 0; else return SourceError(PARSER_IDS_EXPECTED_TRUE_OR_FALSE);
if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTBOOL) || (iSymType > TMT_LASTBOOL)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); }
//---- special handling for "MirrorImage" property ----
if (iSymType == TMT_MIRRORIMAGE) { //---- handle MirrorImage callbacks (packtime) ----
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS)) { BOOL fContinue = (*_pNameCallBack)(TCB_MIRRORIMAGE, _szClassName, _szFullSectionName, pszPropertyName, _iPartId, (LPARAM)bBoolVal);
if (! fContinue) return MakeErrorParserLast(); }
//---- handle getting value from string table (loadtime) ----
if (_fUsingResourceProperties) // substitute resource value
{ WCHAR szValue[MAX_PATH];
HRESULT hr = GetResourceProperty(pszPropertyName, szValue, ARRAYSIZE(szValue)); if (SUCCEEDED(hr)) { bBoolVal = (*szValue == '1'); } else { hr = S_OK; // non-fatal error
} } }
HRESULT hr = AddThemeData(iSymType, TMT_BOOL, &bBoolVal, sizeof(bBoolVal)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
COLORREF CThemeParser::ApplyColorSubstitution(COLORREF crOld) { //---- apply SOLID color substitutions ----
for (int i=0; i < _iColorCount; i++) { if (crOld == _crFromColors[i]) return _crToColors[i]; }
//---- apply HUE color substitutions ----
WORD wHue, wLum, wSat; RGBtoHLS(crOld, &wHue, &wLum, &wSat);
for (i=0; i < _iHueCount; i++) { if (wHue == _bFromHues[i]) // hues match
{ COLORREF crNew = HLStoRGB(_bToHues[i], wLum, wSat); // substitute new hue
return crNew; } }
return crOld; } //---------------------------------------------------------------------------
void CThemeParser::CleanupStockBitmaps() { if (s_pfnClearBitmapAttributes) { for (int i=0; i < _StockBitmapCleanupList.m_nSize; i++) { HBITMAP hbm = (*s_pfnClearBitmapAttributes)(_StockBitmapCleanupList[i], SBA_STOCK); if (hbm) { DeleteObject(hbm); } else { // We are totally out of luck today aren't we
Log(LOG_TMBITMAP, L"Failed to clear stock bitmap on cleanup"); } } }
_StockBitmapCleanupList.RemoveAll(); } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseColorValue(int iSymType, COLORREF *pcrValue, COLORREF *pcrValue2) { COLORREF color; HRESULT hr = S_OK;
{ const WCHAR *parts[] = {L"r", L"g", L"b"}; int ints[3] = {0}; hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 255); if (FAILED(hr)) { hr = SourceError(PARSER_IDS_BAD_COLOR_VALUE); goto exit; }
color = RGB(ints[0], ints[1], ints[2]); }
if (! _fDefiningColorScheme) color = ApplyColorSubstitution(color);
if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTCOLOR) || (iSymType > TMT_LASTCOLOR)) { hr = SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); goto exit; } }
if (pcrValue2) { *pcrValue2 = color; }
if (pcrValue) // special call
*pcrValue = color; else { hr = AddThemeData(iSymType, TMT_COLOR, &color, sizeof(color)); if (FAILED(hr)) goto exit; }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseMarginsValue(int iSymType) { const WCHAR *parts[] = {L"lw", L"rw", L"th", L"bh"}; int ints[4];
HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0); if (FAILED(hr)) return SourceError(PARSER_IDS_BAD_MARGINS_VALUE);
hr = AddThemeData(iSymType, TMT_MARGINS, ints, sizeof(ints)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseIntListValue(int iSymType) { INTLIST IntList; HRESULT hr = S_OK;
//---- unnamed parts ----
for (int i=0; i < MAX_INTLIST_COUNT; i++) { if (! _scan.GetNumber(&IntList.iValues[i])) { if (_scan.EndOfLine()) break; hr = SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p); goto exit; }
_scan.GetChar(','); // optional comma
}
IntList.iValueCount = i;
hr = AddThemeData(iSymType, TMT_INTLIST, &IntList, (1+i)*sizeof(int)); if (FAILED(hr)) goto exit;
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::PackageImageData(LPCWSTR szFileNameR, LPCWSTR szFileNameG, LPCWSTR szFileNameB, int iDibPropNum) { HRESULT hr = S_OK;
//---- add TMT_DIBDATA data ----
WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
// The filename was parsed and validated before, so we're sure it's not longer than _MAX_PATH
_wsplitpath(szFileNameR, drive, dir, fname, ext); WCHAR szResName[_MAX_PATH+1]; DWORD len = lstrlen(dir); if ((len) && (dir[len-1] == L'\\')) { dir[len-1] = L'_'; } StringCchPrintfW(szResName, ARRAYSIZE(szResName), L"%s%s_BMP", dir, fname); HBITMAP hBitmapR = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
if (!hBitmapR) return SourceError(PARSER_IDS_NOOPEN_IMAGE, szResName);
//---- convert to DIBDATA ----
CBitmapPixels pixels; DWORD *pPixelQuads; int iWidth, iHeight, iBytesPerPixel, iBytesPerRow, iPreviousBytesPerPixel;
BOOL fUseDrawStream = TRUE;
// Allocate a TMBITMAPHEADER in addition to the bitmap
hr = pixels.OpenBitmap(NULL, hBitmapR, TRUE, &pPixelQuads, &iWidth, &iHeight, &iBytesPerPixel, &iBytesPerRow, &iPreviousBytesPerPixel, TMBITMAPSIZE); if (FAILED(hr)) { DeleteObject(hBitmapR); return hr; }
BOOL fWasAlpha = (iPreviousBytesPerPixel == 4);
#if 0
//---- apply loaded color scheme, if any ----
if ((szFileNameG && szFileNameG[0]) && (szFileNameB && szFileNameB[0])) { _wsplitpath(szFileNameG, drive, dir, fname, ext); len = lstrlen(dir); if ((len) && (dir[len-1] == L'\\')) { dir[len-1] = L'_'; } StringCchPrintfW(szResName, ARRAYSIZE(szResName), L"%s%s_BMP", dir, fname); HBITMAP hBitmapG = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
_wsplitpath(szFileNameB, drive, dir, fname, ext); len = lstrlen(dir); if ((len) && (dir[len-1] == L'\\')) { dir[len-1] = L'_'; } StringCchPrintfW(szResName, ARRAYSIZE(szResName), L"%s%s_BMP", dir, fname); HBITMAP hBitmapB = (HBITMAP) LoadImage(_hinstThemeDll, szResName, IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
DWORD dwRWeight = GetRValue(_crBlend); DWORD dwGWeight = GetGValue(_crBlend); DWORD dwBWeight = GetBValue(_crBlend);
DWORD *pPixelQuadsG = NULL; DWORD *pPixelQuadsB = NULL; if (hBitmapG && hBitmapB) { HDC hdc = GetDC(NULL); if (hdc) { int dwLen = iWidth * iHeight;
pPixelQuadsG = new DWORD[dwLen]; if (pPixelQuadsG) { pPixelQuadsB = new DWORD[dwLen]; if (pPixelQuadsB) { BITMAPINFO bi = {0}; bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = iWidth; bi.bmiHeader.biHeight = iHeight; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = 32; bi.bmiHeader.biCompression = BI_RGB;
if (GetDIBits(hdc, hBitmapG, 0, iHeight, pPixelQuadsG, &bi, DIB_RGB_COLORS) && GetDIBits(hdc, hBitmapB, 0, iHeight, pPixelQuadsB, &bi, DIB_RGB_COLORS)) { DWORD* pdwR = pPixelQuads; DWORD* pdwG = pPixelQuadsG; DWORD* pdwB = pPixelQuadsB; for (int i = 0; i < dwLen; i++) { if ((*pdwR & 0xffffff) != RGB(255,0,255)) { *pdwR = (*pdwR & 0xff000000) | RGB(min(((GetRValue(*pdwR) * dwRWeight) + (GetRValue(*pdwG) * dwGWeight) + (GetRValue(*pdwB) * dwBWeight)) >> 8, 0xff), min(((GetGValue(*pdwR) * dwRWeight) + (GetGValue(*pdwG) * dwGWeight) + (GetGValue(*pdwB) * dwBWeight)) >> 8, 0xff), min(((GetBValue(*pdwR) * dwRWeight) + (GetBValue(*pdwG) * dwGWeight) + (GetBValue(*pdwB) * dwBWeight)) >> 8, 0xff)); } pdwR++; pdwG++; pdwB++; } }
delete[] pPixelQuadsB; } delete[] pPixelQuadsG; } ReleaseDC(NULL, hdc); } } else { OutputDebugString(L"Failed to load bitmaps"); }
if (hBitmapG) { DeleteObject(hBitmapG); hBitmapG = NULL; }
if (hBitmapB) { DeleteObject(hBitmapB); hBitmapB = NULL; } } #endif
BITMAPINFOHEADER *pBitmapHdr = pixels._hdrBitmap;
//---- if alpha present, pre-multiply RGB values (as per AlphaBlend()) API ----
BOOL fTrueAlpha = FALSE;
// We keep per-pixel alpha bitmaps as 32 bits DIBs, not compatible bitmaps
if (fWasAlpha) { fTrueAlpha = (PreMultiplyAlpha(pPixelQuads, pBitmapHdr->biWidth, pBitmapHdr->biHeight) != 0); #ifdef DEBUG
if (!fTrueAlpha) Log(LOG_TMBITMAP, L"%s is 32 bits, but not true alpha", szFileNameR); #endif
} HBITMAP hbmStock = NULL; BOOL fFlipped = FALSE;
if (fUseDrawStream && _fGlobalTheme) { HDC hdc = ::GetWindowDC(NULL);
if (hdc) { typedef struct { BITMAPINFOHEADER bmih; ULONG masks[3]; } BITMAPHEADER; BITMAPHEADER bmi;
bmi.bmih.biSize = sizeof(bmi.bmih); bmi.bmih.biWidth = pBitmapHdr->biWidth; bmi.bmih.biHeight = pBitmapHdr->biHeight; bmi.bmih.biPlanes = 1; bmi.bmih.biBitCount = 32; bmi.bmih.biCompression = BI_BITFIELDS; bmi.bmih.biSizeImage = 0; bmi.bmih.biXPelsPerMeter = 0; bmi.bmih.biYPelsPerMeter = 0; bmi.bmih.biClrUsed = 3; bmi.bmih.biClrImportant = 0; bmi.masks[0] = 0xff0000; // red
bmi.masks[1] = 0x00ff00; // green
bmi.masks[2] = 0x0000ff; // blue
hbmStock = CreateDIBitmap(hdc, &bmi.bmih, CBM_INIT | CBM_CREATEDIB , pPixelQuads, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS);
// Need to Force 32-bit DIBs in Multi-mon mode
// Make it match the screen resolution setting if it is not an AlphaBlended image
::ReleaseDC(NULL, hdc); }
if (!hbmStock) { hr = E_OUTOFMEMORY; } else { ASSERT(s_pfnSetBitmapAttributes != NULL); ASSERT(s_pfnClearBitmapAttributes != NULL);
HBITMAP hbmOld = hbmStock; hbmStock = (*s_pfnSetBitmapAttributes)(hbmStock, SBA_STOCK);
if (hbmStock == NULL) { DeleteObject(hbmOld); Log(LOG_ALWAYS, L"UxTheme: SetBitmapAttributes failed in CParser::PackageImageData");
hr = E_FAIL; } else { _StockBitmapCleanupList.Add(hbmStock); } } }
::DeleteObject(hBitmapR);
// Fill in the TMBITMAPHEADER structure
if (SUCCEEDED(hr)) { TMBITMAPHEADER *psbh = (TMBITMAPHEADER*) pixels.Buffer();
psbh->dwSize = TMBITMAPSIZE; psbh->fFlipped = fFlipped; psbh->hBitmap = hbmStock; psbh->fTrueAlpha = fTrueAlpha; psbh->dwColorDepth = iBytesPerPixel * 8;
if (hbmStock == NULL) // Pass DIB bits
{ int size = psbh->dwSize + sizeof(BITMAPINFOHEADER) + iHeight * iBytesPerRow; hr = AddThemeData(iDibPropNum, TMT_DIBDATA, psbh, size); } else // Pass the TMBITMAPHEADER structure only
{ hr = AddThemeData(iDibPropNum, TMT_DIBDATA, psbh, psbh->dwSize); } }
return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseFileNameValue(int iSymType, LPWSTR pszBuff, DWORD cchBuff) { WCHAR szFileNameR[_MAX_PATH+1] = {0}; WCHAR szFileNameG[_MAX_PATH+1] = {0}; WCHAR szFileNameB[_MAX_PATH+1] = {0}; HRESULT hr = S_OK;
if (! _scan.GetFileName(szFileNameR, ARRAYSIZE(szFileNameR))) { hr = SourceError(PARSER_IDS_ENUM_VALNAME_EXPECTED); goto exit; }
if (_scan.GetFileName(szFileNameG, ARRAYSIZE(szFileNameG))) { _scan.GetFileName(szFileNameB, ARRAYSIZE(szFileNameB)); }
if (pszBuff) // special call
{ hr = SafeStringCchCopyW(pszBuff, cchBuff, szFileNameR); if (FAILED(hr)) goto exit; } else if (_pCallBackObj) // emit data
{ //---- add TMT_FILENAME data ----
hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameR, sizeof(WCHAR)*(1+lstrlen(szFileNameR))); if (FAILED(hr)) goto exit; if ((szFileNameG[0] != 0) && (szFileNameB[0] != 0)) { hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameG, sizeof(WCHAR)*(1+lstrlen(szFileNameR))); if (FAILED(hr)) goto exit; hr = AddThemeData(iSymType, TMT_FILENAME, &szFileNameB, sizeof(WCHAR)*(1+lstrlen(szFileNameR))); if (FAILED(hr)) goto exit; }
if (iSymType == TMT_IMAGEFILE) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_DIBDATA); } else if (iSymType == TMT_GLYPHIMAGEFILE) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_GLYPHDIBDATA); } else if (iSymType == TMT_STOCKIMAGEFILE) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_STOCKDIBDATA); } else if ((iSymType >= TMT_IMAGEFILE1) && (iSymType <= TMT_IMAGEFILE5)) { hr = PackageImageData(szFileNameR, szFileNameG, szFileNameB, TMT_DIBDATA1 + (iSymType-TMT_IMAGEFILE1)); }
if (FAILED(hr)) goto exit; }
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_FILENAMES)) { BOOL fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameR, NULL, NULL, iSymType, _lNameParam); if (! fContinue) { hr = MakeErrorParserLast(); goto exit; }
if (szFileNameG[0] && szFileNameB[0]) { fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameG, NULL, NULL, iSymType, _lNameParam); if (! fContinue) { hr = MakeErrorParserLast(); goto exit; } fContinue = (*_pNameCallBack)(TCB_FILENAME, szFileNameB, NULL, NULL, iSymType, _lNameParam); if (! fContinue) { hr = MakeErrorParserLast(); goto exit; } } }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseSizeValue(int iSymType) { int val; if (! _scan.GetNumber(&val)) return SourceError(PARSER_IDS_INT_EXPECTED);
int pixels;
HRESULT hr = ParseSizeInfoUnits(val, L"pixels", &pixels); if (FAILED(hr)) return hr;
if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTSIZE) || (iSymType > TMT_LASTSIZE)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); }
hr = AddThemeData(iSymType, TMT_SIZE, &pixels, sizeof(pixels)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParsePositionValue(int iSymType) { const WCHAR *parts[] = {L"x", L"y"}; int ints[2];
HRESULT hr = GetIntList(ints, parts, ARRAYSIZE(ints), 0, 0); if (FAILED(hr)) return SourceError(PARSER_IDS_ILLEGAL_SIZE_VALUE);
hr = AddThemeData(iSymType, TMT_POSITION, ints, sizeof(ints)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseRectValue(int iSymType, LPCWSTR pszPropertyName) { const WCHAR *parts[] = {L"l", L"t", L"r", L"b"}; LONG rgl[4];
HRESULT hr = GetIntList((int*)rgl, parts, ARRAYSIZE(rgl), 0, 0); if (FAILED(hr)) return SourceError(PARSER_IDS_ILLEGAL_RECT_VALUE);
//---- special handling for localizable RECT properties ----
if (iSymType == TMT_DEFAULTPANESIZE) { //---- handle localizable callback (packtime) ----
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS)) { BOOL fContinue = (*_pNameCallBack)(TCB_LOCALIZABLE_RECT, _szClassName, _szFullSectionName, pszPropertyName, _iPartId, (LPARAM)(RECT *)rgl);
if (! fContinue) return MakeErrorParserLast(); }
//---- handle getting value from string table (loadtime) ----
if (_fUsingResourceProperties) // substitute resource value
{ WCHAR szValue[MAX_PATH];
HRESULT hr = GetResourceProperty(pszPropertyName, szValue, ARRAYSIZE(szValue)); if (SUCCEEDED(hr)) { RECT rc;
int cnt = swscanf(szValue, L"%d, %d, %d, %d", &rc.left, &rc.top, &rc.right, &rc.bottom);
if (cnt == 4) { //---- override with localized values ----
CopyMemory(rgl, &rc, sizeof(rgl)); }
} else { hr = S_OK; // non-fatal error
} } }
hr = AddThemeData(iSymType, TMT_RECT, rgl, sizeof(rgl)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseSizeInfoUnits(int iVal, LPCWSTR pszDefaultUnits, int *piPixels) { WCHAR szUnits[_MAX_PATH+1]; HRESULT hr;
//---- NOTE: this uses the THEME_DPI (96) for all size conversions! ----
//---- this gives us consistent LOGFONT, etc. across diff. resolution screens ----
//---- with the promise that we will do just-in-time DPI scaling, when appropriate ----
if (! _scan.GetId(szUnits)) { hr = SafeStringCchCopyW(szUnits, ARRAYSIZE(szUnits), pszDefaultUnits); if (FAILED(hr)) return hr; }
if (AsciiStrCmpI(szUnits, L"pixels")==0) ; // already correct
else if (AsciiStrCmpI(szUnits, L"twips")==0) { iVal = -MulDiv(iVal, THEME_DPI, 20*72); } else if (AsciiStrCmpI(szUnits, L"points")==0) { iVal = -MulDiv(iVal, THEME_DPI, 72); } else return SourceError(PARSER_IDS_UNKNOWN_SIZE_UNITS, szUnits);
*piPixels = iVal; return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseFontValue(int iSymType, LPCWSTR pszPropertyName) { LOGFONT font; WCHAR szLineBuff[_MAX_PATH+1]; HRESULT hr;
_scan.SkipSpaces(); // trim leading blanks
memset(&font, 0, sizeof(font)); font.lfWeight = FW_NORMAL; font.lfCharSet = _uCharSet;
_iFontNumber++; BOOL fGotFont = FALSE;
if (_fUsingResourceProperties) // substitute resource font string
{ hr = GetResourceProperty(pszPropertyName, szLineBuff, ARRAYSIZE(szLineBuff)); if (SUCCEEDED(hr)) { fGotFont = TRUE; } else { hr = S_OK; } }
if (! fGotFont) { //---- copy font specs from scanner ----
hr = SafeStringCchCopyW(szLineBuff, ARRAYSIZE(szLineBuff), _scan._p); if (FAILED(hr)) return hr; }
//---- handle font callback ----
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_LOCALIZATIONS)) { WCHAR *p = szLineBuff; while (IsSpace(*p)) p++;
BOOL fContinue = (*_pNameCallBack)(TCB_FONT, p, _szFullSectionName, pszPropertyName, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); }
//---- family name is required and must be first ----
WCHAR *p; p = wcschr(szLineBuff, ','); if (! p) // whole line is family name
{ hr = StringCchCopyW(font.lfFaceName, ARRAYSIZE(font.lfFaceName), szLineBuff); return hr; }
*p++ = 0; hr = StringCchCopyW(font.lfFaceName, ARRAYSIZE(font.lfFaceName), szLineBuff); if (FAILED(hr)) return hr;
_scan._p = p;
int val; if (_scan.GetNumber(&val)) // font size
{ int pixels;
hr = ParseSizeInfoUnits(val, L"points", &pixels); if (FAILED(hr)) return hr;
font.lfHeight = pixels;
_scan.GetChar(','); // optional comma
}
WCHAR flagname[_MAX_PATH+1];
while (_scan.GetId(flagname)) { if (AsciiStrCmpI(flagname, L"bold")==0) font.lfWeight = FW_BOLD; else if (AsciiStrCmpI(flagname, L"italic")==0) font.lfItalic = TRUE; else if (AsciiStrCmpI(flagname, L"underline")==0) font.lfUnderline = TRUE; else if (AsciiStrCmpI(flagname, L"strikeout")==0) font.lfStrikeOut = TRUE; else return SourceError(PARSER_IDS_UNKNOWN_FONT_FLAG, flagname); }
// addit:
if (_fDefiningMetrics) { if ((iSymType < TMT_FIRSTFONT) || (iSymType > TMT_LASTFONT)) return SourceError(PARSER_IDS_NOT_ALLOWED_SYSMETRICS); }
hr = AddThemeData(iSymType, TMT_FONT, &font, sizeof(font)); if (FAILED(hr)) return hr;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseClassLine(int *piSymType, int *piValue, LPWSTR pszBuff, DWORD cchBuff) { WCHAR szNameBuff[_MAX_PATH+1]; WCHAR szSymbol[MAX_INPUT_LINE+1];
if (! _scan.GetId(szNameBuff)) return SourceError(PARSER_IDS_EXPECTED_PROP_NAME);
if (! _scan.GetChar('=')) return SourceError(PARSER_IDS_EXPECTED_EQUALS_SIGN);
int cnt = _Symbols.GetSize();
for (int i=0; i < cnt; i++) { if (AsciiStrCmpI(_Symbols[i].csName, szNameBuff)==0) break; }
if (i == cnt) return SourceError(PARSER_IDS_UNKNOWN_PROP, szNameBuff);
int symtype = _Symbols[i].sTypeNum; HRESULT hr;
// Handle substituted symbols
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTSYMBOLS)) { if (wcschr(_scan._p, INI_MACRO_SYMBOL)) { // Pass ##
if (_scan.GetChar(INI_MACRO_SYMBOL) && _scan.GetChar(INI_MACRO_SYMBOL)) { WCHAR szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szBaseName[_MAX_FNAME], szExt[_MAX_EXT];
_wsplitpath(_scan._szFileName, szDrive, szDir, szBaseName, szExt);
BOOL fContinue = (*_pNameCallBack)(TCB_NEEDSUBST, szBaseName, _scan._p, szSymbol, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast();
_scan.UseSymbol(szSymbol); } } }
switch (_Symbols[i].ePrimVal) { case TMT_ENUM: hr = ParseEnumValue(symtype); break; case TMT_STRING: hr = ParseStringValue(symtype, pszBuff, cchBuff); break;
case TMT_INT: hr = ParseIntValue(symtype, piValue); break;
case TMT_INTLIST: hr = ParseIntListValue(symtype); break;
case TMT_BOOL: hr = ParseBoolValue(symtype, szNameBuff); break;
case TMT_COLOR: { COLORREF cr; hr = ParseColorValue(symtype, (COLORREF *)piValue, &cr); if (SUCCEEDED(hr)) { if (lstrcmpi(_Symbols[i].csName, L"BLENDCOLOR") == 0) { _crBlend = cr; } } } break;
case TMT_MARGINS: hr = ParseMarginsValue(symtype); break;
case TMT_FILENAME: hr = ParseFileNameValue(symtype, pszBuff, cchBuff); break;
case TMT_SIZE: hr = ParseSizeValue(symtype); break;
case TMT_POSITION: hr = ParsePositionValue(symtype); break;
case TMT_RECT: hr = ParseRectValue(symtype, szNameBuff); break;
case TMT_FONT: hr = ParseFontValue(symtype, szNameBuff); break;
default: hr = E_FAIL; break; }
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTSYMBOLS)) { _scan.UseSymbol(NULL); }
*_szResPropValue = 0; // not yet set
if (FAILED(hr)) return hr;
if (piSymType) // special call
*piSymType = symtype;
if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_EXTRA_PROP_TEXT, _scan._p);
_scan.ForceNextLine(); return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseColorSchemeSection() { HRESULT hr; WCHAR SchemeName[_MAX_PATH+1]; WCHAR DisplayName[_MAX_PATH+1]; WCHAR ToolTip[MAX_INPUT_LINE+1]; WCHAR szBuff[MAX_INPUT_LINE+1];
if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
if (! _scan.GetId(SchemeName, ARRAYSIZE(SchemeName))) return SourceError(PARSER_IDS_CS_NAME_EXPECTED);
if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
_scan.ForceNextLine(); // get line after section line
*ToolTip = 0; *DisplayName = 0;
bool fCorrectScheme = (lstrcmpi(_ColorParam, SchemeName)==0);
if (fCorrectScheme) // initialize all subst. tables
{ hr = SafeStringCchCopyW(DisplayName, ARRAYSIZE(DisplayName), SchemeName); // in case not specified
if (FAILED(hr)) return hr;
for (int i=0; i < HUE_SUBCNT; i++) { _bFromHues[i] = 0; _bToHues[i] = 0; }
for (i=0; i < COLOR_SUBCNT; i++) { _crFromColors[i] = 0; _crToColors[i] = 0; } }
//----- put into vars to make coding/debugging easier ----
int firstFromHue = TMT_FROMHUE1; int lastFromHue = TMT_FROMHUE1 + HUE_SUBCNT - 1; int firstToHue = TMT_TOHUE1; int lastToHue = TMT_TOHUE1 + HUE_SUBCNT - 1;
int firstFromColor = TMT_FROMCOLOR1; int lastFromColor = TMT_FROMCOLOR1 + COLOR_SUBCNT - 1; int firstToColor = TMT_TOCOLOR1; int lastToColor = TMT_TOCOLOR1 + COLOR_SUBCNT - 1;
while (1) // parse each line
{ if (_scan.EndOfFile()) break;
if (_scan.GetChar('[')) // start of new section
break;
int iSymType, iValue;
_fDefiningColorScheme = TRUE;
//---- parse the COLOR or INT property line ----
hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff));
_fDefiningColorScheme = FALSE;
if (FAILED(hr)) return hr;
//---- store the HUE or COLOR param in local tables ----
if ((iSymType >= firstFromHue) && (iSymType <= lastFromHue)) { if (fCorrectScheme) _bFromHues[iSymType-firstFromHue] = (BYTE)iValue; } else if ((iSymType >= firstToHue) && (iSymType <= lastToHue)) { if (fCorrectScheme) _bToHues[iSymType-firstToHue] = (BYTE)iValue; } else if ((iSymType >= firstFromColor) && (iSymType <= lastFromColor)) { if (fCorrectScheme) _crFromColors[iSymType-firstFromColor] = (COLORREF)iValue; } else if ((iSymType >= firstToColor) && (iSymType <= lastToColor)) { if (fCorrectScheme) _crToColors[iSymType-firstToColor] = (COLORREF)iValue; } else if (iSymType == TMT_DISPLAYNAME) { hr = SafeStringCchCopyW(DisplayName, ARRAYSIZE(DisplayName), szBuff); if (FAILED(hr)) return hr; } else if (iSymType == TMT_TOOLTIP) { hr = SafeStringCchCopyW(ToolTip, ARRAYSIZE(ToolTip), szBuff ); if (FAILED(hr)) return hr; } else { return SourceError(PARSER_IDS_ILLEGAL_CS_PROPERTY); } }
if (fCorrectScheme) // adjust counts
{ _iHueCount = HUE_SUBCNT; while (_iHueCount > 0) { if (_bFromHues[_iHueCount-1] == _bToHues[_iHueCount-1]) _iHueCount--; else break; }
_iColorCount = COLOR_SUBCNT; while (_iColorCount > 0) { if (_crFromColors[_iColorCount-1] == _crToColors[_iColorCount-1]) _iColorCount--; else break; } }
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_COLORSECTION)) { BOOL fContinue = (*_pNameCallBack)(TCB_COLORSCHEME, SchemeName, DisplayName, ToolTip, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); }
// Create an empty subst table
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, SchemeName, NULL, NULL, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseSizeSection() { HRESULT hr; WCHAR szSizeName[_MAX_PATH+1]; WCHAR szDisplayName[_MAX_PATH+1]; WCHAR szToolTip[MAX_INPUT_LINE+1]; WCHAR szBuff[MAX_INPUT_LINE+1];
if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
if (! _scan.GetId(szSizeName, ARRAYSIZE(szSizeName))) return SourceError(PARSER_IDS_SS_NAME_EXPECTED);
if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
_scan.ForceNextLine(); // get line after section line
while (1) // parse each line of section
{ if (_scan.EndOfFile()) break;
if (_scan.GetChar('[')) // start of new section
break;
int iSymType, iValue;
//---- parse the property line ----
hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff)); if (FAILED(hr)) return hr;
if (iSymType == TMT_DISPLAYNAME) { hr = SafeStringCchCopyW(szDisplayName, ARRAYSIZE(szDisplayName), szBuff ); if (FAILED(hr)) return hr; } else if (iSymType == TMT_TOOLTIP) { hr = SafeStringCchCopyW(szToolTip, ARRAYSIZE(szToolTip), szBuff ); if (FAILED(hr)) return hr; } else { return SourceError(PARSER_IDS_ILLEGAL_SS_PROPERTY); } }
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SIZESECTION)) { BOOL fContinue = (*_pNameCallBack)(TCB_SIZENAME, szSizeName, szDisplayName, szToolTip, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast(); }
// Create an empty subst table
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName, NULL, NULL, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseFileSection() { HRESULT hr; WCHAR szSizeName[_MAX_PATH+1]; WCHAR szFileName[_MAX_PATH+1]; WCHAR szColorSchemes[_MAX_PATH+1]; WCHAR szSizes[MAX_INPUT_LINE+1]; WCHAR szBuff[MAX_INPUT_LINE+1];
if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
if (! _scan.GetId(szSizeName, ARRAYSIZE(szSizeName))) return SourceError(PARSER_IDS_FS_NAME_EXPECTED);
if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
_scan.ForceNextLine(); // get line after section line
while (1) // parse each line of section
{ if (_scan.EndOfFile()) break;
if (_scan.GetChar('[')) // start of new section
break;
int iSymType, iValue;
//---- parse the property line ----
hr = ParseClassLine(&iSymType, &iValue, szBuff, ARRAYSIZE(szBuff)); if (FAILED(hr)) return hr;
if (iSymType == TMT_FILENAME) { hr = StringCchCopyW(szFileName, ARRAYSIZE(szFileName), szBuff ); } else if (iSymType == TMT_COLORSCHEMES) { hr = StringCchCopyW(szColorSchemes, ARRAYSIZE(szColorSchemes), szBuff ); } else if (iSymType == TMT_SIZES) { hr = StringCchCopyW(szSizes, ARRAYSIZE(szSizes), szBuff ); } else { return SourceError(PARSER_IDS_ILLEGAL_SS_PROPERTY); }
if (FAILED(hr)) return hr; }
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_FILESECTION)) { BOOL fContinue = (*_pNameCallBack)(TCB_CDFILENAME, szSizeName, szFileName, NULL, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); fContinue = (*_pNameCallBack)(TCB_CDFILECOMBO, szSizeName, szColorSchemes, szSizes, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName, SUBST_TABLE_INCLUDE, szColorSchemes, 0, _lNameParam); if (! fContinue) return MakeErrorParserLast();
fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSizeName, SUBST_TABLE_INCLUDE, szSizes, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); }
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseSubstSection() { WCHAR szSubstTableName[_MAX_PATH+1]; WCHAR szId[MAX_INPUT_LINE+1]; WCHAR szValue[MAX_INPUT_LINE+1]; BOOL fFirst = TRUE;
if (! _scan.GetChar('.')) return SourceError(PARSER_IDS_EXPECTED_DOT_SN);
if (! _scan.GetId(szSubstTableName, ARRAYSIZE(szSubstTableName))) return SourceError(PARSER_IDS_FS_NAME_EXPECTED);
if (! _scan.GetChar(']')) return SourceError(PARSER_IDS_RBRACKET_EXPECTED);
if (! _scan.EndOfLine()) return SourceError(PARSER_IDS_END_OF_LINE_EXPECTED);
_scan.ForceNextLine(); // get line after section line
while (1) // parse each line of section
{ if (_scan.EndOfFile()) break;
if (_scan.GetChar('[')) // start of new section
{ // Call the callback once for creating the empty table
if (fFirst && (_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSubstTableName, NULL, NULL, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } break; }
//---- parse the property line ----
if (!_scan.GetIdPair(szId, szValue, ARRAYSIZE(szId))) return SourceError(PARSER_IDS_BAD_SUBST_SYMBOL);
fFirst = FALSE;
_scan.ForceNextLine();
if ((_pNameCallBack) && (_dwParseFlags & PTF_CALLBACK_SUBSTTABLE)) { BOOL fContinue = (*_pNameCallBack)(TCB_SUBSTTABLE, szSubstTableName, szId, szValue, 0, _lNameParam);
if (! fContinue) return MakeErrorParserLast(); } }
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::GenerateEmptySection(LPCWSTR pszSectionName, int iPartId, int iStateId) { int iStartIndex = 0;
if (_pCallBackObj) iStartIndex = _pCallBackObj->GetNextDataIndex();
int index = 0; // will be updated later
HRESULT hr = AddThemeData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &index, sizeof(index)); if (FAILED(hr)) return hr;
if (_pCallBackObj) { int iLen = _pCallBackObj->GetNextDataIndex() - iStartIndex;
hr = _pCallBackObj->AddIndex(L"", pszSectionName, iPartId, iStateId, iStartIndex, iLen); if (FAILED(hr)) return hr; }
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseClassSection(LPCWSTR pszFirstName) { HRESULT hr; int iStartIndex = 0;
BOOL fGlobals = (AsciiStrCmpI(pszFirstName, GLOBALS_SECTION_NAME)==0); BOOL fMetrics = (AsciiStrCmpI(pszFirstName, SYSMETRICS_SECTION_NAME)==0);
if (fGlobals) { if (_fClassSectionDefined) return SourceError(PARSER_IDS_GLOBALS_MUST_BE_FIRST); } else // regular class section
{ if (_dwParseFlags & PTF_CLASSDATA_PARSE) { if (! _fGlobalsDefined) // insert an empty [fGlobals] section
{ hr = GenerateEmptySection(GLOBALS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr;
_fGlobalsDefined = true; }
if ((! fMetrics) && (! _fMetricsDefined)) // insert an empty [sysmetrics] section
{ hr = GenerateEmptySection(SYSMETRICS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr;
_fMetricsDefined = true; } else if ((fMetrics) && (_fClassSectionDefined)) return SourceError(PARSER_IDS_METRICS_MUST_COME_BEFORE_CLASSES); }
_fClassSectionDefined = TRUE; }
WCHAR szAppSym[_MAX_PATH+1];
if (_pCallBackObj) iStartIndex = _pCallBackObj->GetNextDataIndex();
hr = ParseClassSectionName(pszFirstName, szAppSym, ARRAYSIZE(szAppSym)); if (FAILED(hr)) return hr;
_scan.ForceNextLine(); // get line after section line
while (1) // parse each line
{ if (_scan.EndOfFile()) break;
if (_scan.GetChar('[')) // start of new section
break;
hr = ParseClassLine(); if (FAILED(hr)) return hr; }
//---- end this section of theme data ----
int index = 0; // will be updated later
hr = AddThemeData(TMT_JUMPTOPARENT, TMT_JUMPTOPARENT, &index, sizeof(index)); if (FAILED(hr)) return hr;
if (_pCallBackObj) { int iLen = _pCallBackObj->GetNextDataIndex() - iStartIndex;
hr = _pCallBackObj->AddIndex(szAppSym, _szClassName, _iPartId, _iStateId, iStartIndex, iLen); if (FAILED(hr)) return hr; }
if (fGlobals) _fGlobalsDefined = true; else if (fMetrics) _fMetricsDefined = true;
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseThemeFile(LPCTSTR pszFileName, LPCWSTR pszColorParam, IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags) { _pszDocProperty = NULL;
HRESULT hr = InitializeSymbols(); if (FAILED(hr)) goto exit;
hr = _scan.AttachFile(pszFileName); // "pszBuffer" contains the filename
if (FAILED(hr)) goto exit;
if (pszColorParam) { hr = SafeStringCchCopyW(_ColorParam, ARRAYSIZE(_ColorParam), pszColorParam ); if (FAILED(hr)) return hr; } else *_ColorParam = 0;
_hinstThemeDll = NULL;
hr = ParseThemeScanner(pCallBack, pNameCallBack, lNameParam, dwParseFlags);
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseThemeBuffer(LPCWSTR pszBuffer, LPCWSTR pszFileName, LPCWSTR pszColorParam, HINSTANCE hinstThemeDll, IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags, LPCWSTR pszDocProperty, OUT LPWSTR pszResult, DWORD dwMaxResultChars) { _pszDocProperty = pszDocProperty; _pszResult = pszResult;
//---- initialize in case not found ----
if (_pszResult) *_pszResult = 0;
_dwMaxResultChars = dwMaxResultChars;
HRESULT hr = InitializeSymbols(); if (FAILED(hr)) goto exit;
_hinstThemeDll = hinstThemeDll;
_scan.AttachMultiLineBuffer(pszBuffer, pszFileName);
if (pszColorParam) { hr = SafeStringCchCopyW(_ColorParam, ARRAYSIZE(_ColorParam), pszColorParam ); if (FAILED(hr)) return hr; } else *_ColorParam = 0;
hr = ParseThemeScanner(pCallBack, pNameCallBack, lNameParam, dwParseFlags);
//---- make error if doc property not found ----
if ((SUCCEEDED(hr)) && (_dwParseFlags & PTF_QUERY_DOCPROPERTY) && (! *_pszResult)) { hr = MakeError32(ERROR_NOT_FOUND); }
exit: return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::LoadResourceProperties() { WCHAR szFullString[2*MAX_PATH]; WCHAR szBaseIniName[_MAX_PATH]; HRESULT hr = S_OK;
//---- extract base .ini name ----
WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], ext[_MAX_EXT]; _wsplitpath(_scan._szFileName, drive, dir, szBaseIniName, ext);
//---- remove optional "_INI" part ----
LPWSTR pszExt = wcsstr(szBaseIniName, L"_INI"); if (pszExt) *pszExt = 0;
//---- read all localizable property name/value pairs into memory ----
for (int i=RES_BASENUM_PROPVALUEPAIRS; ; i++) { if (! LoadString(_hinstThemeDll, i, szFullString, ARRAYSIZE(szFullString))) { //---- no more properties avail ----
break; }
StringCchCopyW(_szResPropValue, ARRAYSIZE(_szResPropValue), szFullString); // for proper error reporting
_iResPropId = i;
//---- does this property belong to current file? ----
LPWSTR pszAtSign = wcschr(szFullString, '@'); if (! pszAtSign) { hr = SourceError(PARSER_IDS_BAD_RES_PROPERTY); break; }
//---- zero terminate ini name ----
*pszAtSign = 0;
if (lstrcmpi(szBaseIniName, szFullString) != 0) continue;
//---- strip off the .ini name for faster comparing ----
LPCWSTR pszName = pszAtSign+1;
LPWSTR pszValue = wcschr(pszName, '='); if (pszValue) { pszValue++; // skip over equals sign
} else { hr = SourceError(PARSER_IDS_BAD_RES_PROPERTY); break; }
//---- add the value ----
CWideString cwValue(pszValue); _PropertyValues.Add(cwValue);
//---- zero-terminate the name ----
*pszValue = 0;
//---- add the name ----
CWideString cwName(pszName); _PropertyNames.Add(cwName);
//---- add the id ----
_iPropertyIds.Add(i); }
return hr; } //---------------------------------------------------------------------------
void CThemeParser::EmptyResourceProperties() { _PropertyNames.RemoveAll(); _PropertyValues.RemoveAll(); } //---------------------------------------------------------------------------
HRESULT CThemeParser::GetResourceProperty(LPCWSTR pszPropName, LPWSTR pszValueBuff, int cchValueBuff) { WCHAR szPropTarget[2*MAX_PATH]; HRESULT hr = S_OK; BOOL fFound = FALSE;
StringCchPrintfW(szPropTarget, ARRAYSIZE(szPropTarget), L"[%s]%s=", _szFullSectionName, pszPropName);
for (int i=0; i < _PropertyNames.m_nSize; i++) { if (AsciiStrCmpI(szPropTarget, _PropertyNames[i])==0) { fFound = TRUE;
hr = SafeStringCchCopyW(pszValueBuff, cchValueBuff, _PropertyValues[i]); if (SUCCEEDED(hr)) { hr = SafeStringCchCopyW(_szResPropValue, ARRAYSIZE(_szResPropValue), _PropertyValues[i]); _iResPropId = _iPropertyIds[i]; } break; } }
if (! fFound) hr = E_FAIL;
return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::ParseThemeScanner(IParserCallBack *pCallBack, THEMEENUMPROC pNameCallBack, LPARAM lNameParam, DWORD dwParseFlags) { HRESULT hr;
_pCallBackObj = pCallBack;
_pNameCallBack = pNameCallBack; _lNameParam = lNameParam; _dwParseFlags = dwParseFlags; _fClassSectionDefined = FALSE;
//---- setup for properties in the .res file ----
EmptyResourceProperties();
_fUsingResourceProperties = (pCallBack != NULL);
if (_fUsingResourceProperties) { hr = LoadResourceProperties(); if (FAILED(hr)) goto exit;
//---- set the error context for normal .ini parsing ----
*_szResPropValue = 0; // not yet set
}
//---- scan the first, non-comment WCHAR ----
if (! _scan.GetChar('[')) { if (! _scan.EndOfFile()) { hr = SourceError(PARSER_IDS_LBRACKET_EXPECTED); goto exit; } }
while (! _scan.EndOfFile()) // process each section
{
WCHAR section[_MAX_PATH+1]; _scan.GetId(section);
if (AsciiStrCmpI(section, L"documentation")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
hr = ParseDocSection();
if (_dwParseFlags & PTF_QUERY_DOCPROPERTY) break; // quicker to leave in middle of file
} else if (AsciiStrCmpI(section, L"ColorScheme")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
hr = ParseColorSchemeSection(); } else if (AsciiStrCmpI(section, L"Size")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
hr = ParseSizeSection(); } else if (AsciiStrCmpI(section, L"File")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
hr = ParseFileSection(); } else if (AsciiStrCmpI(section, L"Subst")==0) { if (_dwParseFlags & PTF_CLASSDATA_PARSE) return SourceError(PARSER_IDS_BADSECT_CLASSDATA);
hr = ParseSubstSection(); } else // "globals", "sysmetrics", or class section
{ if (_dwParseFlags & PTF_CONTAINER_PARSE) return SourceError(PARSER_IDS_BADSECT_THEMES_INI);
hr = ParseClassSection(section); }
if (FAILED(hr)) goto exit; }
//---- check for empty theme ----
if (_dwParseFlags & PTF_CLASSDATA_PARSE) { if (! _fGlobalsDefined) // insert an empty [fGlobals] section
{ hr = GenerateEmptySection(GLOBALS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr;
_fGlobalsDefined = true; }
if (! _fMetricsDefined) // insert an empty [sysmetrics] section
{ hr = GenerateEmptySection(SYSMETRICS_SECTION_NAME, 0, 0); if (FAILED(hr)) return hr; } }
hr = S_OK;
exit: _outfile.Close();
_pCallBackObj = NULL; _pNameCallBack = NULL; return hr; } //---------------------------------------------------------------------------
HRESULT CThemeParser::GetIntList(int *pInts, LPCWSTR *pParts, int iCount, int iMin, int iMax) { bool bSet[255]; // assume 255 max ints
//---- ensure we set each one once ----
for (int i=0; i < iCount; i++) bSet[i] = false;
if (wcschr(_scan._p, ':')) { //---- named parts ----
for (int i=0; i < iCount; i++) { WCHAR idbuff[_MAX_PATH+1];
if (! _scan.GetId(idbuff)) return SourceError(PARSER_IDS_VALUE_NAME_EXPECTED, _scan._p); for (int j=0; j < iCount; j++) { if (AsciiStrCmpI(pParts[j], idbuff)==0) break; }
if (j == iCount) // unknown part name
return SourceError(PARSER_IDS_UNKNOWN_VALUE_NAME, idbuff);
if (bSet[j]) // name set twice
return SourceError(PARSER_IDS_VALUE_PART_SPECIFIED_TWICE, idbuff);
if (! _scan.GetChar(':')) return SourceError(PARSER_IDS_COLOR_EXPECTED, _scan._p);
if (! _scan.GetNumber(&pInts[j])) return SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p);
bSet[j] = true;
_scan.GetChar(','); // optional comma
} } else { //---- unnamed parts ----
for (int i=0; i < iCount; i++) { if (! _scan.GetNumber(&pInts[i])) return SourceError(PARSER_IDS_NUMBER_EXPECTED, _scan._p);
_scan.GetChar(','); // optional comma
} }
//---- range check ----
if (iMin != iMax) { for (i=0; i < iCount; i++) { if ((pInts[i] < iMin) || (pInts[i] > iMax)) return SourceError(PARSER_IDS_NUMBER_OUT_OF_RANGE); } }
return S_OK; } //---------------------------------------------------------------------------
HRESULT CThemeParser::GetPropertyNum(LPCWSTR pszName, int *piPropNum) { //---- for perf, avoid loading all symbols each time this func is called ----
//---- by using "GetSchemaInfo()" ----
//---- get tm & comctl symbols ----
const TMSCHEMAINFO *si = GetSchemaInfo(); int cnt = si->iPropCount; const TMPROPINFO *pi = si->pPropTable;
for (int i=0; i < cnt; i++) { if (pi[i].sEnumVal < TMT_FIRST_RCSTRING_NAME) continue;
if (pi[i].sEnumVal > TMT_LAST_RCSTRING_NAME) break;
if (AsciiStrCmpI(pszName, pi[i].pszName)==0) { *piPropNum = pi[i].sEnumVal - TMT_FIRST_RCSTRING_NAME; // zero based
return S_OK; } }
return MakeError32(ERROR_NOT_FOUND); }
|