1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/fxcrt/fx_xml.h"
8 #include "xml_int.h"
~CXML_Parser()9 CXML_Parser::~CXML_Parser()
10 {
11 if (m_bOwnedStream) {
12 m_pDataAcc->Release();
13 }
14 }
Init(FX_LPBYTE pBuffer,size_t size)15 FX_BOOL CXML_Parser::Init(FX_LPBYTE pBuffer, size_t size)
16 {
17 m_pDataAcc = new CXML_DataBufAcc(pBuffer, size);
18 return Init(TRUE);
19 }
Init(IFX_FileRead * pFileRead)20 FX_BOOL CXML_Parser::Init(IFX_FileRead *pFileRead)
21 {
22 m_pDataAcc = new CXML_DataStmAcc(pFileRead);
23 return Init(TRUE);
24 }
Init(IFX_BufferRead * pBuffer)25 FX_BOOL CXML_Parser::Init(IFX_BufferRead *pBuffer)
26 {
27 if (!pBuffer) {
28 return FALSE;
29 }
30 m_pDataAcc = pBuffer;
31 return Init(FALSE);
32 }
Init(FX_BOOL bOwndedStream)33 FX_BOOL CXML_Parser::Init(FX_BOOL bOwndedStream)
34 {
35 m_bOwnedStream = bOwndedStream;
36 m_nOffset = 0;
37 return ReadNextBlock();
38 }
ReadNextBlock()39 FX_BOOL CXML_Parser::ReadNextBlock()
40 {
41 if (!m_pDataAcc->ReadNextBlock()) {
42 return FALSE;
43 }
44 m_pBuffer = m_pDataAcc->GetBlockBuffer();
45 m_dwBufferSize = m_pDataAcc->GetBlockSize();
46 m_nBufferOffset = m_pDataAcc->GetBlockOffset();
47 m_dwIndex = 0;
48 return m_dwBufferSize > 0;
49 }
IsEOF()50 FX_BOOL CXML_Parser::IsEOF()
51 {
52 if (!m_pDataAcc->IsEOF()) {
53 return FALSE;
54 }
55 return m_dwIndex >= m_dwBufferSize;
56 }
57 #define FXCRTM_XML_CHARTYPE_Normal 0x00
58 #define FXCRTM_XML_CHARTYPE_SpaceChar 0x01
59 #define FXCRTM_XML_CHARTYPE_Letter 0x02
60 #define FXCRTM_XML_CHARTYPE_Digital 0x04
61 #define FXCRTM_XML_CHARTYPE_NameIntro 0x08
62 #define FXCRTM_XML_CHARTYPE_NameChar 0x10
63 #define FXCRTM_XML_CHARTYPE_HexDigital 0x20
64 #define FXCRTM_XML_CHARTYPE_HexLowerLetter 0x40
65 #define FXCRTM_XML_CHARTYPE_HexUpperLetter 0x60
66 #define FXCRTM_XML_CHARTYPE_HexChar 0x60
67 FX_BYTE g_FXCRT_XML_ByteTypes[256] = {
68 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
69 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
70 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00,
71 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
72 0x00, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x7A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
73 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x18,
74 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
75 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00,
76 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
77 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
78 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
79 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
80 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
81 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
82 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A,
83 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x1A, 0x01, 0x01,
84 };
g_FXCRT_XML_IsWhiteSpace(FX_BYTE ch)85 FX_BOOL g_FXCRT_XML_IsWhiteSpace(FX_BYTE ch)
86 {
87 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_SpaceChar) != 0;
88 }
g_FXCRT_XML_IsLetter(FX_BYTE ch)89 FX_BOOL g_FXCRT_XML_IsLetter(FX_BYTE ch)
90 {
91 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Letter) != 0;
92 }
g_FXCRT_XML_IsDigital(FX_BYTE ch)93 FX_BOOL g_FXCRT_XML_IsDigital(FX_BYTE ch)
94 {
95 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Digital) != 0;
96 }
g_FXCRT_XML_IsNameIntro(FX_BYTE ch)97 FX_BOOL g_FXCRT_XML_IsNameIntro(FX_BYTE ch)
98 {
99 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameIntro) != 0;
100 }
g_FXCRT_XML_IsNameChar(FX_BYTE ch)101 FX_BOOL g_FXCRT_XML_IsNameChar(FX_BYTE ch)
102 {
103 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameChar) != 0;
104 }
g_FXCRT_XML_IsHexChar(FX_BYTE ch)105 FX_BOOL g_FXCRT_XML_IsHexChar(FX_BYTE ch)
106 {
107 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar) != 0;
108 }
SkipWhiteSpaces()109 void CXML_Parser::SkipWhiteSpaces()
110 {
111 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
112 if (IsEOF()) {
113 return;
114 }
115 do {
116 while (m_dwIndex < m_dwBufferSize && g_FXCRT_XML_IsWhiteSpace(m_pBuffer[m_dwIndex])) {
117 m_dwIndex ++;
118 }
119 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
120 if (m_dwIndex < m_dwBufferSize || IsEOF()) {
121 break;
122 }
123 } while (ReadNextBlock());
124 }
GetName(CFX_ByteString & space,CFX_ByteString & name)125 void CXML_Parser::GetName(CFX_ByteString &space, CFX_ByteString &name)
126 {
127 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
128 if (IsEOF()) {
129 return;
130 }
131 CFX_ByteTextBuf buf;
132 FX_BYTE ch;
133 do {
134 while (m_dwIndex < m_dwBufferSize) {
135 ch = m_pBuffer[m_dwIndex];
136 if (ch == ':') {
137 space = buf.GetByteString();
138 buf.Clear();
139 } else if (g_FXCRT_XML_IsNameChar(ch)) {
140 buf.AppendChar(ch);
141 } else {
142 break;
143 }
144 m_dwIndex ++;
145 }
146 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
147 if (m_dwIndex < m_dwBufferSize || IsEOF()) {
148 break;
149 }
150 } while (ReadNextBlock());
151 name = buf.GetByteString();
152 }
SkipLiterals(FX_BSTR str)153 void CXML_Parser::SkipLiterals(FX_BSTR str)
154 {
155 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
156 if (IsEOF()) {
157 return;
158 }
159 FX_INT32 i = 0, iLen = str.GetLength();
160 do {
161 while (m_dwIndex < m_dwBufferSize) {
162 if (str.GetAt(i) != m_pBuffer[m_dwIndex ++]) {
163 i = 0;
164 } else {
165 i ++;
166 if (i == iLen) {
167 break;
168 }
169 }
170 }
171 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
172 if (i == iLen) {
173 return;
174 }
175 if (m_dwIndex < m_dwBufferSize || IsEOF()) {
176 break;
177 }
178 } while (ReadNextBlock());
179 while (!m_pDataAcc->IsEOF()) {
180 ReadNextBlock();
181 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwBufferSize;
182 }
183 m_dwIndex = m_dwBufferSize;
184 }
GetCharRef()185 FX_DWORD CXML_Parser::GetCharRef()
186 {
187 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
188 if (IsEOF()) {
189 return 0;
190 }
191 FX_BYTE ch;
192 FX_INT32 iState = 0;
193 CFX_ByteTextBuf buf;
194 FX_DWORD code = 0;
195 do {
196 while (m_dwIndex < m_dwBufferSize) {
197 ch = m_pBuffer[m_dwIndex];
198 switch (iState) {
199 case 0:
200 if (ch == '#') {
201 m_dwIndex ++;
202 iState = 2;
203 break;
204 }
205 iState = 1;
206 case 1:
207 m_dwIndex ++;
208 if (ch == ';') {
209 CFX_ByteStringC ref = buf.GetByteString();
210 if (ref == FX_BSTRC("gt")) {
211 code = '>';
212 } else if (ref == FX_BSTRC("lt")) {
213 code = '<';
214 } else if (ref == FX_BSTRC("amp")) {
215 code = '&';
216 } else if (ref == FX_BSTRC("apos")) {
217 code = '\'';
218 } else if (ref == FX_BSTRC("quot")) {
219 code = '"';
220 }
221 iState = 10;
222 break;
223 }
224 buf.AppendByte(ch);
225 break;
226 case 2:
227 if (ch == 'x') {
228 m_dwIndex ++;
229 iState = 4;
230 break;
231 }
232 iState = 3;
233 case 3:
234 m_dwIndex ++;
235 if (ch == ';') {
236 iState = 10;
237 break;
238 }
239 if (g_FXCRT_XML_IsDigital(ch)) {
240 code = code * 10 + ch - '0';
241 }
242 break;
243 case 4:
244 m_dwIndex ++;
245 if (ch == ';') {
246 iState = 10;
247 break;
248 }
249 FX_BYTE nHex = g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar;
250 if (nHex) {
251 if (nHex == FXCRTM_XML_CHARTYPE_HexDigital) {
252 code = (code << 4) + ch - '0';
253 } else if (nHex == FXCRTM_XML_CHARTYPE_HexLowerLetter) {
254 code = (code << 4) + ch - 87;
255 } else {
256 code = (code << 4) + ch - 55;
257 }
258 }
259 break;
260 }
261 if (iState == 10) {
262 break;
263 }
264 }
265 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
266 if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
267 break;
268 }
269 } while (ReadNextBlock());
270 return code;
271 }
GetAttrValue(CFX_WideString & value)272 void CXML_Parser::GetAttrValue(CFX_WideString &value)
273 {
274 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
275 if (IsEOF()) {
276 return;
277 }
278 CFX_UTF8Decoder decoder;
279 FX_BYTE mark = 0, ch = 0;
280 do {
281 while (m_dwIndex < m_dwBufferSize) {
282 ch = m_pBuffer[m_dwIndex];
283 if (mark == 0) {
284 if (ch != '\'' && ch != '"') {
285 return;
286 }
287 mark = ch;
288 m_dwIndex ++;
289 ch = 0;
290 continue;
291 }
292 m_dwIndex ++;
293 if (ch == mark) {
294 break;
295 }
296 if (ch == '&') {
297 decoder.AppendChar(GetCharRef());
298 if (IsEOF()) {
299 value = decoder.GetResult();
300 return;
301 }
302 } else {
303 decoder.Input(ch);
304 }
305 }
306 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
307 if (ch == mark || m_dwIndex < m_dwBufferSize || IsEOF()) {
308 break;
309 }
310 } while (ReadNextBlock());
311 value = decoder.GetResult();
312 }
GetTagName(CFX_ByteString & space,CFX_ByteString & name,FX_BOOL & bEndTag,FX_BOOL bStartTag)313 void CXML_Parser::GetTagName(CFX_ByteString &space, CFX_ByteString &name, FX_BOOL &bEndTag, FX_BOOL bStartTag)
314 {
315 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
316 if (IsEOF()) {
317 return;
318 }
319 bEndTag = FALSE;
320 FX_BYTE ch;
321 FX_INT32 iState = bStartTag ? 1 : 0;
322 do {
323 while (m_dwIndex < m_dwBufferSize) {
324 ch = m_pBuffer[m_dwIndex];
325 switch (iState) {
326 case 0:
327 m_dwIndex ++;
328 if (ch != '<') {
329 break;
330 }
331 iState = 1;
332 break;
333 case 1:
334 if (ch == '?') {
335 m_dwIndex ++;
336 SkipLiterals(FX_BSTRC("?>"));
337 iState = 0;
338 break;
339 } else if (ch == '!') {
340 m_dwIndex ++;
341 SkipLiterals(FX_BSTRC("-->"));
342 iState = 0;
343 break;
344 }
345 if (ch == '/') {
346 m_dwIndex ++;
347 GetName(space, name);
348 bEndTag = TRUE;
349 } else {
350 GetName(space, name);
351 bEndTag = FALSE;
352 }
353 return;
354 }
355 }
356 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
357 if (m_dwIndex < m_dwBufferSize || IsEOF()) {
358 break;
359 }
360 } while (ReadNextBlock());
361 }
ParseElement(CXML_Element * pParent,FX_BOOL bStartTag)362 CXML_Element* CXML_Parser::ParseElement(CXML_Element* pParent, FX_BOOL bStartTag)
363 {
364 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
365 if (IsEOF()) {
366 return NULL;
367 }
368 CFX_ByteString tag_name, tag_space;
369 FX_BOOL bEndTag;
370 GetTagName(tag_space, tag_name, bEndTag, bStartTag);
371 if (tag_name.IsEmpty() || bEndTag) {
372 return NULL;
373 }
374 CXML_Element* pElement = new CXML_Element;
375 pElement->m_pParent = pParent;
376 pElement->SetTag(tag_space, tag_name);
377 do {
378 CFX_ByteString attr_space, attr_name;
379 while (m_dwIndex < m_dwBufferSize) {
380 SkipWhiteSpaces();
381 if (IsEOF()) {
382 break;
383 }
384 if (!g_FXCRT_XML_IsNameIntro(m_pBuffer[m_dwIndex])) {
385 break;
386 }
387 GetName(attr_space, attr_name);
388 SkipWhiteSpaces();
389 if (IsEOF()) {
390 break;
391 }
392 if (m_pBuffer[m_dwIndex] != '=') {
393 break;
394 }
395 m_dwIndex ++;
396 SkipWhiteSpaces();
397 if (IsEOF()) {
398 break;
399 }
400 CFX_WideString attr_value;
401 GetAttrValue(attr_value);
402 pElement->m_AttrMap.SetAt(attr_space, attr_name, attr_value);
403 }
404 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
405 if (m_dwIndex < m_dwBufferSize || IsEOF()) {
406 break;
407 }
408 } while (ReadNextBlock());
409 SkipWhiteSpaces();
410 if (IsEOF()) {
411 return pElement;
412 }
413 FX_BYTE ch = m_pBuffer[m_dwIndex ++];
414 if (ch == '/') {
415 m_dwIndex ++;
416 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
417 return pElement;
418 }
419 if (ch != '>') {
420 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
421 delete pElement;
422 return NULL;
423 }
424 SkipWhiteSpaces();
425 if (IsEOF()) {
426 return pElement;
427 }
428 CFX_UTF8Decoder decoder;
429 CFX_WideTextBuf content;
430 FX_BOOL bCDATA = FALSE;
431 FX_INT32 iState = 0;
432 do {
433 while (m_dwIndex < m_dwBufferSize) {
434 ch = m_pBuffer[m_dwIndex ++];
435 switch (iState) {
436 case 0:
437 if (ch == '<') {
438 iState = 1;
439 } else if (ch == '&') {
440 decoder.ClearStatus();
441 decoder.AppendChar(GetCharRef());
442 } else {
443 decoder.Input(ch);
444 }
445 break;
446 case 1:
447 if (ch == '!') {
448 iState = 2;
449 } else if (ch == '?') {
450 SkipLiterals(FX_BSTRC("?>"));
451 SkipWhiteSpaces();
452 iState = 0;
453 } else if (ch == '/') {
454 CFX_ByteString space, name;
455 GetName(space, name);
456 SkipWhiteSpaces();
457 m_dwIndex ++;
458 iState = 10;
459 } else {
460 content << decoder.GetResult();
461 CFX_WideString dataStr = content.GetWideString();
462 if (!bCDATA && !m_bSaveSpaceChars) {
463 dataStr.TrimRight(L" \t\r\n");
464 }
465 InsertContentSegment(bCDATA, dataStr, pElement);
466 content.Clear();
467 decoder.Clear();
468 bCDATA = FALSE;
469 iState = 0;
470 m_dwIndex --;
471 CXML_Element* pSubElement = ParseElement(pElement, TRUE);
472 if (pSubElement == NULL) {
473 break;
474 }
475 pSubElement->m_pParent = pElement;
476 pElement->m_Children.Add((FX_LPVOID)CXML_Element::Element);
477 pElement->m_Children.Add(pSubElement);
478 SkipWhiteSpaces();
479 }
480 break;
481 case 2:
482 if (ch == '[') {
483 SkipLiterals(FX_BSTRC("]]>"));
484 } else if (ch == '-') {
485 m_dwIndex ++;
486 SkipLiterals(FX_BSTRC("-->"));
487 } else {
488 SkipLiterals(FX_BSTRC(">"));
489 }
490 decoder.Clear();
491 SkipWhiteSpaces();
492 iState = 0;
493 break;
494 }
495 if (iState == 10) {
496 break;
497 }
498 }
499 m_nOffset = m_nBufferOffset + (FX_FILESIZE)m_dwIndex;
500 if (iState == 10 || m_dwIndex < m_dwBufferSize || IsEOF()) {
501 break;
502 }
503 } while (ReadNextBlock());
504 content << decoder.GetResult();
505 CFX_WideString dataStr = content.GetWideString();
506 if (!m_bSaveSpaceChars) {
507 dataStr.TrimRight(L" \t\r\n");
508 }
509 InsertContentSegment(bCDATA, dataStr, pElement);
510 content.Clear();
511 decoder.Clear();
512 bCDATA = FALSE;
513 return pElement;
514 }
InsertContentSegment(FX_BOOL bCDATA,FX_WSTR content,CXML_Element * pElement)515 void CXML_Parser::InsertContentSegment(FX_BOOL bCDATA, FX_WSTR content, CXML_Element* pElement)
516 {
517 if (content.IsEmpty()) {
518 return;
519 }
520 CXML_Content* pContent = new CXML_Content;
521 pContent->Set(bCDATA, content);
522 pElement->m_Children.Add((FX_LPVOID)CXML_Element::Content);
523 pElement->m_Children.Add(pContent);
524 }
XML_ContinueParse(CXML_Parser & parser,FX_BOOL bSaveSpaceChars,FX_FILESIZE * pParsedSize)525 static CXML_Element* XML_ContinueParse(CXML_Parser &parser, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
526 {
527 parser.m_bSaveSpaceChars = bSaveSpaceChars;
528 CXML_Element* pElement = parser.ParseElement(NULL, FALSE);
529 if (pParsedSize) {
530 *pParsedSize = parser.m_nOffset;
531 }
532 return pElement;
533 }
Parse(const void * pBuffer,size_t size,FX_BOOL bSaveSpaceChars,FX_FILESIZE * pParsedSize)534 CXML_Element* CXML_Element::Parse(const void* pBuffer, size_t size, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
535 {
536 CXML_Parser parser;
537 if (!parser.Init((FX_LPBYTE)pBuffer, size)) {
538 return NULL;
539 }
540 return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
541 }
Parse(IFX_FileRead * pFile,FX_BOOL bSaveSpaceChars,FX_FILESIZE * pParsedSize)542 CXML_Element* CXML_Element::Parse(IFX_FileRead *pFile, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
543 {
544 CXML_Parser parser;
545 if (!parser.Init(pFile)) {
546 return NULL;
547 }
548 return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
549 }
Parse(IFX_BufferRead * pBuffer,FX_BOOL bSaveSpaceChars,FX_FILESIZE * pParsedSize)550 CXML_Element* CXML_Element::Parse(IFX_BufferRead *pBuffer, FX_BOOL bSaveSpaceChars, FX_FILESIZE* pParsedSize)
551 {
552 CXML_Parser parser;
553 if (!parser.Init(pBuffer)) {
554 return NULL;
555 }
556 return XML_ContinueParse(parser, bSaveSpaceChars, pParsedSize);
557 }
CXML_Element()558 CXML_Element::CXML_Element()
559 : m_QSpaceName()
560 , m_TagName()
561 , m_AttrMap()
562 {
563 }
CXML_Element(FX_BSTR qSpace,FX_BSTR tagName)564 CXML_Element::CXML_Element(FX_BSTR qSpace, FX_BSTR tagName)
565 : m_QSpaceName()
566 , m_TagName()
567 , m_AttrMap()
568 {
569 m_QSpaceName = qSpace;
570 m_TagName = tagName;
571 }
CXML_Element(FX_BSTR qTagName)572 CXML_Element::CXML_Element(FX_BSTR qTagName)
573 : m_pParent(NULL)
574 , m_QSpaceName()
575 , m_TagName()
576 , m_AttrMap()
577 {
578 SetTag(qTagName);
579 }
~CXML_Element()580 CXML_Element::~CXML_Element()
581 {
582 Empty();
583 }
Empty()584 void CXML_Element::Empty()
585 {
586 RemoveChildren();
587 }
RemoveChildren()588 void CXML_Element::RemoveChildren()
589 {
590 for (int i = 0; i < m_Children.GetSize(); i += 2) {
591 ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
592 if (type == Content) {
593 CXML_Content* content = (CXML_Content*)m_Children.GetAt(i + 1);
594 delete content;
595 } else if (type == Element) {
596 CXML_Element* child = (CXML_Element*)m_Children.GetAt(i + 1);
597 child->RemoveChildren();
598 delete child;
599 }
600 }
601 m_Children.RemoveAll();
602 }
GetTagName(FX_BOOL bQualified) const603 CFX_ByteString CXML_Element::GetTagName(FX_BOOL bQualified) const
604 {
605 if (!bQualified || m_QSpaceName.IsEmpty()) {
606 return m_TagName;
607 }
608 CFX_ByteString bsTag = m_QSpaceName;
609 bsTag += ":";
610 bsTag += m_TagName;
611 return bsTag;
612 }
GetNamespace(FX_BOOL bQualified) const613 CFX_ByteString CXML_Element::GetNamespace(FX_BOOL bQualified) const
614 {
615 if (bQualified) {
616 return m_QSpaceName;
617 }
618 return GetNamespaceURI(m_QSpaceName);
619 }
GetNamespaceURI(FX_BSTR qName) const620 CFX_ByteString CXML_Element::GetNamespaceURI(FX_BSTR qName) const
621 {
622 const CFX_WideString* pwsSpace;
623 const CXML_Element *pElement = this;
624 do {
625 if (qName.IsEmpty()) {
626 pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC(""), FX_BSTRC("xmlns"));
627 } else {
628 pwsSpace = pElement->m_AttrMap.Lookup(FX_BSTRC("xmlns"), qName);
629 }
630 if (pwsSpace) {
631 break;
632 }
633 pElement = pElement->GetParent();
634 } while(pElement);
635 return pwsSpace ? FX_UTF8Encode(*pwsSpace) : CFX_ByteString();
636 }
GetAttrByIndex(int index,CFX_ByteString & space,CFX_ByteString & name,CFX_WideString & value) const637 void CXML_Element::GetAttrByIndex(int index, CFX_ByteString& space, CFX_ByteString& name, CFX_WideString& value) const
638 {
639 if (index < 0 || index >= m_AttrMap.GetSize()) {
640 return;
641 }
642 CXML_AttrItem& item = m_AttrMap.GetAt(index);
643 space = item.m_QSpaceName;
644 name = item.m_AttrName;
645 value = item.m_Value;
646 }
HasAttr(FX_BSTR name) const647 FX_BOOL CXML_Element::HasAttr(FX_BSTR name) const
648 {
649 CFX_ByteStringC bsSpace, bsName;
650 FX_XML_SplitQualifiedName(name, bsSpace, bsName);
651 return m_AttrMap.Lookup(bsSpace, bsName) != NULL;
652 }
GetAttrValue(FX_BSTR name,CFX_WideString & attribute) const653 FX_BOOL CXML_Element::GetAttrValue(FX_BSTR name, CFX_WideString& attribute) const
654 {
655 CFX_ByteStringC bsSpace, bsName;
656 FX_XML_SplitQualifiedName(name, bsSpace, bsName);
657 return GetAttrValue(bsSpace, bsName, attribute);
658 }
GetAttrValue(FX_BSTR space,FX_BSTR name,CFX_WideString & attribute) const659 FX_BOOL CXML_Element::GetAttrValue(FX_BSTR space, FX_BSTR name, CFX_WideString& attribute) const
660 {
661 const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
662 if (pValue) {
663 attribute = *pValue;
664 return TRUE;
665 }
666 return FALSE;
667 }
GetAttrInteger(FX_BSTR name,int & attribute) const668 FX_BOOL CXML_Element::GetAttrInteger(FX_BSTR name, int& attribute) const
669 {
670 CFX_ByteStringC bsSpace, bsName;
671 FX_XML_SplitQualifiedName(name, bsSpace, bsName);
672 const CFX_WideString* pwsValue = m_AttrMap.Lookup(bsSpace, bsName);
673 if (pwsValue) {
674 attribute = pwsValue->GetInteger();
675 return TRUE;
676 }
677 return FALSE;
678 }
GetAttrInteger(FX_BSTR space,FX_BSTR name,int & attribute) const679 FX_BOOL CXML_Element::GetAttrInteger(FX_BSTR space, FX_BSTR name, int& attribute) const
680 {
681 const CFX_WideString* pwsValue = m_AttrMap.Lookup(space, name);
682 if (pwsValue) {
683 attribute = pwsValue->GetInteger();
684 return TRUE;
685 }
686 return FALSE;
687 }
GetAttrFloat(FX_BSTR name,FX_FLOAT & attribute) const688 FX_BOOL CXML_Element::GetAttrFloat(FX_BSTR name, FX_FLOAT& attribute) const
689 {
690 CFX_ByteStringC bsSpace, bsName;
691 FX_XML_SplitQualifiedName(name, bsSpace, bsName);
692 return GetAttrFloat(bsSpace, bsName, attribute);
693 }
GetAttrFloat(FX_BSTR space,FX_BSTR name,FX_FLOAT & attribute) const694 FX_BOOL CXML_Element::GetAttrFloat(FX_BSTR space, FX_BSTR name, FX_FLOAT& attribute) const
695 {
696 const CFX_WideString* pValue = m_AttrMap.Lookup(space, name);
697 if (pValue) {
698 attribute = pValue->GetFloat();
699 return TRUE;
700 }
701 return FALSE;
702 }
CountChildren() const703 FX_DWORD CXML_Element::CountChildren() const
704 {
705 return m_Children.GetSize() / 2;
706 }
GetChildType(FX_DWORD index) const707 CXML_Element::ChildType CXML_Element::GetChildType(FX_DWORD index) const
708 {
709 index <<= 1;
710 if (index >= (FX_DWORD)m_Children.GetSize()) {
711 return Invalid;
712 }
713 return (ChildType)(FX_UINTPTR)m_Children.GetAt(index);
714 }
GetContent(FX_DWORD index) const715 CFX_WideString CXML_Element::GetContent(FX_DWORD index) const
716 {
717 index <<= 1;
718 if (index >= (FX_DWORD)m_Children.GetSize() ||
719 (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Content) {
720 return CFX_WideString();
721 }
722 CXML_Content* pContent = (CXML_Content*)m_Children.GetAt(index + 1);
723 if (pContent) {
724 return pContent->m_Content;
725 }
726 return CFX_WideString();
727 }
GetElement(FX_DWORD index) const728 CXML_Element* CXML_Element::GetElement(FX_DWORD index) const
729 {
730 index <<= 1;
731 if (index >= (FX_DWORD)m_Children.GetSize() ||
732 (ChildType)(FX_UINTPTR)m_Children.GetAt(index) != Element) {
733 return NULL;
734 }
735 return (CXML_Element*)m_Children.GetAt(index + 1);
736 }
CountElements(FX_BSTR space,FX_BSTR tag) const737 FX_DWORD CXML_Element::CountElements(FX_BSTR space, FX_BSTR tag) const
738 {
739 int count = 0;
740 for (int i = 0; i < m_Children.GetSize(); i += 2) {
741 ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
742 if (type != Element) {
743 continue;
744 }
745 CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
746 if ((space.IsEmpty() || pKid->m_QSpaceName == space) && pKid->m_TagName == tag) {
747 count ++;
748 }
749 }
750 return count;
751 }
GetElement(FX_BSTR space,FX_BSTR tag,int index) const752 CXML_Element* CXML_Element::GetElement(FX_BSTR space, FX_BSTR tag, int index) const
753 {
754 if (index < 0) {
755 return NULL;
756 }
757 for (int i = 0; i < m_Children.GetSize(); i += 2) {
758 ChildType type = (ChildType)(FX_UINTPTR)m_Children.GetAt(i);
759 if (type != Element) {
760 continue;
761 }
762 CXML_Element* pKid = (CXML_Element*)m_Children.GetAt(i + 1);
763 if ((!space.IsEmpty() && pKid->m_QSpaceName != space) || pKid->m_TagName != tag) {
764 continue;
765 }
766 if (index -- == 0) {
767 return pKid;
768 }
769 }
770 return NULL;
771 }
FindElement(CXML_Element * pChild) const772 FX_DWORD CXML_Element::FindElement(CXML_Element *pChild) const
773 {
774 for (int i = 0; i < m_Children.GetSize(); i += 2) {
775 if ((ChildType)(FX_UINTPTR)m_Children.GetAt(i) == Element &&
776 (CXML_Element*)m_Children.GetAt(i + 1) == pChild) {
777 return (FX_DWORD)(i >> 1);
778 }
779 }
780 return (FX_DWORD) - 1;
781 }
Lookup(FX_BSTR space,FX_BSTR name) const782 const CFX_WideString* CXML_AttrMap::Lookup(FX_BSTR space, FX_BSTR name) const
783 {
784 if (m_pMap == NULL) {
785 return NULL;
786 }
787 for (int i = 0; i < m_pMap->GetSize(); i ++) {
788 CXML_AttrItem& item = GetAt(i);
789 if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
790 return &item.m_Value;
791 }
792 }
793 return NULL;
794 }
SetAt(FX_BSTR space,FX_BSTR name,FX_WSTR value)795 void CXML_AttrMap::SetAt(FX_BSTR space, FX_BSTR name, FX_WSTR value)
796 {
797 for (int i = 0; i < GetSize(); i++) {
798 CXML_AttrItem& item = GetAt(i);
799 if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
800 item.m_Value = value;
801 return;
802 }
803 }
804 if (!m_pMap) {
805 m_pMap = new CFX_ObjectArray<CXML_AttrItem>;
806 }
807 CXML_AttrItem* pItem = (CXML_AttrItem*)m_pMap->AddSpace();
808 if (!pItem) {
809 return;
810 }
811 pItem->m_QSpaceName = space;
812 pItem->m_AttrName = name;
813 pItem->m_Value = value;
814 }
RemoveAt(FX_BSTR space,FX_BSTR name)815 void CXML_AttrMap::RemoveAt(FX_BSTR space, FX_BSTR name)
816 {
817 if (m_pMap == NULL) {
818 return;
819 }
820 for (int i = 0; i < m_pMap->GetSize(); i ++) {
821 CXML_AttrItem& item = GetAt(i);
822 if ((space.IsEmpty() || item.m_QSpaceName == space) && item.m_AttrName == name) {
823 m_pMap->RemoveAt(i);
824 return;
825 }
826 }
827 }
GetSize() const828 int CXML_AttrMap::GetSize() const
829 {
830 return m_pMap == NULL ? 0 : m_pMap->GetSize();
831 }
GetAt(int index) const832 CXML_AttrItem& CXML_AttrMap::GetAt(int index) const
833 {
834 ASSERT(m_pMap != NULL);
835 return (*m_pMap)[index];
836 }
RemoveAll()837 void CXML_AttrMap::RemoveAll()
838 {
839 if (!m_pMap) {
840 return;
841 }
842 m_pMap->RemoveAll();
843 delete m_pMap;
844 m_pMap = NULL;
845 }
846