// Write template<> bool OpcXml::Write(const DateTime& cValue, COpcString& cString) { // check for invalid date. if (cValue == OpcMinDate()) { cString.Empty(); return true; } // convert to xml dateTime representation. SYSTEMTIME cSystemTime; if (!FileTimeToSystemTime(&((FILETIME)cValue), &cSystemTime)) { return false; } WCHAR szBuf[MAX_VALUE_BUF_SIZE]; swprintf( szBuf, L"%04hu-%02hu-%02huT%02hu:%02hu:%02hu.%03hu", cSystemTime.wYear, cSystemTime.wMonth, cSystemTime.wDay, cSystemTime.wHour, cSystemTime.wMinute, cSystemTime.wSecond, cSystemTime.wMilliseconds); cString = szBuf; return true; }
// AddNamespace bool COpcXmlDocument::AddNamespace(const COpcString& cPrefix, const COpcString& cNamespace) { // check for a valid root element. COpcXmlElement cElement(GetRoot()); if (cElement == NULL) { return false; } // check for an invalid prefix if (cPrefix.IsEmpty()) { return false; } // construct the new namespace attribute name. COpcString cAttributeName; cAttributeName += OPCXML_NAMESPACE_ATTRIBUTE; cAttributeName += ":"; cAttributeName += cPrefix; // add or update the namespace string. cElement.SetAttribute(cAttributeName, cNamespace); return true; }
// Save bool COpcXmlDocument::Save(const COpcString& cFilePath) { HRESULT hResult = S_OK; VARIANT varFile; varFile.vt = VT_BSTR; varFile.bstrVal = SysAllocString((LPCWSTR)((cFilePath.IsEmpty())?m_cFilePath:cFilePath)); TRY { // save the file. hResult = m_ipDocument->save(varFile); if (FAILED(hResult)) { THROW(); } } CATCH_FINALLY { OpcVariantClear(&varFile); } return SUCCEEDED(hResult); }
// GetNamespaces void COpcXmlDocument::GetNamespaces(COpcStringMap& cNamespaces) { // clear the current set. cNamespaces.RemoveAll(); // check for a valid root element. COpcXmlElement cElement(GetRoot()); if (cElement == NULL) { return; } // add the namespace for the root element. COpcString cPrefix = cElement.GetPrefix(); if (!cPrefix.IsEmpty()) { cNamespaces[cPrefix] = cElement.GetNamespace(); } // fetch the attributes from the root element. COpcXmlAttributeList cAttributes; if (cElement.GetAttributes(cAttributes) > 0) { for (UINT ii = 0; ii < cAttributes.GetSize(); ii++) { if (cAttributes[ii].GetPrefix() == OPCXML_NAMESPACE_ATTRIBUTE) { COpcString cName = cAttributes[ii].GetQualifiedName().GetName(); // don't add the default namespace. if (!cName.IsEmpty()) { cNamespaces[cName] = cAttributes[ii].GetValue(); } } } } }
// Find COpcBrowseElement* COpcBrowseElement::Find(const COpcString& cPath) { // remove leading separator - if it exists. COpcString cPrefix = GetSeparator(); COpcString cLocalPath = cPath; while (cLocalPath.Find(GetSeparator()) == 0) { cLocalPath = cLocalPath.SubStr(cPrefix.GetLength()); } // recursively search children. OPC_POS pos = m_cChildren.GetHeadPosition(); while (pos != NULL) { COpcBrowseElement* pChild = m_cChildren.GetNext(pos); // check for a child with an exact name match. if (cLocalPath == pChild->m_cName) { return pChild; } // check if the path starts with the child name. COpcString cPrefix = pChild->m_cName + pChild->GetSeparator(); // check for a child with an exact name match plus trailing separator. if (cLocalPath == cPrefix) { return pChild; } UINT uIndex = cLocalPath.Find(cPrefix); // search the child node if there is a match. if (uIndex == 0) { cLocalPath = cLocalPath.SubStr(cPrefix.GetLength()); return pChild->Find(cLocalPath); } } return NULL; }
// GetItemID COpcString COpcBrowseElement::GetItemID() const { if (m_cItemID.IsEmpty()) { COpcString cItemID; if (m_pParent != NULL) { cItemID += m_pParent->GetItemID(); if (!cItemID.IsEmpty()) { cItemID += m_pParent->GetSeparator(); } } cItemID += m_cName; return cItemID; } return m_cItemID; }
COpcTextReader::COpcTextReader(const COpcString& cBuffer) : m_szBuf(NULL), m_uLength(0), m_uEndOfData(0) { if (!cBuffer.IsEmpty()) { LPCWSTR szBuf = (COpcString&)cBuffer; m_uLength = (szBuf != NULL)?wcslen(szBuf):0; m_szBuf = (WCHAR*)OpcAlloc((m_uLength+1)*sizeof(WCHAR)); wcsncpy(m_szBuf, szBuf, m_uLength); m_uEndOfData = m_uLength; m_szBuf[m_uEndOfData] = L'\0'; } }
// 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; }
// Write template<> bool OpcXml::Write(const GUID& cValue, COpcString& cText) { cText.FromGuid(cValue); return true; }
// Read template<> bool OpcXml::Read(const COpcString& cText, GUID& cValue) { return cText.ToGuid(cValue); }
// Clear template<> void OpcXml::Clear(COpcString& cValue) { cValue.Empty(); }
// Init template<> void OpcXml::Init(COpcString& cValue) { cValue.Empty(); }
// 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; }
// Load bool COpcXmlDocument::Load(const COpcString& cFilePath) { HRESULT hResult = S_OK; VARIANT varFile; varFile.vt = VT_BSTR; varFile.bstrVal = SysAllocString((LPCWSTR)cFilePath); TRY { // create new document instance. if (!Init()) { THROW_(hResult, E_FAIL); } // load the file. VARIANT_BOOL bResult = VARIANT_FALSE; hResult = m_ipDocument->load(varFile, &bResult); if (FAILED(hResult)) { THROW(); } if (!bResult) { IXMLDOMParseError* ipError = NULL; hResult = m_ipDocument->get_parseError(&ipError); if (FAILED(hResult)) { THROW_(hResult, E_FAIL); } BSTR bstrReason = NULL; hResult = ipError->get_reason(&bstrReason); if (SUCCEEDED(hResult)) { SysFreeString(bstrReason); } ipError->Release(); } // update default path. if (!cFilePath.IsEmpty()) m_cFilePath = cFilePath; } CATCH { Clear(); } FINALLY { OpcVariantClear(&varFile); } return SUCCEEDED(hResult); }
// Insert COpcBrowseElement* COpcBrowseElement::Insert(const COpcString& cPath) { COpcString cName = cPath; COpcString cSubPath = OPC_EMPTY_STRING; // check if multiple levels have been specified. do { UINT uIndex = cName.Find(GetSeparator()); if (uIndex == -1) { break; } cSubPath = cName.SubStr(uIndex + GetSeparator().GetLength()); cName = cName.SubStr(0, uIndex); if (!cName.IsEmpty()) { break; } cName = cSubPath; } while (!cSubPath.IsEmpty()); // invalid path specified. if (cName.IsEmpty()) { return NULL; } // find out if node already exists. COpcBrowseElement* pNode = NULL; OPC_POS pos = m_cChildren.GetHeadPosition(); while (pos != NULL) { pNode = m_cChildren.GetNext(pos); if (pNode->m_cName == cName) { // return existing node. if (cSubPath.IsEmpty()) { return pNode; } // insert sub-path into existing node. return pNode->Insert(cSubPath); } } // create new node. pNode = CreateInstance(); pNode->m_cName = cName; OPC_ASSERT(!pNode->m_cName.IsEmpty()); COpcBrowseElement* pChild = pNode; if (!cSubPath.IsEmpty()) { pChild = pNode->Insert(cSubPath); if (pChild == NULL) { delete pNode; return NULL; } } m_cChildren.AddTail(pNode); return pChild; }