// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved #include "stdafx.h" #include "serialization.h" #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// // CXMLDataSaver::CXMLDataSaver() { } CXMLDataSaver::~CXMLDataSaver() { } HRESULT CXMLDataSaver::Init(LPCWSTR docName) { HRESULT hr = S_OK; CComPtr pXDN; CComPtr tempNode; m_spXMLDoc.Release(); IFC( CoCreateInstance(__uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument2), (void**)&m_spXMLDoc) ); IFC( m_spXMLDoc->QueryInterface(IID_IXMLDOMNode, (void **)&pXDN) ); // Create root node m_spRootNode.Release(); VARIANT var; var.intVal = NODE_ELEMENT; var.vt = VT_INT; IFC( m_spXMLDoc->createNode(var, CComBSTR(docName), NULL, &tempNode) ); IFC( pXDN->appendChild(tempNode, &m_spRootNode) ); Cleanup: assert(!FAILED(hr)); return hr; } HRESULT CXMLDataSaver::BeginSaveObject(LPCWSTR name) { HRESULT hr = S_OK; m_spCurrObjNode.Release(); CComVariant var; var.intVal = NODE_ELEMENT; var.vt = VT_INT; CComPtr tempNode; IFC( m_spXMLDoc->createNode(var, CComBSTR(name), NULL, &tempNode) ); IFC( m_spRootNode->appendChild(tempNode, &m_spCurrObjNode) ); Cleanup: assert(!FAILED(hr)); return hr; } HRESULT CXMLDataSaver::BeginSaveChildObjects() { SaveContext SCtx; SCtx.m_spRootNode = m_spRootNode; SCtx.m_spCurrObjNode = m_spCurrObjNode; m_arrSaveContexts.Add(SCtx); m_spRootNode = m_spCurrObjNode; return S_OK; } HRESULT CXMLDataSaver::EndSaveChildObjects() { if(!m_arrSaveContexts.IsEmpty()) { size_t nLastNode = m_arrSaveContexts.GetCount() - 1; SaveContext SCtx = m_arrSaveContexts.GetAt(nLastNode); m_arrSaveContexts.RemoveAt(nLastNode); m_spRootNode = SCtx.m_spRootNode; m_spCurrObjNode = SCtx.m_spCurrObjNode; } return S_OK; } HRESULT CXMLDataSaver::SaveData(LPCWSTR strName, LPCWSTR strValue) { HRESULT hr = S_OK; CComPtr tempNode; CComPtr propertyNode; CComPtr propertyElement; IFC( m_spXMLDoc->createNode(CComVariant(NODE_ELEMENT), CComBSTR(strName), NULL, &tempNode) ); IFC( m_spCurrObjNode->appendChild(tempNode, &propertyNode) ); IFC( propertyNode->QueryInterface(IID_IXMLDOMElement, (void**) &propertyElement) ); IFC( propertyElement->setAttribute(CComBSTR(L"Value"), CComVariant(strValue)) ); Cleanup: assert(!FAILED(hr)); return hr; } HRESULT CXMLDataSaver::SaveToFile(LPCWSTR fileName) { HRESULT hr = S_OK; CComVariant varFileName(fileName); IFC( m_spXMLDoc->save(varFileName) ); Cleanup: assert(!FAILED(hr)); return hr; } ////////////////////////////////////////////////////////////////////////// // // We will not be saving any files with 1000+ character strings, so we will treat any files that have such strings as corrupt const UINT CXMLDataLoader::MAX_STRING_LENGTH = 1000; CXMLDataLoader::CXMLDataLoader() { } CXMLDataLoader::~CXMLDataLoader() { } HRESULT CXMLDataLoader::HasNextObject(BOOL* pfHasNextObject) { if(NULL == pfHasNextObject) { return E_POINTER; } *pfHasNextObject = (m_spNextObjNode.p != NULL); return S_OK; } HRESULT CXMLDataLoader::GetNextObject(__out LPWSTR* strName) { USES_CONVERSION; HRESULT hr = S_OK; CComBSTR nodeName; if(NULL == strName) { IFC( E_POINTER ); } m_spCurrObjNode = m_spNextObjNode; IFC( LoadNextObject() ); assert(m_spCurrObjNode != NULL); IFC( m_spCurrObjNode->get_nodeName(&nodeName) ); if(nodeName.Length() > MAX_STRING_LENGTH) { IFC( STRSAFE_E_INVALID_PARAMETER ); } if(nodeName.Length() + 1 < nodeName.Length()) { return E_INVALIDARG; } DWORD cbAlloc = 0; IFC( DWordMult(nodeName.Length() + 1, sizeof(WCHAR), &cbAlloc) ); *strName = (LPWSTR) CoTaskMemAlloc(cbAlloc); if(!*strName) IFC( E_OUTOFMEMORY ); IFC( StringCchCopyN(*strName, nodeName.Length() + 1, nodeName, nodeName.Length()) ); (*strName)[nodeName.Length()] = 0; Cleanup: return hr; } HRESULT CXMLDataLoader::HasChildObjects(BOOL* pfHasChildObjects) { HRESULT hr = S_OK; CComPtr spChildList; if(NULL == pfHasChildObjects) { IFC(hr = E_POINTER); } IFC( m_spCurrObjNode->get_childNodes(&spChildList) ); long length; IFC( spChildList->get_length(&length) ); BOOL fHasChildObject = FALSE; for(long i = 0; i < length; i++) { CComPtr spChildNode; IFC( spChildList->nextNode(&spChildNode) ); DOMNodeType nodeType; IFC( spChildNode->get_nodeType(&nodeType) ); if(nodeType == NODE_ELEMENT) { fHasChildObject = TRUE; break; } } *pfHasChildObjects = fHasChildObject; Cleanup: return hr; } HRESULT CXMLDataLoader::BeginLoadChildObjects() { HRESULT hr = S_OK; LoadContext LCtx; BOOL fHasChildObjects; IFC( HasChildObjects(&fHasChildObjects) ); if(!fHasChildObjects) IFC( hr = E_FAIL ); LCtx.m_spObjectList = m_spObjectList; LCtx.m_spCurrObjNode = m_spCurrObjNode; LCtx.m_spNextObjNode = m_spNextObjNode; m_arrLoadContexts.Add(LCtx); m_spObjectList.Release(); IFC( m_spCurrObjNode->get_childNodes(&m_spObjectList) ); IFC( LoadNextObject() ); Cleanup: return hr; } HRESULT CXMLDataLoader::EndLoadChildObjects() { HRESULT hr = S_OK; size_t nLastObj = m_arrLoadContexts.GetCount() - 1; LoadContext LCtx = m_arrLoadContexts.GetAt(nLastObj); m_arrLoadContexts.RemoveAt(nLastObj); m_spObjectList = LCtx.m_spObjectList; m_spCurrObjNode = LCtx.m_spCurrObjNode; m_spNextObjNode = LCtx.m_spNextObjNode; return hr; } HRESULT CXMLDataLoader::LoadData(LPCWSTR strName, __out LPWSTR* strValue, long nIndex) { HRESULT hr = S_OK; CComPtr spChildList; CComPtr spAttributes; CComPtr spFoundNode; CComPtr spAttributeNode; CComVariant nodeValue; CComBSTR bstrValue; long nCurrentIndex = 0; IFC( m_spCurrObjNode->get_childNodes(&spChildList) ); long length; IFC(spChildList->get_length(&length)); for(long i = 0; i < length; i++) { CComPtr childNode; CComBSTR nodeName; IFC( spChildList->nextNode(&childNode) ); IFC( childNode->get_nodeName(&nodeName) ); if(nodeName == CAtlStringW::PCXSTR(strName)) { if(nIndex == nCurrentIndex) { spFoundNode = childNode; break; } else { nCurrentIndex++; } } } if(spFoundNode == NULL) { hr = MF_E_NOT_FOUND; goto Cleanup; } IFC( spFoundNode->get_attributes(&spAttributes) ); IFC( spAttributes->getNamedItem(CComBSTR(L"Value"), &spAttributeNode) ); IFC( spAttributeNode->get_nodeValue(&nodeValue) ); bstrValue = nodeValue.bstrVal; if(bstrValue.Length() > MAX_STRING_LENGTH) { IFC( STRSAFE_E_INVALID_PARAMETER ); } if(bstrValue.Length() + 1 < bstrValue.Length()) { IFC( E_INVALIDARG ); } DWORD cbAlloc = 0; IFC( DWordMult(bstrValue.Length() + 1, sizeof(WCHAR), &cbAlloc) ); *strValue = (LPWSTR) CoTaskMemAlloc(cbAlloc); if(!*strValue) IFC( E_OUTOFMEMORY ); StringCchCopyN(*strValue, bstrValue.Length() + 1, bstrValue, bstrValue.Length()); (*strValue)[bstrValue.Length()] = 0; Cleanup: return hr; } HRESULT CXMLDataLoader::LoadFromFile(LPCWSTR fileName, LPCWSTR docName) { HRESULT hr = S_OK; CComPtr spChildList; CComBSTR nodeName; m_spXMLDoc.Release(); IFC( CoCreateInstance(__uuidof(DOMDocument60), NULL, CLSCTX_INPROC_SERVER, __uuidof(IXMLDOMDocument2), (void**)&m_spXMLDoc) ); VARIANT_BOOL varSucceeded; IFC( m_spXMLDoc->load(CComVariant(fileName), &varSucceeded) ); IFC( m_spXMLDoc->get_childNodes(&spChildList) ); long length; IFC(spChildList->get_length(&length)); if(length != 1) { hr = MF_E_INVALID_FILE_FORMAT; goto Cleanup; } m_spRootNode.Release(); IFC( spChildList->nextNode(&m_spRootNode) ); IFC( m_spRootNode->get_nodeName(&nodeName) ); if(nodeName != CAtlStringW::PCXSTR(docName)) { hr = MF_E_INVALID_FILE_FORMAT; goto Cleanup; } m_spObjectList.Release(); IFC( m_spRootNode->get_childNodes(&m_spObjectList) ); IFC( LoadNextObject() ); Cleanup: return hr; } HRESULT CXMLDataLoader::LoadNextObject() { HRESULT hr = S_OK; HRESULT hrAttribute = S_OK; do { CComPtr spElement; m_spNextObjNode.Release(); hr = m_spObjectList->nextNode(&m_spNextObjNode); if(hr == S_FALSE) { break; } IFC( m_spNextObjNode->QueryInterface(IID_IXMLDOMElement, (void**) &spElement) ); VARIANT var; hrAttribute = spElement->getAttribute(CComBSTR(L"Value"), &var); } while(hrAttribute != S_FALSE); Cleanup: return hr; }