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