| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- //-------------------------------------------------------------------------------------------------------
- // Copyright (C) Microsoft. All rights reserved.
- // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
- //-------------------------------------------------------------------------------------------------------
- #include "rl.h"
- #include <objbase.h>
- #include <XmlLite.h>
- #define CHECKHR(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
- #define SAFERELEASE(p) {if (p) {(p)->Release(); p = NULL;}}
- namespace Xml
- {
- Node * Node::TopNode;
- //-----------------------------------------------------------------------------
- //
- // Description:
- //
- // Constructor for Attribute class.
- //
- //-----------------------------------------------------------------------------
- Attribute::Attribute
- (
- Char * name,
- Char * value
- )
- : Name(name)
- , Value(value)
- , Next(NULL)
- {}
- Char *
- Attribute::GetValue
- (
- const Char * name
- )
- {
- for (Attribute * p = this; p != NULL; p = p->Next)
- {
- if (strcmp(p->Name, name) == 0)
- {
- return p->Value;
- }
- }
- return NULL;
- }
- void
- Attribute::Dump()
- {
- for (Attribute * attr = this;
- attr != NULL;
- attr = attr->Next)
- {
- printf("%s=\"%s\"", attr->Name, attr->Value);
- if (attr->Next != NULL)
- {
- printf(" ");
- }
- }
- printf("\n");
- }
- //-----------------------------------------------------------------------------
- //
- // Description:
- //
- // Constructor for Node class.
- //
- //
- //-----------------------------------------------------------------------------
- Node::Node
- (
- const Char * name,
- Attribute * attributeList
- )
- : Name(name)
- , AttributeList(attributeList)
- , Next(NULL)
- , ChildList(NULL)
- , Data(NULL)
- // , LineNumber(Xml::LineNumber)
- {}
- Node *
- Node::GetChild
- (
- const Char * name
- )
- {
- for (Node * p = this->ChildList; p != NULL; p = p->Next)
- {
- if (strcmp(p->Name, name) == 0)
- {
- return p;
- }
- }
- return NULL;
- }
- Char *
- Node::GetAttributeValue
- (
- const Char * name
- )
- {
- return this->AttributeList->GetValue(name);
- }
- void
- Node::Dump
- (
- int indent
- )
- {
- for (int i = 0; i < indent; i++)
- {
- printf(" ");
- }
- printf("Node %s ", this->Name);
- this->AttributeList->Dump();
- if (this->Data != NULL)
- {
- for (int i = 0; i <= indent; i++)
- {
- printf(" ");
- }
- printf("Data: %s\n", this->Data);
- }
- else
- {
- for (Node * child = this->ChildList;
- child != NULL;
- child = child->Next)
- {
- child->Dump(indent + 1);
- }
- }
- }
- void
- Node::Dump()
- {
- this->Dump(0);
- }
- Char *
- ConvertWCHAR
- (
- const WCHAR * pWchar
- )
- {
- int len = ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pWchar, -1,
- NULL, 0, NULL, NULL);
- Char * newStr = new char[len + 1];
- ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pWchar, -1,
- newStr, len + 1, NULL, NULL);
- return newStr;
- }
- HRESULT
- ParseAttributes
- (
- IXmlReader * pReader,
- Attribute ** ppAttrList
- )
- {
- HRESULT hr;
- const WCHAR * tmpString;
- Attribute * attrLast = nullptr;
- while (S_OK == (hr = pReader->MoveToNextAttribute()))
- {
- pReader->GetLocalName(&tmpString, nullptr);
- Char * attrName = ConvertWCHAR(tmpString);
- pReader->GetValue(&tmpString, nullptr);
- Char * attrValue = ConvertWCHAR(tmpString);
- Attribute * attrItem = new Attribute(attrName, attrValue);
- if (attrLast != nullptr)
- {
- attrLast->Next = attrItem;
- }
- else
- {
- *ppAttrList = attrItem;
- }
- attrLast = attrItem;
- }
- return hr;
- }
- HRESULT
- ParseNode
- (
- IXmlReader * pReader,
- Node ** ppNode
- )
- {
- HRESULT hr;
- XmlNodeType nodeType;
- Char * nodeName = nullptr;
- Attribute * attrList = nullptr;
- Node * childList = nullptr;
- Node * childLast = nullptr;
- const WCHAR * tmpString;
- #define APPEND_CHILD(childNode) \
- if (childLast == nullptr) \
- { \
- childList = childLast = childNode; \
- } \
- else \
- { \
- childLast->Next = childNode; \
- childLast = childNode; \
- }
- // This call won't fail we make sure the reader is positioned at a valid
- // node before ParseNode() is called.
- pReader->GetNodeType(&nodeType);
- do
- {
- switch (nodeType)
- {
- case XmlNodeType_Element:
- {
- bool inOpenElement = nodeName != nullptr;
- if (inOpenElement)
- {
- Node * childNode;
- hr = ParseNode(pReader, &childNode);
- if (hr == S_OK)
- {
- APPEND_CHILD(childNode);
- }
- else
- {
- return hr;
- }
- }
- else
- {
- pReader->GetLocalName(&tmpString, nullptr);
- nodeName = ConvertWCHAR(tmpString);
- hr = ParseAttributes(pReader, &attrList);
- if (FAILED(hr))
- {
- *ppNode = nullptr;
- return hr;
- }
- *ppNode = new Node(nodeName, attrList);
- if (pReader->IsEmptyElement())
- {
- return S_OK;
- }
- }
- break;
- }
- case XmlNodeType_EndElement:
- {
- Node * node = *ppNode;
- // If we have a single child with data called "#text", then pull the data up to this node.
- if (childList != nullptr
- && childList == childLast
- && (childList->Data != nullptr)
- && (_stricmp(childList->Name, "#text") == 0))
- {
- node->Data = childList->Data;
- node->ChildList = nullptr;
- }
- else
- {
- node->ChildList = childList;
- }
- return S_OK;
- }
- case XmlNodeType_Attribute:
- // Need to manually move to attributes when at an element node.
- break;
- case XmlNodeType_CDATA:
- case XmlNodeType_Text:
- {
- pReader->GetValue(&tmpString, nullptr);
- Node * node = new Node("#text", nullptr);
- node->Data = ConvertWCHAR(tmpString);
- APPEND_CHILD(node);
- break;
- }
- case XmlNodeType_Comment:
- case XmlNodeType_DocumentType:
- case XmlNodeType_None:
- case XmlNodeType_ProcessingInstruction:
- case XmlNodeType_Whitespace:
- case XmlNodeType_XmlDeclaration:
- // Ignored.
- break;
- }
- }
- while (S_OK == (hr = pReader->Read(&nodeType)));
- return hr;
- #undef APPEND_CHILD
- }
- HRESULT
- ParseXml
- (
- IXmlReader * pReader,
- Node ** ppNode
- )
- {
- HRESULT hr;
- XmlNodeType nodeType;
- // ParseNode() ignores the XML declaration node, so there can be only one
- // top level node.
- if (SUCCEEDED(hr = pReader->Read(&nodeType)))
- {
- return ParseNode(pReader, ppNode);
- }
- return hr;
- }
- HRESULT
- CreateStreamOnHandle
- (
- HANDLE handle,
- IStream ** ppStream
- )
- {
- // Note that this function reads the whole file into memory.
- //
- // There is no API on ARM similar to SHCreateStreamOnFileEx which creates
- // an IStream object that reads a file lazily. Rather than writing our own
- // IStream implementation that does this, we just read the whole file here
- // given that XML files don't get quite large and it should be okay to keep
- // everything in memory.
- DWORD fileSize, fileSizeHigh, bytesRead;
- HGLOBAL buffer;
- fileSize = GetFileSize(handle, &fileSizeHigh);
- if (fileSize == INVALID_FILE_SIZE || fileSizeHigh != 0)
- {
- return E_FAIL;
- }
- buffer = GlobalAlloc(GPTR, fileSize + 1);
- if (buffer == nullptr)
- {
- return E_FAIL;
- }
- if (!::ReadFile(handle, buffer, fileSize, &bytesRead, nullptr)
- || FAILED(CreateStreamOnHGlobal(buffer, /* fDeleteOnRelease */ true, ppStream)))
- {
- GlobalFree(buffer);
- return E_FAIL;
- }
- return S_OK;
- }
- Node *
- ReadFile
- (
- const char * fileName
- )
- {
- IStream * pStream;
- IXmlReader * pReader;
- HANDLE fileHandle = CreateFile(fileName, FILE_GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
- if (fileHandle == INVALID_HANDLE_VALUE)
- {
- Fatal("Cannot open XML file %s", fileName);
- }
- if (FAILED(CreateStreamOnHandle(fileHandle, &pStream)))
- {
- Fatal("Cannot create stream from file");
- }
- if (FAILED(CreateXmlReader(__uuidof(IXmlReader), (void**) &pReader, nullptr)))
- {
- Fatal("Cannot create XML reader");
- }
- if (FAILED(pReader->SetProperty(XmlReaderProperty_DtdProcessing, DtdProcessing_Prohibit)))
- {
- Fatal("Cannot prohibit DTD processing");
- }
- if (FAILED(pReader->SetInput(pStream)))
- {
- Fatal("Cannot set XML reader input");
- }
- Node * topNode;
- if (FAILED(ParseXml(pReader, &topNode)))
- {
- unsigned int line, linePos;
- pReader->GetLineNumber(&line);
- pReader->GetLinePosition(&linePos);
- fprintf(
- stderr,
- "Error on line %d, position %d in \"%s\".\n",
- line,
- linePos,
- fileName);
- Fatal("Error parsing XML");
- }
- SAFERELEASE(pReader);
- SAFERELEASE(pStream);
- CloseHandle(fileHandle);
- return topNode;
- }
- } // namespace Xml
|