windows-nt/Source/XPSP1/NT/admin/activec/locparser/xml_supp.cpp

405 lines
11 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//------------------------------------------------------------------------------
//
// File: xml_supp.cpp
// Copyright (C) 1995-2000 Microsoft Corporation
// All rights reserved.
//
// Purpose:
// implements helper functions for parsing XML document
//
//------------------------------------------------------------------------------
#include "stdafx.h"
#include "xml_supp.h"
// include "strings.h" to get tag names and attribute names for XML elements in MSC file
#define INIT_MMC_BASE_STRINGS
#include "strings.h"
// note if you want to untie the project from MMC, copy the definitions for
// the following strings from strings.h here:
/*
XML_TAG_MMC_CONSOLE_FILE;
XML_TAG_MMC_STRING_TABLE;
XML_TAG_STRING_TABLE_MAP;
XML_TAG_STRING_TABLE;
XML_TAG_VALUE_GUID;
XML_TAG_STRING_TABLE_STRING;
XML_ATTR_STRING_TABLE_STR_ID;
*/
LPCSTR strXMLStringTablePath[] = { XML_TAG_MMC_CONSOLE_FILE,
XML_TAG_MMC_STRING_TABLE,
XML_TAG_STRING_TABLE_MAP };
/***************************************************************************\
*
* METHOD: LocateNextElementNode
*
* PURPOSE: locates sibling node of type ELEMENT
*
* PARAMETERS:
* IXMLDOMNode *pNode [in] - node which sibling to locate
* IXMLDOMNode **ppNode [out] - sibling node
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
static HRESULT LocateNextElementNode(IXMLDOMNode *pNode, IXMLDOMNode **ppNode)
{
// parameter check
if (ppNode == NULL)
return E_INVALIDARG;
// init out parameter
*ppNode = NULL;
// check [in] parameter
if (pNode == NULL)
return E_INVALIDARG;
// loop thru siblings
CComPtr<IXMLDOMNode> spCurrNode = pNode;
CComPtr<IXMLDOMNode> spResultNode;
while (1)
{
// get sibling node
HRESULT hr = spCurrNode->get_nextSibling(&spResultNode);
if (FAILED(hr))
return hr;
// check the pointer
if (spResultNode == NULL)
return E_FAIL; // not found
// done if it's ELEMENT node
DOMNodeType elType = NODE_INVALID;
spResultNode->get_nodeType(&elType);
if (elType == NODE_ELEMENT)
{
*ppNode = spResultNode.Detach();
return S_OK;
}
// get to the next one
spCurrNode = spResultNode;
}
return E_UNEXPECTED;
}
/***************************************************************************\
*
* METHOD: OpenXMLStringTable
*
* PURPOSE: Opens XML document and locates string table node in it
*
* PARAMETERS:
* LPCWSTR lpstrFileName - [in] file to load document from
* IXMLDOMNode **ppStringTableNode - [out] pointer to node containing string table
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
HRESULT OpenXMLStringTable(LPCWSTR lpstrFileName, IXMLDOMNode **ppStringTableNode)
{
// do parameter check
if (lpstrFileName == NULL || ppStringTableNode == NULL)
return E_INVALIDARG;
// init return value
*ppStringTableNode = NULL;
// cocreate xml document
CComQIPtr<IXMLDOMDocument> spDocument;
HRESULT hr = spDocument.CoCreateInstance(CLSID_DOMDocument);
if (FAILED(hr))
return hr;
// prevent re-formating
spDocument->put_preserveWhiteSpace(VARIANT_TRUE);
// load the file
VARIANT_BOOL bOK = VARIANT_FALSE;
hr = spDocument->load(CComVariant(lpstrFileName), &bOK);
if (hr != S_OK || bOK != VARIANT_TRUE)
return FAILED(hr) ? hr : E_FAIL;
// the path represents element tags in similar to the file system manner
// so 'c' from <a><b><c/></b></a> can be selected by "a/b/c"
// construct the path
std::string strPath;
for (int i = 0; i< sizeof(strXMLStringTablePath)/sizeof(strXMLStringTablePath[0]); i++)
strPath.append(i > 0 ? 1 : 0, '/' ).append(strXMLStringTablePath[i]);
// locate required node
hr = spDocument->selectSingleNode(CComBSTR(strPath.c_str()), ppStringTableNode);
if (FAILED(hr))
return hr;
return S_OK;
}
/***************************************************************************\
*
* METHOD: SaveXMLContents
*
* PURPOSE: Saves XML document to file
*
* PARAMETERS:
* LPCWSTR lpstrFileName [in] - file to save to
* IXMLDOMNode *pStringTableNode [in] - pointer to <any> document's element
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
HRESULT SaveXMLContents(LPCWSTR lpstrFileName, IXMLDOMNode *pStringTableNode)
{
// do parameter check
if (lpstrFileName == NULL || pStringTableNode == NULL)
return E_INVALIDARG;
// get the document
CComQIPtr<IXMLDOMDocument> spDocument;
HRESULT hr = pStringTableNode->get_ownerDocument(&spDocument);
if (FAILED(hr))
return hr;
// save the file
hr = spDocument->save(CComVariant(lpstrFileName));
if (FAILED(hr))
return hr;
return S_OK;
}
/***************************************************************************\
*
* METHOD: GetXMLElementContents
*
* PURPOSE: retuns XML text elements' contents as BSTR
*
* PARAMETERS:
* IXMLDOMNode *pNode [in] - node which contents is requested
* CComBSTR& bstrResult [out] - resulting string
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
HRESULT GetXMLElementContents(IXMLDOMNode *pNode, CComBSTR& bstrResult)
{
// init result
bstrResult.Empty();
// parameter check
if (pNode == NULL)
return E_INVALIDARG;
// locate required node
CComQIPtr<IXMLDOMNode> spTextNode;
HRESULT hr = pNode->selectSingleNode(CComBSTR(L"text()"), &spTextNode);
if (FAILED(hr))
return hr;
// recheck the pointer
if (spTextNode == NULL)
return E_POINTER;
// done
return spTextNode->get_text(&bstrResult);
}
/***************************************************************************\
*
* METHOD: ReadXMLStringTables
*
* PURPOSE: Reads string tables to std::map - based structure
*
* PARAMETERS:
* IXMLDOMNode *pNode [in] - string table node
* CStringTableMap& mapResult [out] - map containing string tables
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
HRESULT ReadXMLStringTables(IXMLDOMNode *pNode, CStringTableMap& mapResult)
{
mapResult.clear();
// parameter check
if (pNode == NULL)
return E_INVALIDARG;
// get the node list
CComQIPtr<IXMLDOMNodeList> spGUIDNodes;
HRESULT hr = pNode->selectNodes(CComBSTR(XML_TAG_VALUE_GUID), &spGUIDNodes);
if (FAILED(hr))
return hr;
// recheck the pointer
if (spGUIDNodes == NULL)
return E_POINTER;
// get the item count
long length = 0;
hr = spGUIDNodes->get_length(&length);
if (FAILED(hr))
return hr;
// read the items
for (int n = 0; n < length; n++)
{
// get one node
CComQIPtr<IXMLDOMNode> spGUIDNode;
hr = spGUIDNodes->get_item(n, &spGUIDNode);
if (FAILED(hr))
return hr;
// read the text
CComBSTR bstrLastGUID;
hr = GetXMLElementContents(spGUIDNode, bstrLastGUID);
if (FAILED(hr))
return hr;
// Add the entry to the map;
CStringMap& rMapStrings = mapResult[static_cast<LPOLESTR>(bstrLastGUID)];
//get the strings node following the guid
CComPtr<IXMLDOMNode> spStringsNode;
hr = LocateNextElementNode(spGUIDNode, &spStringsNode);
if (FAILED(hr))
return hr;
// recheck
if (spStringsNode == NULL)
return E_POINTER;
// select strings for this guid
CComQIPtr<IXMLDOMNodeList> spStringNodeList;
HRESULT hr = spStringsNode->selectNodes(CComBSTR(XML_TAG_STRING_TABLE_STRING), &spStringNodeList);
if (FAILED(hr))
return hr;
// recheck the pointer
if (spStringNodeList == NULL)
return E_POINTER;
// count the strings
long nStrCount = 0;
hr = spStringNodeList->get_length(&nStrCount);
if (FAILED(hr))
return hr;
// add all the strings to map
CComQIPtr<IXMLDOMNode> spStringNode;
for(int iStr = 0; iStr < nStrCount; iStr++)
{
// get n-th string
spStringNode.Release();
hr = spStringNodeList->get_item(iStr, &spStringNode);
if (FAILED(hr))
return hr;
CComQIPtr<IXMLDOMElement> spElement = spStringNode;
if (spElement == NULL)
return E_UNEXPECTED;
// get string id
CComVariant val;
hr = spElement->getAttribute(CComBSTR(XML_ATTR_STRING_TABLE_STR_ID), &val);
if (FAILED(hr))
continue;
DWORD dwID = val.bstrVal ? wcstoul(val.bstrVal, NULL, 10) : 0;
// get string text
CComBSTR bstrText;
hr = GetXMLElementContents(spStringNode, bstrText);
if (FAILED(hr))
return hr;
// add to the map
rMapStrings[dwID] = bstrText;
}
}
return S_OK;
}
/***************************************************************************\
*
* METHOD: UpdateXMLString
*
* PURPOSE: Updates string in string table
*
* PARAMETERS:
* IXMLDOMNode *pNode [in] - string tables
* const std::wstring& strGUID [in] - GUID of string table
* DWORD ID [in] - id of string
* const std::wstring& strNewVal [in] - new value for string
*
* RETURNS:
* HRESULT - result code
*
\***************************************************************************/
HRESULT UpdateXMLString(IXMLDOMNode *pNode, const std::wstring& strGUID, DWORD ID, const std::wstring& strNewVal)
{
// parameter check
if (pNode == NULL)
return E_INVALIDARG;
USES_CONVERSION;
// locate the GUID node
std::wstring strTagGUID(T2CW(XML_TAG_VALUE_GUID));
std::wstring strGUIDPattern( strTagGUID + L"[text() = \"" + strGUID + L"\"]" );
CComQIPtr<IXMLDOMNode> spGUIDNode;
HRESULT hr = pNode->selectSingleNode(CComBSTR(strGUIDPattern.c_str()), &spGUIDNode);
if (FAILED(hr))
return hr;
// recheck
if (spGUIDNode == NULL)
return E_POINTER;
//get the strings node following the guid
CComPtr<IXMLDOMNode> spStringsNode;
hr = LocateNextElementNode(spGUIDNode, &spStringsNode);
if (FAILED(hr))
return hr;
// recheck
if (spStringsNode == NULL)
return E_POINTER;
// locate the string node by ID (actually its text node)
CString strPattern;
strPattern.Format("%s[@%s = %d]/text()", XML_TAG_STRING_TABLE_STRING,
XML_ATTR_STRING_TABLE_STR_ID, ID);
CComQIPtr<IXMLDOMNode> spTextNode;
hr = spStringsNode->selectSingleNode(CComBSTR(strPattern), &spTextNode);
if (FAILED(hr))
return hr;
// recheck
if (spTextNode == NULL)
return E_POINTER;
// set the contents
hr = spTextNode->put_text(CComBSTR(strNewVal.c_str()));
if (FAILED(hr))
return hr;
return S_OK; // done
}