#include "stdinc.h" #include "debmacro.h" #include "ntdef.h" #include "fusionparser.h" #include "shlwapi.h" #if !defined(NUMBER_OF) #define NUMBER_OF(x) (sizeof(x) / sizeof((x)[0])) #endif BOOL CFusionParser::ParseVersion( ASSEMBLY_VERSION &rav, PCWSTR sz, SIZE_T cch, bool &rfSyntaxValid ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); ULONG cDots = 0; PCWSTR pszTemp; SIZE_T cchLeft; ULONG ulTemp; ASSEMBLY_VERSION avTemp; PCWSTR pszLast; bool fSyntaxValid = true; rfSyntaxValid = false; PARAMETER_CHECK((sz != NULL) || (cch == 0)); avTemp.Major = 0; avTemp.Minor = 0; avTemp.Revision = 0; avTemp.Build = 0; while ((cch != 0) && (sz[cch - 1] == L'\0')) cch--; // Unfortunately there isn't a StrChrN(), so we'll look for the dots ourselves... pszTemp = sz; cchLeft = cch; while (cchLeft-- != 0) { WCHAR wch = *pszTemp++; if (wch == L'.') { cDots++; if (cDots >= 4) { fSyntaxValid = false; break; } } else if ((wch < L'0') || (wch > L'9')) { fSyntaxValid = false; break; } } if (fSyntaxValid && (cDots < 3)) fSyntaxValid = false; if (fSyntaxValid) { pszTemp = sz; pszLast = sz + cch; ulTemp = 0; for (;;) { WCHAR wch = *pszTemp++; if (wch == L'.') break; ulTemp = (ulTemp * 10) + (wch - L'0'); if (ulTemp > 65535) { fSuccess = true; // rfSyntaxValid implicitly false ASSERT(!rfSyntaxValid); goto Exit; } } avTemp.Major = (USHORT) ulTemp; ulTemp = 0; for (;;) { WCHAR wch = *pszTemp++; if (wch == L'.') break; ulTemp = (ulTemp * 10) + (wch - L'0'); if (ulTemp > 65535) { fSuccess = true; // rfSyntaxValid implicitly false ASSERT(!rfSyntaxValid); goto Exit; } } avTemp.Minor = (USHORT) ulTemp; ulTemp = 0; for (;;) { WCHAR wch = *pszTemp++; if (wch == L'.') break; ulTemp = (ulTemp * 10) + (wch - L'0'); if (ulTemp > 65535) { fSuccess = true; // rfSyntaxValid implicitly false ASSERT(!rfSyntaxValid); goto Exit; } } avTemp.Revision = (USHORT) ulTemp; // Now the tricky bit. We aren't necessarily null-terminated, so we // have to just look for hitting the end. ulTemp = 0; while (pszTemp < pszLast) { WCHAR wch = *pszTemp++; ulTemp = (ulTemp * 10) + (wch - L'0'); if (ulTemp > 65535) { fSuccess = true; // rfSyntaxValid implicitly false ASSERT(!rfSyntaxValid); goto Exit; } } avTemp.Build = (USHORT) ulTemp; rav = avTemp; } rfSyntaxValid = fSyntaxValid; fSuccess = TRUE; Exit: return fSuccess; } #if FUSION_DISABLED_CODE HRESULT CFusionParser::ParseThreadingModel(ULONG &threadingModel, PCWSTR sz, SIZE_T cch) { HRESULT hr = NOERROR; #define FUSIONPARSER_PARSETHREADINGMODELENTRY(x, y) \ { x, NUMBER_OF(x) - 1, y }, static const struct { PCWSTR m_psz; SIZE_T m_cch; ULONG m_threadingModel; } s_rgmap[] = { FUSIONPARSER_PARSETHREADINGMODELENTRY(L"Free", COMCLASS_THREADINGMODEL_FREE) FUSIONPARSER_PARSETHREADINGMODELENTRY(L"Apartment", COMCLASS_THREADINGMODEL_APARTMENT) FUSIONPARSER_PARSETHREADINGMODELENTRY(L"Both", COMCLASS_THREADINGMODEL_BOTH) }; ULONG i; // If the caller included the terminating null character, back up one. while ((cch != 0) && (sz[cch - 1] == L'\0')) cch--; for (i=0; i= 2) && (Radix <= 36)); while (cch != 0) { const WCHAR wch = *sz++; ULONG Digit = 0; cch--; if ((wch >= L'0') && (wch <= L'9')) Digit = (wch - L'0'); else if ((wch >= L'a') && (wch <= L'z')) Digit = (10 + wch - L'a'); else if ((wch >= L'A') && (wch <= L'Z')) Digit = (10 + wch - L'A'); else ORIGINATE_WIN32_FAILURE_AND_EXIT(InvalidDigit, ERROR_SXS_MANIFEST_PARSE_ERROR); if (Digit >= Radix) ORIGINATE_WIN32_FAILURE_AND_EXIT(InvalidDigitForRadix, ERROR_SXS_MANIFEST_PARSE_ERROR); ulTemp = (ulTemp * Radix) + Digit; } rul = ulTemp; fSuccess = TRUE; Exit: return fSuccess; } BOOL CFusionParser::ParseIETFDate( FILETIME &rft, PCWSTR sz, SIZE_T cch ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); SYSTEMTIME st; ULONG ulTemp; // // Our format is: // // DD/MM/YYYY // 0123456789 // // Strip off extra \0's from the end of sz, adjusting the cch // while ( ( cch != 0 ) && ( sz[cch - 1] == L'\0' ) ) cch--; PARAMETER_CHECK(cch == 10); PARAMETER_CHECK(sz[2] == L'/'); PARAMETER_CHECK(sz[5] == L'/'); ZeroMemory( &st, sizeof( st ) ); IFW32FALSE_EXIT(CFusionParser::ParseULONG(ulTemp, sz, 2, 10)); st.wDay = (WORD)ulTemp; IFW32FALSE_EXIT(CFusionParser::ParseULONG(ulTemp, sz + 3, 2, 10)); st.wMonth = (WORD)ulTemp; IFW32FALSE_EXIT(CFusionParser::ParseULONG(ulTemp, sz + 6, 4, 10)); st.wYear = (WORD)ulTemp; IFW32FALSE_ORIGINATE_AND_EXIT(::SystemTimeToFileTime(&st, &rft)); fSuccess = TRUE; Exit: return fSuccess; } BOOL CFusionParser::ParseFILETIME( FILETIME &rft, PCWSTR sz, SIZE_T cch ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); SYSTEMTIME st; ULONG ulTemp; while ((cch != 0) && (sz[cch - 1] == L'\0')) cch--; // MM/DD/YYYY HH:MM:SS.CCC // 01234567890123456789012 if (cch != 23) // 23 is the exact length of a filetime that we require ORIGINATE_WIN32_FAILURE_AND_EXIT(BadFiletimeLength, ERROR_SXS_MANIFEST_PARSE_ERROR); st.wMonth = 0; st.wDay = 0; st.wYear = 0; st.wHour = 0; st.wMinute = 0; st.wSecond = 0; st.wMilliseconds = 0; if ((sz[2] != L'/') || (sz[5] != L'/') || (sz[10] != L' ') || (sz[13] != L':') || (sz[16] != L':') || (sz[19] != L'.')) { ::SetLastError(ERROR_SXS_MANIFEST_PARSE_ERROR); goto Exit; } #define PARSE_FIELD(_field, _index, _length) \ do \ { \ if (!CFusionParser::ParseULONG(ulTemp, &sz[(_index)], (_length))) \ goto Exit; \ st._field = (WORD) ulTemp; \ } while (0) PARSE_FIELD(wMonth, 0, 2); PARSE_FIELD(wDay, 3, 2); PARSE_FIELD(wYear, 6, 4); PARSE_FIELD(wHour, 11, 2); PARSE_FIELD(wMinute, 14, 2); PARSE_FIELD(wSecond, 17, 2); PARSE_FIELD(wMilliseconds, 20, 3); IFW32FALSE_ORIGINATE_AND_EXIT(::SystemTimeToFileTime(&st, &rft)); fSuccess = TRUE; Exit: return fSuccess; } BOOL FusionDupString( LPWSTR *ppszOut, PCWSTR szIn, SIZE_T cchIn ) { BOOL fSuccess = FALSE; FN_TRACE_WIN32(fSuccess); if (ppszOut != NULL) *ppszOut = NULL; PARAMETER_CHECK((cchIn == 0) || (szIn != NULL)); PARAMETER_CHECK(ppszOut != NULL); IFALLOCFAILED_EXIT(*ppszOut = FUSION_NEW_ARRAY(WCHAR, cchIn + 1)); if (cchIn != 0) memcpy(*ppszOut, szIn, cchIn * sizeof(WCHAR)); (*ppszOut)[cchIn] = L'\0'; fSuccess = TRUE; Exit: return fSuccess; } int SxspHexDigitToValue(WCHAR wch) { if ((wch >= L'a') && (wch <= L'f')) return 10 + (wch - L'a'); else if ((wch >= L'A') && (wch <= 'F')) return 10 + (wch - L'A'); else if (wch >= '0' && wch <= '9') return (wch - L'0'); else return -1; } bool SxspIsHexDigit(WCHAR wch) { return (((wch >= L'0') && (wch <= L'9')) || ((wch >= L'a') && (wch <= L'f')) || ((wch >= L'A') && (wch <= L'F'))); } #if FUSION_DISABLED_CODE HRESULT CFusionParser::ParseULARGE_INTEGER(ULARGE_INTEGER &ruli, PCWSTR sz, SIZE_T cch) { HRESULT hr = NOERROR; ULONGLONG ullTemp = 0; if (cch < 0) cch = ::wcslen(sz); while ((cch != 0) && (sz[cch - 1] == L'\0')) cch--; while (cch-- != 0) { WCHAR wch = *sz++; // If we see anything other than a digit, we fail. We're not // atoi(); we're hard core. if ((wch < L'0') || (wch > L'9')) { hr = E_FAIL; goto Exit; } // I don't know if I really need all these casts, but I don't know what the // compiler's documented behavior for expressions of mixed unsigned __int64, int and // unsigned short types will be. Instead we'll explicitly cast everything to // unsigned __int64 (e.g. ULONGLONG) and hopefully the right stuff will happen. ullTemp = (ullTemp * static_cast(10)) + static_cast(wch - L'\0'); } ruli.QuadPart = ullTemp; hr = NOERROR; Exit: return hr; } HRESULT CFusionParser::ParseHexString(PCWSTR sz, SIZE_T cch, DWORD &rdwOut, PCWSTR &rszOut) { HRESULT hr = NOERROR; FN_TRACE_HR(hr); DWORD dw = 0; if (cch < 0) cch = ::wcslen(sz); while ((cch != 0) && (sz[cch - 1] == L'\0')) cch--; while (cch-- != 0) { int i = ::SxspHexDigitToValue(*sz++); INTERNAL_ERROR_CHECK(i >= 0); dw = (dw << 4) | i; } rdwOut = dw; rszOut = sz; hr = NOERROR; Exit: return hr; } HRESULT FusionCopyString( WCHAR *prgchBuffer, SIZE_T *pcchBuffer, PCWSTR szIn, SIZE_T cchIn) { HRESULT hr = NOERROR; FN_TRACE_HR(hr); SIZE_T cch; PARAMETER_CHECK(pcchBuffer != NULL); PARAMETER_CHECK((pcchBuffer == NULL) || ((*pcchBuffer == 0) || (prgchBuffer != NULL))); PARAMETER_CHECK((szIn != NULL) || (cchIn == 0)); if (cchIn < 0) cchIn = ::wcslen(szIn); if ((*pcchBuffer) < ((SIZE_T) (cchIn + 1))) { *pcchBuffer = cchIn + 1; ORIGINATE_WIN32_FAILURE_AND_EXIT(NoRoom, ERROR_INSUFFICIENT_BUFFER); } memcpy(prgchBuffer, szIn, cchIn * sizeof(WCHAR)); prgchBuffer[cchIn] = L'\0'; *pcchBuffer = (cchIn + 1); hr = NOERROR; Exit: return hr; } HRESULT FusionCopyBlob(BLOB *pblobOut, const BLOB &rblobIn) { HRESULT hr = NOERROR; if (pblobOut != NULL) { pblobOut->cbSize = 0; pblobOut->pBlobData = NULL; } if (pblobOut == NULL) { hr = E_POINTER; goto Exit; } if (rblobIn.cbSize != 0) { pblobOut->pBlobData = NEW(BYTE[rblobIn.cbSize]); if (pblobOut->pBlobData == NULL) { hr = E_OUTOFMEMORY; goto Exit; } memcpy(pblobOut->pBlobData, rblobIn.pBlobData, rblobIn.cbSize); pblobOut->cbSize = rblobIn.cbSize; } hr = NOERROR; Exit: return hr; } VOID FusionFreeBlob(BLOB *pblob) { if (pblob != NULL) { if (pblob->pBlobData != NULL) { CSxsPreserveLastError ple; delete []pblob->pBlobData; pblob->pBlobData = NULL; ple.Restore(); } pblob->cbSize = 0; } } #endif // FUSION_DISABLED_CODE