windows-nt/Source/XPSP1/NT/admin/snapin/dsadmin/xmlutil.cpp
2020-09-26 16:20:57 +08:00

633 lines
14 KiB
C++

#include "stdafx.h"
#include "xmlutil.h"
/////////////////////////////////////////////////////
// helpers for encoding and decoding of C++
// data structures to and from XML PCDATA fields
WCHAR EncodeByteToWchar(IN BYTE b)
{
ASSERT(b <= 0x0f); // low nibble
if(b <= 9)
return static_cast<WCHAR>(b + L'0');
else
return static_cast<WCHAR>((b-10) + L'a');
}
BYTE DecodeWcharToByte(IN WCHAR ch)
{
BYTE byte = 0;
if ((ch >= L'0') && (ch <= L'9'))
{
byte = static_cast<BYTE>((ch - L'0') & 0xff);
}
else if ((ch >= L'a') && (ch <= L'f'))
{
byte = static_cast<BYTE>(((ch - L'a')+10) & 0xff);
}
else if ((ch >= L'A') && (ch <= L'F'))
{
byte = static_cast<BYTE>(((ch - L'A')+10) & 0xff);
}
else
{
ASSERT(FALSE);
byte = 0xFF;
}
return byte;
}
HRESULT EncodeBlobToBSTR(IN BYTE* pBlob, IN ULONG nBytes, OUT BSTR* pBstr)
{
ASSERT(pBstr != NULL);
*pBstr = NULL;
if ((pBlob == NULL) || (nBytes == 0))
{
return E_POINTER;
}
ULONG nChars = 2*nBytes;
*pBstr = SysAllocStringLen(NULL, nChars);
if (*pBstr == NULL)
{
return E_OUTOFMEMORY;
}
WCHAR* pCurr = *pBstr;
for (ULONG k=0; k< nBytes; k++)
{
*pCurr = EncodeByteToWchar(static_cast<BYTE>((pBlob[k]>>4) & 0xff));
pCurr++;
*pCurr = EncodeByteToWchar(static_cast<BYTE>(pBlob[k] & 0x0f));
pCurr++;
}
return S_OK;
}
void DecodeLoop(IN LPCWSTR lpsz, OUT BYTE* pByte, OUT ULONG nBytes)
{
for (ULONG k=0; k< nBytes; k++)
{
BYTE bHigh = DecodeWcharToByte(lpsz[2*k]);
BYTE bLow = DecodeWcharToByte(lpsz[(2*k)+1]);
pByte[k] = static_cast<BYTE>((bHigh<<4) | bLow);
}
}
HRESULT DecodeBSTRtoBlob(IN BSTR bstr, OUT BYTE** ppByte, OUT ULONG* pnBytes)
{
*ppByte = NULL;
*pnBytes = 0;
if ((bstr == NULL) || (ppByte == NULL) || (pnBytes == NULL))
{
// bad parameters
return E_POINTER;
}
// compute the length of the BSTR
ULONG nChars = static_cast<ULONG>(wcslen(bstr));
if (nChars == 0)
{
return E_INVALIDARG;
}
// must be even
size_t nBytes = nChars/2;
if (nBytes*2 != nChars)
{
return E_INVALIDARG;
}
// allocate memory and set the buffer length
*ppByte = (BYTE*)malloc(nBytes);
if (*ppByte == NULL)
{
return E_OUTOFMEMORY;
}
*pnBytes = static_cast<ULONG>(nBytes);
DecodeLoop(bstr, *ppByte, static_cast<UINT>(nBytes));
return TRUE;
}
//
// given a BSTR containing the encoding of a struct
// it loads it into a buffer, pByte of size nBytes
//
HRESULT DecodeBSTRtoStruct(IN BSTR bstr, IN BYTE* pByte, IN ULONG nBytes)
{
ASSERT(pByte != NULL);
ASSERT(pByte != NULL);
if ( (bstr == NULL) && (pByte == NULL) )
{
// bad parameters
return E_POINTER;
}
// compute the length of the BSTR
size_t nChars = wcslen(bstr);
if (nChars == 0)
{
return E_INVALIDARG;
}
// must be even (because of encoding)
ULONG nBstrBytes = static_cast<ULONG>(nChars/2);
if (nBstrBytes*2 != nChars)
{
ASSERT(FALSE);
return E_INVALIDARG;
}
// must match the struct length
if (nBstrBytes != nBytes)
{
ASSERT(FALSE);
return E_INVALIDARG;
}
DecodeLoop(bstr, pByte, nBytes);
return S_OK;
}
HRESULT EncodeBoolToBSTR(IN BOOL b, OUT BSTR* pBstr)
{
if (pBstr == NULL)
{
return E_POINTER;
}
*pBstr = SysAllocString(b ? L"TRUE" : L"FALSE");
if (*pBstr == NULL)
{
return E_OUTOFMEMORY;
}
return S_OK;
}
HRESULT DecodeBSTRtoBool(IN BSTR bstr, OUT BOOL* pb)
{
if (bstr == NULL)
{
return E_INVALIDARG;
}
if (pb == NULL)
{
return E_POINTER;
}
if (CompareNoCase(bstr, L"TRUE"))
{
*pb = TRUE;
return S_OK;
}
if (CompareNoCase(bstr, L"FALSE"))
{
*pb = FALSE;
return S_OK;
}
return E_INVALIDARG;
}
/*
HRESULT EncodeIntToBSTR(IN int n, OUT BSTR* pBstr)
{
int i = n;
pBstr = NULL;
return E_NOTIMPL;
}
HRESULT DecodeIntToBool(IN BSTR bstr, OUT int* pN)
{
//
// This doesn't do anything useful
//
*pN = 0;
return E_NOTIMPL;
}
*/
///////////////////////////////////////////////////////////////////////
// XML SPECIFIC FUNCTIONS
///////////////////////////////////////////////////////////////////////
//
// given an XML node, it retrieves the node name
// and compares it with the given string
//
BOOL XMLIsNodeName(IXMLDOMNode* pXDN, LPCWSTR lpszName)
{
ASSERT(lpszName != NULL);
ASSERT(pXDN != NULL);
CComBSTR bstrName;
HRESULT hr = pXDN->get_nodeName(&bstrName);
ASSERT(SUCCEEDED(hr));
if (FAILED(hr))
{
return FALSE;
}
return CompareXMLTags(bstrName, lpszName);
}
//
// given an XML node of type NODE_TEXT, it
// returns its value into a BSTR
//
HRESULT XML_GetNodeText(IXMLDOMNode* pXDN, BSTR* pBstr)
{
ASSERT(pXDN != NULL);
ASSERT(pBstr != NULL);
// null out output value
*pBstr = NULL;
// assume the given node has a child node
CComPtr<IXMLDOMNode> spName;
HRESULT hr = pXDN->get_firstChild(&spName);
if (FAILED(hr))
{
// unexpected failure
return hr;
}
// if no children, the api returns S_FALSE
if (spName == NULL)
{
return hr;
}
// got now a valid pointer,
// check if this is the valid node type
DOMNodeType nodeType;
hr = spName->get_nodeType(&nodeType);
ASSERT(hr == S_OK);
ASSERT(nodeType == NODE_TEXT);
if (nodeType != NODE_TEXT)
{
ASSERT(FALSE);
return E_INVALIDARG;
}
// it is of type text
// retrieve the node value into a variant
CComVariant val;
hr = pXDN->get_nodeTypedValue(&val);
if (FAILED(hr))
{
// unexpected failure
ASSERT(FALSE);
return hr;
}
if (val.vt != VT_BSTR)
{
ASSERT(FALSE);
return E_INVALIDARG;
}
// got the text value, package it into a BSTR
*pBstr = ::SysAllocString(val.bstrVal);
return S_OK;
}
//
// given an XML node of type NODE_TEXT, containing an encoding of
// a struct and given a buffer pByte of length nBytes, it decodes the
// node and fills it in the buffer
//
HRESULT XML_GetNodeStruct(IXMLDOMNode* pXDN, BYTE* pByte, ULONG nBytes)
{
CComBSTR bstr;
HRESULT hr = XML_GetNodeText(pXDN, &bstr);
if (FAILED(hr))
{
return hr;
}
return DecodeBSTRtoStruct(bstr, pByte, nBytes);
}
//
// given an XML node of type NODE_TEXT, containing an encoding of
// a blob it decodes the string and allocates *pnBytes of memory
// and fills it in the buffer
//
HRESULT XML_GetNodeBlob(IXMLDOMNode* pXDN, BYTE** ppByte, ULONG* pnBytes)
{
CComBSTR bstr;
HRESULT hr = XML_GetNodeText(pXDN, &bstr);
if (FAILED(hr))
{
return hr;
}
return DecodeBSTRtoBlob(bstr, ppByte, pnBytes);
}
//
// given an XML node of type NODE_TEXT, containing an encoding of
// a BOOL value it returns a value into a BOOL*
//
HRESULT XML_GetNodeBOOL(IXMLDOMNode* pXDN, BOOL* pb)
{
CComBSTR bstr;
HRESULT hr = XML_GetNodeText(pXDN, &bstr);
if (FAILED(hr))
{
return hr;
}
return DecodeBSTRtoBool(bstr, pb);
}
HRESULT XML_GetNodeDWORD(IXMLDOMNode* pXDN, DWORD* pdw)
{
CComBSTR bstr;
HRESULT hr = XML_GetNodeText(pXDN, &bstr);
if (FAILED(hr))
{
return hr;
}
long lVal = _wtol(bstr);
*pdw = static_cast<DWORD>(lVal);
return hr;
}
//
// given an XML node and a tag for a node, it
// searches the subtree (depth first) to find the
// first occurrence and returns the associated XML node
//
HRESULT XML_FindSubtreeNode(IXMLDOMNode* pXMLCurrentRootNode,
LPCWSTR lpszNodeTag,
IXMLDOMNode** ppXMLNode)
{
ASSERT(pXMLCurrentRootNode != NULL);
ASSERT(lpszNodeTag != NULL);
ASSERT(ppXMLNode != NULL);
*ppXMLNode = NULL; // null out return value
// get the list of child nodes
CComPtr<IXMLDOMNode> spCurrChild;
HRESULT hr = pXMLCurrentRootNode->get_firstChild(&spCurrChild);
if (FAILED(hr))
{
return hr;
}
if (spCurrChild == NULL)
{
return S_OK; // end of the recursion
}
// recurse down on children
while (spCurrChild != NULL)
{
CComBSTR bstrChildName;
hr = spCurrChild->get_nodeName(&bstrChildName);
if (FAILED(hr))
{
return hr;
}
if (bstrChildName != NULL)
{
//wprintf(L"bstrChildName = %s\n", bstrChildName);
if (CompareXMLTags(bstrChildName, lpszNodeTag))
{
// got the node we want
(*ppXMLNode) = spCurrChild;
(*ppXMLNode)->AddRef();
return S_OK;
}
}
// go down recursively on the current child
hr = XML_FindSubtreeNode(spCurrChild, lpszNodeTag, ppXMLNode);
if (FAILED(hr))
{
return hr;
}
if (*ppXMLNode != NULL)
{
// got it from the recursion, just return
return S_OK;
}
// keep going to the next child node
CComPtr<IXMLDOMNode> spTemp = spCurrChild;
spCurrChild = NULL;
spTemp->get_nextSibling(&spCurrChild);
}
// not found in the recursion and in the loop above
// need to return S_OK, we will check the output pointer
return S_OK;
}
//
// function to walk the list of children of a node
// and print some information
// NOTICE: this is for debugging and learning purposes
// more than for getting real info
//
void XML_PrintTreeRaw(IXMLDOMNode* pXDN, int nLevel)
{
PrintIdentation(nLevel);
//
// get the name and type of the node
//
CComBSTR bstrName;
pXDN->get_nodeName(&bstrName);
CComBSTR bstrType;
pXDN->get_nodeTypeString(&bstrType);
DOMNodeType nodeType;
pXDN->get_nodeType(&nodeType);
TRACE(L"Name = %s, Type = %d (%s) ", bstrName, nodeType, bstrType);
if (nodeType == NODE_TEXT)
{
CComVariant val;
pXDN->get_nodeTypedValue(&val);
if (val.vt == VT_BSTR)
{
TRACE(L"Val = %s", val.bstrVal);
}
}
TRACE(L"\n");
// get the list of child nodes
CComPtr<IXMLDOMNode> spCurrChild;
pXDN->get_firstChild(&spCurrChild);
if (spCurrChild == NULL)
{
return;
}
// recurse down on children
while (spCurrChild != NULL)
{
XML_PrintTreeRaw(spCurrChild, nLevel+1);
CComPtr<IXMLDOMNode> temp = spCurrChild;
spCurrChild = NULL;
temp->get_nextSibling(&spCurrChild);
}
}
void PrintIdentation(int iLevel)
{
for (int k=0; k<iLevel;k++)
{
// wprintf(L" ");
TRACE(L" ");
}
}
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
//
// given an XML document,it creates an XML node of the given type
// and with the given name
//
HRESULT XML_CreateDOMNode(IXMLDOMDocument* pDoc,
DOMNodeType type, LPCWSTR lpszName,
IXMLDOMNode** ppXMLDOMNode)
{
*ppXMLDOMNode = NULL;
CComVariant vtype((long)type, VT_I4);
CComBSTR bstrName = lpszName;
HRESULT hr = pDoc->createNode(vtype, bstrName, NULL, ppXMLDOMNode);
return hr;
}
HRESULT XML_AppendChildDOMNode(IXMLDOMNode* pXMLContainerNode,
IXMLDOMNode* pXMLChildNode)
{
CComPtr<IXMLDOMNode> p;
CComVariant after;
after.vt = VT_EMPTY;
HRESULT hr = pXMLContainerNode->appendChild(pXMLChildNode, &p);
return hr;
}
HRESULT XML_CreateTextDataNode(IXMLDOMDocument* pXMLDoc,
LPCWSTR lpszNodeTag,
LPCWSTR lpszNodeData,
IXMLDOMNode** ppNode)
{
*ppNode = NULL;
CComPtr<IXMLDOMNode> spXMLDOMNodeName;
HRESULT hr = XML_CreateDOMNode(pXMLDoc, NODE_ELEMENT, lpszNodeTag, &spXMLDOMNodeName);
RETURN_IF_FAILED(hr);
CComPtr<IXMLDOMNode> spXMLDOMNodeNameval;
hr = XML_CreateDOMNode(pXMLDoc, NODE_TEXT, NULL, &spXMLDOMNodeNameval);
RETURN_IF_FAILED(hr);
CComVariant val = lpszNodeData;
spXMLDOMNodeNameval->put_nodeTypedValue(val);
hr = XML_AppendChildDOMNode(spXMLDOMNodeName, spXMLDOMNodeNameval);
RETURN_IF_FAILED(hr);
(*ppNode) = spXMLDOMNodeName;
(*ppNode)->AddRef();
return hr;
}
HRESULT XML_CreateStructDataNode(IXMLDOMDocument* pXMLDoc,
LPCWSTR lpszNodeTag,
BYTE* pByte, ULONG nBytes,
IXMLDOMNode** ppNode)
{
CComBSTR bstr;
HRESULT hr = EncodeBlobToBSTR(pByte, nBytes, &bstr);
RETURN_IF_FAILED(hr);
return XML_CreateTextDataNode(pXMLDoc, lpszNodeTag, bstr, ppNode);
}
HRESULT XML_CreateBOOLDataNode(IXMLDOMDocument* pXMLDoc,
LPCWSTR lpszNodeTag,
BOOL b,
IXMLDOMNode** ppNode)
{
CComBSTR bstr;
HRESULT hr = EncodeBoolToBSTR(b, &bstr);
RETURN_IF_FAILED(hr);
return XML_CreateTextDataNode(pXMLDoc, lpszNodeTag, bstr, ppNode);
}
HRESULT XML_CreateDWORDDataNode(IXMLDOMDocument* pXMLDoc,
LPCWSTR lpszNodeTag,
DWORD dwVal,
IXMLDOMNode** ppNode)
{
CString szTemp;
szTemp.Format(L"%d", dwVal);
CComBSTR bstr;
bstr = szTemp.AllocSysString();
return XML_CreateTextDataNode(pXMLDoc, lpszNodeTag, bstr, ppNode);
}
HRESULT XML_AppendStructDataNode(IXMLDOMDocument* pXMLDoc,
IXMLDOMNode* pXMLNode,
LPCWSTR lpszNodeTag,
BYTE* pByte,
ULONG nBytes)
{
CComPtr<IXMLDOMNode> spXMLDOMNodeName;
HRESULT hr = XML_CreateStructDataNode(pXMLDoc, lpszNodeTag, pByte, nBytes, &spXMLDOMNodeName);
RETURN_IF_FAILED(hr);
return XML_AppendChildDOMNode(pXMLNode, spXMLDOMNodeName);
}
HRESULT XML_AppendTextDataNode(IXMLDOMDocument* pXMLDoc,
IXMLDOMNode* pXMLNode,
LPCWSTR lpszNodeTag,
LPCWSTR lpszNodeData)
{
CComPtr<IXMLDOMNode> spXMLDOMNodeName;
HRESULT hr = XML_CreateTextDataNode(pXMLDoc, lpszNodeTag, lpszNodeData, &spXMLDOMNodeName);
RETURN_IF_FAILED(hr);
return hr = XML_AppendChildDOMNode(pXMLNode, spXMLDOMNodeName);
}
HRESULT XML_AppendBOOLDataNode(IXMLDOMDocument* pXMLDoc,
IXMLDOMNode* pXMLNode,
LPCWSTR lpszNodeTag,
BOOL b)
{
CComPtr<IXMLDOMNode> spXMLDOMNodeName;
HRESULT hr = XML_CreateBOOLDataNode(pXMLDoc, lpszNodeTag, b, &spXMLDOMNodeName);
RETURN_IF_FAILED(hr);
return hr = XML_AppendChildDOMNode(pXMLNode, spXMLDOMNodeName);
}
HRESULT XML_AppendDWORDDataNode(IXMLDOMDocument* pXMLDoc,
IXMLDOMNode* pXMLNode,
LPCWSTR lpszNodeTag,
DWORD dwVal)
{
CComPtr<IXMLDOMNode> spXMLDOMNodeName;
HRESULT hr = XML_CreateDWORDDataNode(pXMLDoc, lpszNodeTag, dwVal, &spXMLDOMNodeName);
RETURN_IF_FAILED(hr);
return XML_AppendChildDOMNode(pXMLNode, spXMLDOMNodeName);
}