xmlreader.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "rl.h"
  6. #include <objbase.h>
  7. #include <XmlLite.h>
  8. #define CHECKHR(x) {hr = x; if (FAILED(hr)) goto CleanUp;}
  9. #define SAFERELEASE(p) {if (p) {(p)->Release(); p = NULL;}}
  10. namespace Xml
  11. {
  12. Node * Node::TopNode;
  13. //-----------------------------------------------------------------------------
  14. //
  15. // Description:
  16. //
  17. // Constructor for Attribute class.
  18. //
  19. //-----------------------------------------------------------------------------
  20. Attribute::Attribute
  21. (
  22. Char * name,
  23. Char * value
  24. )
  25. : Name(name)
  26. , Value(value)
  27. , Next(NULL)
  28. {}
  29. Char *
  30. Attribute::GetValue
  31. (
  32. const Char * name
  33. )
  34. {
  35. for (Attribute * p = this; p != NULL; p = p->Next)
  36. {
  37. if (strcmp(p->Name, name) == 0)
  38. {
  39. return p->Value;
  40. }
  41. }
  42. return NULL;
  43. }
  44. void
  45. Attribute::Dump()
  46. {
  47. for (Attribute * attr = this;
  48. attr != NULL;
  49. attr = attr->Next)
  50. {
  51. printf("%s=\"%s\"", attr->Name, attr->Value);
  52. if (attr->Next != NULL)
  53. {
  54. printf(" ");
  55. }
  56. }
  57. printf("\n");
  58. }
  59. //-----------------------------------------------------------------------------
  60. //
  61. // Description:
  62. //
  63. // Constructor for Node class.
  64. //
  65. //
  66. //-----------------------------------------------------------------------------
  67. Node::Node
  68. (
  69. Char * name,
  70. Attribute * attributeList
  71. )
  72. : Name(name)
  73. , AttributeList(attributeList)
  74. , Next(NULL)
  75. , ChildList(NULL)
  76. , Data(NULL)
  77. // , LineNumber(Xml::LineNumber)
  78. {}
  79. Node *
  80. Node::GetChild
  81. (
  82. const Char * name
  83. )
  84. {
  85. for (Node * p = this->ChildList; p != NULL; p = p->Next)
  86. {
  87. if (strcmp(p->Name, name) == 0)
  88. {
  89. return p;
  90. }
  91. }
  92. return NULL;
  93. }
  94. Char *
  95. Node::GetAttributeValue
  96. (
  97. const Char * name
  98. )
  99. {
  100. return this->AttributeList->GetValue(name);
  101. }
  102. void
  103. Node::Dump
  104. (
  105. int indent
  106. )
  107. {
  108. for (int i = 0; i < indent; i++)
  109. {
  110. printf(" ");
  111. }
  112. printf("Node %s ", this->Name);
  113. this->AttributeList->Dump();
  114. if (this->Data != NULL)
  115. {
  116. for (int i = 0; i <= indent; i++)
  117. {
  118. printf(" ");
  119. }
  120. printf("Data: %s\n", this->Data);
  121. }
  122. else
  123. {
  124. for (Node * child = this->ChildList;
  125. child != NULL;
  126. child = child->Next)
  127. {
  128. child->Dump(indent + 1);
  129. }
  130. }
  131. }
  132. void
  133. Node::Dump()
  134. {
  135. this->Dump(0);
  136. }
  137. Char *
  138. ConvertWCHAR
  139. (
  140. const WCHAR * pWchar
  141. )
  142. {
  143. int len = ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pWchar, -1,
  144. NULL, 0, NULL, NULL);
  145. Char * newStr = new char[len + 1];
  146. ::WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, pWchar, -1,
  147. newStr, len + 1, NULL, NULL);
  148. return newStr;
  149. }
  150. HRESULT
  151. ParseAttributes
  152. (
  153. IXmlReader * pReader,
  154. Attribute ** ppAttrList
  155. )
  156. {
  157. HRESULT hr;
  158. const WCHAR * tmpString;
  159. Attribute * attrLast = nullptr;
  160. while (S_OK == (hr = pReader->MoveToNextAttribute()))
  161. {
  162. pReader->GetLocalName(&tmpString, nullptr);
  163. Char * attrName = ConvertWCHAR(tmpString);
  164. pReader->GetValue(&tmpString, nullptr);
  165. Char * attrValue = ConvertWCHAR(tmpString);
  166. Attribute * attrItem = new Attribute(attrName, attrValue);
  167. if (attrLast != nullptr)
  168. {
  169. attrLast->Next = attrItem;
  170. }
  171. else
  172. {
  173. *ppAttrList = attrItem;
  174. }
  175. attrLast = attrItem;
  176. }
  177. return hr;
  178. }
  179. HRESULT
  180. ParseNode
  181. (
  182. IXmlReader * pReader,
  183. Node ** ppNode
  184. )
  185. {
  186. HRESULT hr;
  187. XmlNodeType nodeType;
  188. Char * nodeName = nullptr;
  189. Attribute * attrList = nullptr;
  190. Node * childList = nullptr;
  191. Node * childLast = nullptr;
  192. const WCHAR * tmpString;
  193. #define APPEND_CHILD(childNode) \
  194. if (childLast == nullptr) \
  195. { \
  196. childList = childLast = childNode; \
  197. } \
  198. else \
  199. { \
  200. childLast->Next = childNode; \
  201. childLast = childNode; \
  202. }
  203. // This call won't fail we make sure the reader is positioned at a valid
  204. // node before ParseNode() is called.
  205. pReader->GetNodeType(&nodeType);
  206. do
  207. {
  208. switch (nodeType)
  209. {
  210. case XmlNodeType_Element:
  211. {
  212. bool inOpenElement = nodeName != nullptr;
  213. if (inOpenElement)
  214. {
  215. Node * childNode;
  216. hr = ParseNode(pReader, &childNode);
  217. if (hr == S_OK)
  218. {
  219. APPEND_CHILD(childNode);
  220. }
  221. else
  222. {
  223. return hr;
  224. }
  225. }
  226. else
  227. {
  228. pReader->GetLocalName(&tmpString, nullptr);
  229. nodeName = ConvertWCHAR(tmpString);
  230. hr = ParseAttributes(pReader, &attrList);
  231. if (FAILED(hr))
  232. {
  233. *ppNode = nullptr;
  234. return hr;
  235. }
  236. *ppNode = new Node(nodeName, attrList);
  237. if (pReader->IsEmptyElement())
  238. {
  239. return S_OK;
  240. }
  241. }
  242. break;
  243. }
  244. case XmlNodeType_EndElement:
  245. {
  246. Node * node = *ppNode;
  247. // If we have a single child with data called "#text", then pull the data up to this node.
  248. if (childList != nullptr
  249. && childList == childLast
  250. && (childList->Data != nullptr)
  251. && (_stricmp(childList->Name, "#text") == 0))
  252. {
  253. node->Data = childList->Data;
  254. node->ChildList = nullptr;
  255. }
  256. else
  257. {
  258. node->ChildList = childList;
  259. }
  260. return S_OK;
  261. }
  262. case XmlNodeType_Attribute:
  263. // Need to manually move to attributes when at an element node.
  264. break;
  265. case XmlNodeType_CDATA:
  266. case XmlNodeType_Text:
  267. {
  268. pReader->GetValue(&tmpString, nullptr);
  269. Node * node = new Node("#text", nullptr);
  270. node->Data = ConvertWCHAR(tmpString);
  271. APPEND_CHILD(node);
  272. break;
  273. }
  274. case XmlNodeType_Comment:
  275. case XmlNodeType_DocumentType:
  276. case XmlNodeType_None:
  277. case XmlNodeType_ProcessingInstruction:
  278. case XmlNodeType_Whitespace:
  279. case XmlNodeType_XmlDeclaration:
  280. // Ignored.
  281. break;
  282. }
  283. }
  284. while (S_OK == (hr = pReader->Read(&nodeType)));
  285. return hr;
  286. #undef APPEND_CHILD
  287. }
  288. HRESULT
  289. ParseXml
  290. (
  291. IXmlReader * pReader,
  292. Node ** ppNode
  293. )
  294. {
  295. HRESULT hr;
  296. XmlNodeType nodeType;
  297. // ParseNode() ignores the XML declaration node, so there can be only one
  298. // top level node.
  299. if (SUCCEEDED(hr = pReader->Read(&nodeType)))
  300. {
  301. return ParseNode(pReader, ppNode);
  302. }
  303. return hr;
  304. }
  305. HRESULT
  306. CreateStreamOnHandle
  307. (
  308. HANDLE handle,
  309. IStream ** ppStream
  310. )
  311. {
  312. // Note that this function reads the whole file into memory.
  313. //
  314. // There is no API on ARM similar to SHCreateStreamOnFileEx which creates
  315. // an IStream object that reads a file lazily. Rather than writing our own
  316. // IStream implementation that does this, we just read the whole file here
  317. // given that XML files don't get quite large and it should be okay to keep
  318. // everything in memory.
  319. DWORD fileSize, fileSizeHigh, bytesRead;
  320. HGLOBAL buffer;
  321. fileSize = GetFileSize(handle, &fileSizeHigh);
  322. if (fileSize == INVALID_FILE_SIZE || fileSizeHigh != 0)
  323. {
  324. return E_FAIL;
  325. }
  326. buffer = GlobalAlloc(GPTR, fileSize + 1);
  327. if (buffer == nullptr)
  328. {
  329. return E_FAIL;
  330. }
  331. if (!::ReadFile(handle, buffer, fileSize, &bytesRead, nullptr)
  332. || FAILED(CreateStreamOnHGlobal(buffer, /* fDeleteOnRelease */ true, ppStream)))
  333. {
  334. GlobalFree(buffer);
  335. return E_FAIL;
  336. }
  337. return S_OK;
  338. }
  339. Node *
  340. ReadFile
  341. (
  342. const char * fileName
  343. )
  344. {
  345. IStream * pStream;
  346. IXmlReader * pReader;
  347. HANDLE fileHandle = CreateFile(fileName, FILE_GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, 0, nullptr);
  348. if (fileHandle == INVALID_HANDLE_VALUE)
  349. {
  350. Fatal("Cannot open XML file %s", fileName);
  351. }
  352. if (FAILED(CreateStreamOnHandle(fileHandle, &pStream)))
  353. {
  354. Fatal("Cannot create stream from file");
  355. }
  356. if (FAILED(CreateXmlReader(__uuidof(IXmlReader), (void**) &pReader, nullptr)))
  357. {
  358. Fatal("Cannot create XML reader");
  359. }
  360. if (FAILED(pReader->SetProperty(XmlReaderProperty_DtdProcessing, DtdProcessing_Prohibit)))
  361. {
  362. Fatal("Cannot prohibit DTD processing");
  363. }
  364. if (FAILED(pReader->SetInput(pStream)))
  365. {
  366. Fatal("Cannot set XML reader input");
  367. }
  368. Node * topNode;
  369. if (FAILED(ParseXml(pReader, &topNode)))
  370. {
  371. unsigned int line, linePos;
  372. pReader->GetLineNumber(&line);
  373. pReader->GetLinePosition(&linePos);
  374. fprintf(
  375. stderr,
  376. "Error on line %d, position %d in \"%s\".\n",
  377. line,
  378. linePos,
  379. fileName);
  380. Fatal("Error parsing XML");
  381. }
  382. SAFERELEASE(pReader);
  383. SAFERELEASE(pStream);
  384. CloseHandle(fileHandle);
  385. return topNode;
  386. }
  387. } // namespace Xml