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" 9 CXML_Parser::~CXML_Parser() 10 { 11 if (m_bOwnedStream) { 12 m_pDataAcc->Release(); 13 } 14 } 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 } 20 FX_BOOL CXML_Parser::Init(IFX_FileRead *pFileRead) 21 { 22 m_pDataAcc = new CXML_DataStmAcc(pFileRead); 23 return Init(TRUE); 24 } 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 } 33 FX_BOOL CXML_Parser::Init(FX_BOOL bOwndedStream) 34 { 35 m_bOwnedStream = bOwndedStream; 36 m_nOffset = 0; 37 return ReadNextBlock(); 38 } 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 } 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 }; 85 FX_BOOL g_FXCRT_XML_IsWhiteSpace(FX_BYTE ch) 86 { 87 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_SpaceChar) != 0; 88 } 89 FX_BOOL g_FXCRT_XML_IsLetter(FX_BYTE ch) 90 { 91 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Letter) != 0; 92 } 93 FX_BOOL g_FXCRT_XML_IsDigital(FX_BYTE ch) 94 { 95 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_Digital) != 0; 96 } 97 FX_BOOL g_FXCRT_XML_IsNameIntro(FX_BYTE ch) 98 { 99 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameIntro) != 0; 100 } 101 FX_BOOL g_FXCRT_XML_IsNameChar(FX_BYTE ch) 102 { 103 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_NameChar) != 0; 104 } 105 FX_BOOL g_FXCRT_XML_IsHexChar(FX_BYTE ch) 106 { 107 return (g_FXCRT_XML_ByteTypes[ch] & FXCRTM_XML_CHARTYPE_HexChar) != 0; 108 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 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 } 558 CXML_Element::CXML_Element() 559 : m_QSpaceName() 560 , m_TagName() 561 , m_AttrMap() 562 { 563 } 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 } 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 } 580 CXML_Element::~CXML_Element() 581 { 582 Empty(); 583 } 584 void CXML_Element::Empty() 585 { 586 RemoveChildren(); 587 } 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 } 603 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 } 613 CFX_ByteString CXML_Element::GetNamespace(FX_BOOL bQualified) const 614 { 615 if (bQualified) { 616 return m_QSpaceName; 617 } 618 return GetNamespaceURI(m_QSpaceName); 619 } 620 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 } 637 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 } 647 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 } 653 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 } 659 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 } 668 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 } 679 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 } 688 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 } 694 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 } 703 FX_DWORD CXML_Element::CountChildren() const 704 { 705 return m_Children.GetSize() / 2; 706 } 707 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 } 715 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 } 728 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 } 737 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 } 752 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 } 772 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 } 782 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 } 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 } 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 } 828 int CXML_AttrMap::GetSize() const 829 { 830 return m_pMap == NULL ? 0 : m_pMap->GetSize(); 831 } 832 CXML_AttrItem& CXML_AttrMap::GetAt(int index) const 833 { 834 ASSERT(m_pMap != NULL); 835 return (*m_pMap)[index]; 836 } 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