// Read template<> bool OpcXml::Read(const COpcString& cString, Decimal& cValue) { bool bResult = true; TRY { COpcText cText; COpcTextReader cReader(cString); // parse whole integer portion. cText.SetType(COpcText::Delimited); cText.SetDelims(L"."); cText.SetEofDelim(); if (!cReader.GetNext(cText)) { THROW_(bResult, false); } // convert to signed integer. Long nValue = 0; if (!ToSigned(cText, nValue, MAX_DECIMAL, MIN_DECIMAL)) { THROW_(bResult, false); } cValue.int64 = nValue*10000; if (cText.GetDelimChar() == L'.') { // parse decimal portion. cText.SetType(COpcText::Delimited); cText.SetEofDelim(); if (!cReader.GetNext(cText)) { THROW_(bResult, false); } // convert to unsigned integer. ULong uValue = 0; if (!ToUnsigned(cText, uValue, MAX_DEC_FRACTION, 0, 10)) { THROW_(bResult, false); } cValue.int64 += (Long)uValue; } } CATCH { cValue.int64 = 0; } return bResult; }
// ToDate static bool ToDate( const COpcString& cString, WORD& wYear, WORD& wMonth, WORD& wDay ) { bool bResult = true; TRY { COpcText cText; COpcTextReader cReader(cString); ULong uValue = 0; // parse year field. cText.SetType(COpcText::Delimited); cText.SetDelims(L"-"); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_YEAR, MIN_YEAR, 10)) THROW_(bResult, false); wYear = (WORD)uValue; // parse month field. cText.SetType(COpcText::Delimited); cText.SetDelims(L"-"); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_MONTH, MIN_MONTH, 10)) THROW_(bResult, false); wMonth = (WORD)uValue; // parse day field. cText.SetType(COpcText::Delimited); cText.SetEofDelim(); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_DAY, MIN_DAY, 10)) THROW_(bResult, false); wDay = (WORD)uValue; } CATCH { wYear = 0; wMonth = 0; wDay = 0; } return bResult; }
// ToOffset static bool ToOffset( const COpcString& cString, bool bNegative, SHORT& sMinutes ) { bool bResult = true; TRY { COpcText cText; COpcTextReader cReader(cString); ULong uValue = 0; // parse hour field. cText.SetType(COpcText::Delimited); cText.SetDelims(L":"); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_HOUR, MIN_HOUR, 10)) THROW_(bResult, false); sMinutes = (SHORT)uValue*60; // parse minute field. cText.SetType(COpcText::Delimited); cText.SetDelims(L"."); cText.SetEofDelim(); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_MINUTE, MIN_MINUTE, 10)) THROW_(bResult, false); sMinutes += (SHORT)uValue; // add sign. if (bNegative) { sMinutes = -sMinutes; } } CATCH { sMinutes = 0; } return bResult; }
// Read template<> bool OpcXml::Read(const COpcString& cString, DateTime& cValue) { bool bResult = true; FILETIME cFileTime; // check for invalid date. if (cString.IsEmpty()) { cValue = OpcMinDate(); return true; } TRY { SYSTEMTIME cSystemTime; ZeroMemory(&cSystemTime, sizeof(cSystemTime)); COpcText cText; COpcTextReader cReader(cString); // parse date fields. cText.SetType(COpcText::Delimited); cText.SetDelims(L"T"); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToDate(cText, cSystemTime.wYear, cSystemTime.wMonth, cSystemTime.wDay)) { THROW_(bResult, false); } // parse time fields. cText.SetType(COpcText::Delimited); cText.SetDelims(L"Z-+"); cText.SetEofDelim(); if (!cReader.GetNext(cText)) THROW_(bResult, false); bResult = ToTime( cText, cSystemTime.wHour, cSystemTime.wMinute, cSystemTime.wSecond, cSystemTime.wMilliseconds); if (!bResult) { THROW_(bResult, false); } // convert to a UTC file time. if (!SystemTimeToFileTime(&cSystemTime, &cFileTime)) { THROW_(bResult, false); } if (cText.GetDelimChar() != _T('Z')) { // convert local system time to UTC file time. if (cText.GetEof()) { FILETIME ftUtcTime; if (!OpcLocalTimeToUtcTime(cFileTime, ftUtcTime)) { THROW_(bResult, false); } cFileTime = ftUtcTime; } // apply offset specified in the datetime string. else { bool bNegative = (cText.GetDelimChar() == _T('-')); // parse time fields. cText.SetType(COpcText::Delimited); cText.SetEofDelim(); if (!cReader.GetNext(cText)) THROW_(bResult, false); SHORT sMinutes = 0; bResult = ToOffset( cText, bNegative, sMinutes); if (!bResult) { THROW_(bResult, false); } // apply timezone offset. LONGLONG llTime = OpcToInt64(cFileTime); llTime -= ((LONGLONG)sMinutes)*60*10000000; cFileTime = OpcToFILETIME(llTime); } } cValue = cFileTime; } CATCH { ZeroMemory(&cFileTime, sizeof(cFileTime)); cValue = cFileTime; } return bResult; }
// ToTime static bool ToTime( const COpcString& cString, WORD& wHour, WORD& wMinute, WORD& wSeconds, WORD& wFraction ) { bool bResult = true; TRY { COpcText cText; COpcTextReader cReader(cString); ULong uValue = 0; // parse hour field. cText.SetType(COpcText::Delimited); cText.SetDelims(L":"); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_HOUR, MIN_HOUR, 10)) THROW_(bResult, false); wHour = (WORD)uValue; // parse month field. cText.SetType(COpcText::Delimited); cText.SetDelims(L":"); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_MINUTE, MIN_MINUTE, 10)) THROW_(bResult, false); wMinute = (WORD)uValue; // parse seconds field. cText.SetType(COpcText::Delimited); cText.SetDelims(L"."); cText.SetEofDelim(); if (!cReader.GetNext(cText)) THROW_(bResult, false); if (!ToUnsigned(cText, uValue, MAX_SECOND, MIN_SECOND, 10)) THROW_(bResult, false); wSeconds = (WORD)uValue; // parse seconds fraction field. wFraction = 0; if (cText.GetDelimChar() == L'.') { cText.SetType(COpcText::Delimited); cText.SetEofDelim(); if (!cReader.GetNext(cText)) THROW_(bResult, false); // preprocess text. COpcString cFraction = cText; // add trailing zeros. while (cFraction.GetLength() < 3) cFraction += _T("0"); // truncate extra digits. if (cFraction.GetLength() > 3) cFraction = cFraction.SubStr(0,3); if (!ToUnsigned(cFraction, uValue, MAX_ULONG, 0, 10)) { THROW_(bResult, false); } // result is in milliseconds. wFraction = (WORD)uValue; } } CATCH { wHour = 0; wMinute = 0; wSeconds = 0; wFraction = 0; } return bResult; }
// ToUnsigned static bool ToUnsigned( const COpcString& cString, ULong& nValue, ULong nMax, ULong nMin, UINT uBase ) { bool bResult = true; TRY { COpcText cText; COpcTextReader cReader(cString); // extract non-whitespace. cText.SetType(COpcText::NonWhitespace); cText.SetEofDelim(); if (!cReader.GetNext(cText)) { THROW_(bResult, false); } COpcString cValue = cText; nValue = 0; for (UINT ii = 0; ii < cValue.GetLength(); ii++) { UINT uDigit = CharToValue(cValue[ii], uBase); // invalid digit found. if (uDigit == -1) { bResult = false; break; } // detect overflow if (nValue > nMax/uBase) THROW_(bResult, false); // shift result up by base. nValue *= uBase; // detect overflow if (nValue > nMax - uDigit) THROW_(bResult, false); // add digit. nValue += uDigit; } // detect underflow if (nMin > nValue) THROW_(bResult, false); } CATCH { nValue = 0; } return bResult; }