1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include "js_xml.h" 17 #include "securec.h" 18 namespace OHOS::xml { DealNapiStrValue(napi_env env,const napi_value napiStr,std::string & result)19 napi_status XmlSerializer::DealNapiStrValue(napi_env env, const napi_value napiStr, std::string &result) 20 { 21 std::string buffer = ""; 22 size_t bufferSize = 0; 23 napi_status status = napi_ok; 24 status = napi_get_value_string_utf8(env, napiStr, nullptr, -1, &bufferSize); 25 buffer.reserve(bufferSize + 1); 26 buffer.resize(bufferSize); 27 if (status != napi_ok) { 28 HILOG_ERROR("can not get buffer size"); 29 return status; 30 } 31 if (bufferSize > 0) { 32 status = napi_get_value_string_utf8(env, napiStr, buffer.data(), bufferSize + 1, &bufferSize); 33 if (status != napi_ok) { 34 HILOG_ERROR("can not get buffer value"); 35 return status; 36 } 37 } 38 if (buffer.data() != nullptr) { 39 result = buffer; 40 } 41 return status; 42 } 43 SplicNsp()44 void XmlSerializer::SplicNsp() 45 { 46 elementStack[depth_ * 3] = elementStack[(depth_ - 1) * 3]; // 3: number of args 47 elementStack[depth_ * 3 + 1] = elementStack[(depth_ - 1) * 3 + 1]; // 3: number of args 48 if (multNsp[depth_ - 1].size() == 0) { 49 return; 50 } 51 if (type == "isAttri" || type == "isStart") { 52 for (int i = 0; i < curNspNum; ++i) { 53 out_.append(" xmlns:"); 54 out_.append(multNsp[depth_ - 1][i * 2]); // 2: number of args 55 out_.append("=\""); 56 out_.append(multNsp[depth_ - 1][i * 2 + 1]); // 2: number of args 57 out_.append("\""); 58 } 59 multNsp[depth_ - 1].clear(); 60 curNspNum = 0; 61 } 62 } 63 NextItem()64 void XmlSerializer::NextItem() 65 { 66 out_.append("\r\n"); 67 for (size_t i = 0; i < depth_; i++) { 68 out_.append(" "); 69 } 70 } 71 Replace(std::string str,const std::string & subStr,const std::string & repStr)72 std::string XmlSerializer::Replace(std::string str, const std::string &subStr, const std::string &repStr) 73 { 74 size_t iPos = 0; 75 size_t subLen = subStr.length(); 76 size_t step = repStr.length(); 77 while ((iPos = str.find(subStr, iPos)) != std::string::npos) { 78 str = str.substr(0, iPos) + repStr + str.substr(iPos + subLen); 79 iPos += step; 80 } 81 return str; 82 } 83 SetDeclaration()84 void XmlSerializer::SetDeclaration() 85 { 86 if (isHasDecl) { 87 xmlSerializerError_ = "illegal position for declaration"; 88 return; 89 } 90 isHasDecl = true; 91 out_ = ""; 92 out_.append("<?xml version=\"1.0\""); 93 out_.append(" encoding=\""); 94 out_.append(encoding_); 95 out_.append("\"?>"); 96 type = "isDecl"; 97 size_t iLenTemp = out_.length(); 98 if (iLength_ > iPos_ + iLenTemp - 1) { 99 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 100 iPos_ += iLenTemp; 101 } else { 102 HILOG_ERROR("SetDeclaration memcpy_s failed"); 103 } 104 } 105 } 106 SetNamespace(std::string prefix,const std::string & nsTemp)107 void XmlSerializer::SetNamespace(std::string prefix, const std::string &nsTemp) 108 { 109 out_ = ""; 110 if (type == "isStart" || type == "isAttri") { 111 SplicNsp(); 112 out_.append(">"); 113 } 114 elementStack[depth_ * 3] = prefix; // 3: number of args 115 elementStack[depth_ * 3 + 1] = nsTemp; // 3: number of args 116 multNsp[depth_][curNspNum * 2] = elementStack[depth_ * 3]; // 3: number of args 2: number of args 117 multNsp[depth_][curNspNum * 2 + 1] = elementStack[depth_ * 3 + 1]; // 3: number of args 2: number of args 118 ++curNspNum; 119 type = "isNsp"; 120 size_t iLenTemp = out_.length(); 121 if (iLength_ > iPos_ + iLenTemp - 1) { 122 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 123 iPos_ += iLenTemp; 124 } else { 125 HILOG_ERROR("SetNamespace memcpy_s failed"); 126 } 127 } 128 } 129 StartElement(const std::string & name)130 void XmlSerializer::StartElement(const std::string &name) 131 { 132 out_ = ""; 133 if (type == "isStart" || type == "isAttri") { 134 SplicNsp(); 135 out_.append(">"); 136 } 137 if (type != "" && type != "isDecl") { 138 NextItem(); 139 } 140 elementStack[depth_ * 3 + 2] = name; // 3: number of args 2: number of args 141 out_.append("<"); 142 if (elementStack[depth_ * 3] != "") { // 3: number of args 143 out_.append(elementStack[depth_ * 3]); // 3: number of args 144 out_.append(":"); 145 } else if (depth_ != 0) { 146 if (elementStack[(depth_ - 1) * 3] != "") { // 3: number of args 147 elementStack[depth_ * 3] = elementStack[(depth_ - 1) * 3]; // 3: number of args 148 out_.append(elementStack[depth_ * 3]); // 3: number of args 149 out_.append(":"); 150 } 151 } 152 out_.append(elementStack[depth_ * 3 + 2]); // 3: number of args 2: number of args 153 type = "isStart"; 154 ++depth_; 155 elementStack.push_back(""); 156 elementStack.push_back(""); 157 elementStack.push_back(""); 158 size_t iLenTemp = out_.length(); 159 if (iLength_ > iPos_ + iLenTemp - 1) { 160 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 161 iPos_ += iLenTemp; 162 } else { 163 HILOG_ERROR("StartElement memcpy_s failed"); 164 } 165 } 166 } 167 SetAttributes(const std::string & name,const std::string & value)168 void XmlSerializer::SetAttributes(const std::string &name, const std::string &value) 169 { 170 out_ = ""; 171 if (type != "isStart" && type != "isAttri") { 172 xmlSerializerError_ = "illegal position for attribute"; 173 } 174 out_.append(" "); 175 out_.append(name); 176 out_.append("=\""); 177 WriteEscaped(value); 178 out_.append("\""); 179 type = "isAttri"; 180 size_t iLenTemp = out_.length(); 181 if (iLength_ > iPos_ + iLenTemp - 1) { 182 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 183 iPos_ += iLenTemp; 184 } else { 185 HILOG_ERROR("SetAttributes memcpy_s failed"); 186 } 187 } 188 } 189 EndElement()190 void XmlSerializer::EndElement() 191 { 192 out_ = ""; 193 size_t iLenTemp = 0; 194 if (type == "isStart" || type == "isAttri") { 195 SplicNsp(); 196 out_.append("/>"); 197 type = "isEndTag"; 198 --depth_; 199 iLenTemp = out_.length(); 200 if (iLength_ > iPos_ + iLenTemp - 1) { 201 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 202 iPos_ += iLenTemp; 203 } else { 204 HILOG_ERROR("StartElement memcpy_s failed"); 205 } 206 } 207 return; 208 } 209 --depth_; 210 if (type != "isText") { 211 NextItem(); 212 } 213 out_.append("</"); 214 if (elementStack[depth_ * 3] != "") { // 3: number of args 215 out_.append(elementStack[depth_ * 3]); // 3: number of args 216 out_.append(":"); 217 } 218 out_.append(elementStack[depth_ * 3 + 2]); // 3: number of args 2: number of args 219 elementStack[depth_ * 3] = ""; // 3: number of args 220 elementStack[depth_ * 3 + 1] = ""; // 3: number of args 221 type = "isEndTag"; 222 out_.append(">"); 223 iLenTemp = out_.length(); 224 if (iLength_ > iPos_ + iLenTemp - 1) { 225 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 226 iPos_ += iLenTemp; 227 } else { 228 HILOG_ERROR("EndElement memcpy_s failed"); 229 } 230 } 231 } 232 AddEmptyElement(std::string name)233 void XmlSerializer::AddEmptyElement(std::string name) 234 { 235 out_ = ""; 236 if (type == "isStart" || type == "isAttri") { 237 SplicNsp(); 238 out_.append(">"); 239 } 240 if (type != "") { 241 NextItem(); 242 } 243 out_.append("<"); 244 out_.append(name); 245 out_.append("/>"); 246 type = "isAddEmpElem"; 247 size_t iLenTemp = out_.length(); 248 if (iLength_ > iPos_ + iLenTemp - 1) { 249 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 250 iPos_ += iLenTemp; 251 } else { 252 HILOG_ERROR("AddEmptyElement memcpy_s failed"); 253 } 254 } 255 } 256 SetText(const std::string & text)257 void XmlSerializer::SetText(const std::string &text) 258 { 259 out_ = ""; 260 if (type == "isStart" || type == "isAttri") { 261 SplicNsp(); 262 out_.append(">"); 263 } 264 WriteEscaped(text); 265 type = "isText"; 266 size_t iLenTemp = out_.length(); 267 if (iLength_ > iPos_ + iLenTemp - 1) { 268 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 269 iPos_ += iLenTemp; 270 } else { 271 HILOG_ERROR("SetText memcpy_s failed"); 272 } 273 } 274 } 275 SetComment(const std::string & comment)276 void XmlSerializer::SetComment(const std::string &comment) 277 { 278 out_ = ""; 279 if (type == "isStart" || type == "isAttri") { 280 SplicNsp(); 281 out_.append(">"); 282 } 283 if (type != "") { 284 NextItem(); 285 } 286 out_ += "<!--" + comment + "-->"; 287 type = "isCom"; 288 size_t iLenTemp = out_.length(); 289 if (iLength_ > iPos_ + iLenTemp - 1) { 290 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 291 iPos_ += iLenTemp; 292 } else { 293 HILOG_ERROR("SetComment memcpy_s failed"); 294 } 295 } 296 } 297 SetCData(std::string data)298 void XmlSerializer::SetCData(std::string data) 299 { 300 out_ = ""; 301 if (type == "isStart" || type == "isAttri") { 302 SplicNsp(); 303 out_.append(">"); 304 } 305 if (type != "") { 306 NextItem(); 307 } 308 data = Replace(data, "]]>", "]]]]><![CDATA[>"); 309 out_ += "<![CDATA[" + data + "]]>"; 310 type = "isCData"; 311 size_t iLenTemp = out_.length(); 312 if (iLength_ > iPos_ + iLenTemp - 1) { 313 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 314 iPos_ += iLenTemp; 315 } else { 316 HILOG_ERROR("SetCData memcpy_s failed"); 317 } 318 } 319 } 320 SetDocType(const std::string & text)321 void XmlSerializer::SetDocType(const std::string &text) 322 { 323 out_ = ""; 324 if (type == "isStart" || type == "isAttri") { 325 SplicNsp(); 326 out_.append(">"); 327 } 328 if (type != "") { 329 NextItem(); 330 } 331 out_ += "<!DOCTYPE " + text + ">"; 332 type = "isDocType"; 333 size_t iLenTemp = out_.length(); 334 if (iLength_ > iPos_ + iLenTemp - 1) { 335 if (memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp) == EOK) { 336 iPos_ += iLenTemp; 337 } else { 338 HILOG_ERROR("SetDocType memcpy_s failed"); 339 } 340 } 341 } 342 WriteEscaped(std::string s)343 void XmlSerializer::WriteEscaped(std::string s) 344 { 345 size_t len = s.length(); 346 for (size_t i = 0; i < len; ++i) { 347 char c = s[i]; 348 switch (c) { 349 case '\'': 350 out_.append("'"); 351 break; 352 case '\"': 353 out_.append("""); 354 break; 355 case '&': 356 out_.append("&"); 357 break; 358 case '>': 359 out_.append(">"); 360 break; 361 case '<': 362 out_.append("<"); 363 break; 364 default: 365 out_ += c; 366 } 367 } 368 } 369 XmlSerializerError()370 std::string XmlSerializer::XmlSerializerError() 371 { 372 return xmlSerializerError_; 373 } 374 DealOptionInfo(napi_env env,napi_value napiObj)375 napi_value XmlPullParser::DealOptionInfo(napi_env env, napi_value napiObj) 376 { 377 std::vector<std::string> vctOptions = { 378 "supportDoctype", "ignoreNameSpace", "tagValueCallbackFunction", 379 "attributeValueCallbackFunction", "tokenValueCallbackFunction" 380 }; 381 size_t vctLength = vctOptions.size(); 382 for (size_t i = 0; i < vctLength; ++i) { 383 napi_value recvTemp = nullptr; 384 bool bRecv = false; 385 napi_get_named_property(env, napiObj, vctOptions[i].c_str(), &recvTemp); 386 napi_valuetype valuetype; 387 NAPI_CALL(env, napi_typeof(env, recvTemp, &valuetype)); 388 if (valuetype == napi_boolean && (napi_get_value_bool(env, recvTemp, &bRecv)) == napi_ok) { 389 switch (i) { 390 case 0: // 0:supportDoctype 391 bDoctype_ = bRecv; 392 break; 393 case 1: // 1:ignoreNameSpace 394 bIgnoreNS_ = bRecv; 395 break; 396 default: 397 break; 398 } 399 } else if (valuetype == napi_function) { 400 NAPI_ASSERT(env, recvTemp != nullptr, "Parameter is empty."); 401 switch (i) { 402 case 2: // 2:tagValueCallbackFunction 403 tagFunc_ = recvTemp; 404 break; 405 case 3: // 3:attributeValueCallbackFunction 406 attrFunc_ = recvTemp; 407 break; 408 case 4: // 4:tokenValueCallbackFunction 409 tokenFunc_ = recvTemp; 410 break; 411 default: 412 break; 413 } 414 } 415 } 416 return nullptr; 417 } 418 PushSrcLinkList(std::string strBuffer)419 void XmlPullParser::PushSrcLinkList(std::string strBuffer) 420 { 421 auto pNew = new SrcLinkList; 422 srcLinkList_->next = pNew; 423 pNew->strBuffer = strBuffer; 424 pNew->position = 0; 425 pNew->max = strBuffer.size(); 426 srcLinkList_ = pNew; 427 } 428 PopSrcLinkList()429 void XmlPullParser::PopSrcLinkList() 430 { 431 SrcLinkList* pTemp = srcLinkList_; 432 if (srcLinkList_) { 433 srcLinkList_ = srcLinkList_->next; 434 } 435 if (pTemp != nullptr) { 436 delete pTemp; 437 pTemp = nullptr; 438 } 439 } 440 DealLength(size_t minimum)441 bool XmlPullParser::DealLength(size_t minimum) 442 { 443 while (srcLinkList_->next != nullptr) { 444 if (position_ < max_) { 445 xmlPullParserError_ = "Unbalanced entity!"; 446 } 447 PopSrcLinkList(); 448 if (max_ - position_ >= minimum) { 449 return true; 450 } 451 } 452 for (size_t i = 0; i < position_; i++) { 453 if (strXml_[i] == '\n') { 454 bufferStartLine_++; 455 bufferStartColumn_ = 0; 456 } else { 457 bufferStartColumn_++; 458 } 459 } 460 if (keyInfo_ != "") { 461 keyInfo_.append(strXml_, 0, position_); 462 } 463 464 if (max_ > position_) { 465 max_ -= position_; 466 for (size_t j = 0; j < max_; ++j) { 467 strXml_[j] = strXml_[position_ + j]; 468 } 469 } else { 470 max_ = 0; 471 } 472 if (position_ != strXml_.size()) { 473 position_ = 0; 474 } 475 if (strXml_.size() - max_ > 0 && position_ == 0) { 476 max_ += strXml_.size() - max_; 477 if (max_ >= minimum) { 478 return true; 479 } 480 } 481 return false; 482 } 483 GetNSCount(size_t iTemp)484 size_t XmlPullParser::GetNSCount(size_t iTemp) 485 { 486 if (iTemp > depth) { 487 xmlPullParserError_ = " IndexOutOfBoundsException"; 488 } 489 return nspCounts_[depth]; 490 } 491 XmlPullParserError() const492 std::string XmlPullParser::XmlPullParserError() const 493 { 494 return xmlPullParserError_; 495 } 496 ParseToken(napi_env env,napi_value thisVar) const497 bool XmlPullParser::ParseToken(napi_env env, napi_value thisVar) const 498 { 499 napi_handle_scope scope = nullptr; 500 napi_status status = napi_open_handle_scope(env, &scope); 501 if (status != napi_ok) { 502 HILOG_ERROR("XmlPullParser::open scope failed!"); 503 return false; 504 } 505 napi_value returnVal = nullptr; 506 size_t argc = 2; // 2: number of args 507 napi_value key = nullptr; 508 napi_create_int32(env, (int)type, &key); 509 napi_value parseInfo = nullptr; 510 napi_create_object(env, &parseInfo); 511 auto object = new ParseInfo(); 512 napi_wrap(env, parseInfo, object, nullptr, nullptr, nullptr); 513 static napi_property_descriptor xmlDesc[] = { 514 DECLARE_NAPI_FUNCTION("getDepth", XmlPullParser::ParseInfo::GetDepth), 515 DECLARE_NAPI_FUNCTION("getColumnNumber", XmlPullParser::ParseInfo::GetColumnNumber), 516 DECLARE_NAPI_FUNCTION("getLineNumber", XmlPullParser::ParseInfo::GetLineNumber), 517 DECLARE_NAPI_FUNCTION("getAttributeCount", XmlPullParser::ParseInfo::GetAttributeCount), 518 DECLARE_NAPI_FUNCTION("getName", XmlPullParser::ParseInfo::GetName), 519 DECLARE_NAPI_FUNCTION("getNamespace", XmlPullParser::ParseInfo::GetNamespace), 520 DECLARE_NAPI_FUNCTION("getPrefix", XmlPullParser::ParseInfo::GetPrefix), 521 DECLARE_NAPI_FUNCTION("getText", XmlPullParser::ParseInfo::GetText), 522 DECLARE_NAPI_FUNCTION("isEmptyElementTag", XmlPullParser::ParseInfo::IsEmptyElementTag), 523 DECLARE_NAPI_FUNCTION("isWhitespace", XmlPullParser::ParseInfo::IsWhitespace) 524 }; 525 napi_define_properties(env, parseInfo, sizeof(xmlDesc) / sizeof(xmlDesc[0]), xmlDesc); 526 napi_set_named_property(env, parseInfo, "MainInfo", thisVar); 527 napi_value argv[2] = {key, parseInfo}; // 2: number of args 528 napi_call_function(env, parseInfo, tokenFunc_, argc, argv, &returnVal); 529 bool bRec = false; 530 napi_get_value_bool(env, returnVal, &bRec); 531 if (object != nullptr) { 532 delete object; 533 object = nullptr; 534 } 535 napi_close_handle_scope(env, scope); 536 return bRec; 537 } 538 ParseAttri(napi_env env,napi_value thisVar) const539 bool XmlPullParser::ParseAttri(napi_env env, napi_value thisVar) const 540 { 541 for (size_t i = 0; i < attriCount_; ++i) { 542 napi_value returnVal = nullptr; 543 size_t argc = 3; // 3: number of args 544 napi_value global = nullptr; 545 napi_get_global(env, &global); 546 napi_value key = nullptr; 547 napi_create_string_utf8(env, attributes[i * 4 + 2].c_str(), // 4 and 2: number of args 548 attributes[i * 4 + 2].size(), &key); // 4 and 2: number of args 549 napi_value value = nullptr; 550 napi_create_string_utf8(env, attributes[i * 4 + 3].c_str(), // 4 and 3: number of args 551 attributes[i * 4 + 3].size(), &value); // 3 and 4: number of args 552 napi_value argv[3] = {key, value, thisVar}; 553 napi_call_function(env, global, attrFunc_, argc, argv, &returnVal); 554 bool bRec = false; 555 napi_get_value_bool(env, returnVal, &bRec); 556 if (!bRec) { 557 return bRec; 558 } 559 } 560 return true; 561 } 562 DealCdata(std::string data)563 std::string XmlPullParser::DealCdata(std::string data) 564 { 565 std::string_view cDataBegin = "<![CDATA["; 566 std::string_view cDataEnd = "]]>"; 567 size_t foundPosBegin = data.find(cDataBegin); 568 size_t foundPosEnd = data.find(cDataEnd); 569 size_t count = 0; 570 while (foundPosBegin != std::string::npos) { 571 std::string temp = data.substr(foundPosBegin, foundPosEnd - foundPosBegin + cDataEnd.length()); 572 std::string resStr = ""; 573 for (char c : temp) { 574 if (c == '\r') { 575 resStr += "\\r"; 576 count++; 577 } else if (c == '\n') { 578 resStr += "\\n"; 579 count++; 580 } else { 581 resStr += c; 582 } 583 } 584 data.replace(foundPosBegin, temp.length(), resStr); 585 foundPosBegin = data.find(cDataBegin, foundPosBegin + 1); 586 foundPosEnd = data.find(cDataEnd, foundPosEnd + count + 1); 587 } 588 return data; 589 } 590 Parse(napi_env env,napi_value thisVar,bool deprecated)591 void XmlPullParser::Parse(napi_env env, napi_value thisVar, bool deprecated) 592 { 593 if (deprecated) { 594 strXml_ = DealCdata(strXml_); 595 } 596 if (tagFunc_ || attrFunc_ || tokenFunc_) { 597 while (type != TagEnum::END_DOCUMENT) { 598 if (ParseOneTag() == TagEnum::ERROR) { 599 break; 600 } 601 bool bRec = false; 602 if (tagFunc_) { 603 napi_value returnVal = nullptr; 604 size_t argc = 3; // 3: number of args 605 napi_value global = nullptr; 606 napi_get_global(env, &global); 607 napi_value key = nullptr; 608 napi_create_string_utf8(env, name_.c_str(), name_.size(), &key); 609 napi_value value = nullptr; 610 napi_create_string_utf8(env, text_.c_str(), text_.size(), &value); 611 napi_value argv[3] = {key, value, thisVar}; 612 napi_call_function(env, global, tagFunc_, argc, argv, &returnVal); 613 napi_get_value_bool(env, returnVal, &bRec); 614 } 615 if (tagFunc_ && type == TagEnum::START_TAG && !bRec) { 616 break; 617 } 618 if (tokenFunc_) { 619 bRec = ParseToken(env, thisVar); 620 } 621 if (tokenFunc_ && !bRec) { 622 break; 623 } 624 if (attrFunc_ && attriCount_) { 625 bRec = ParseAttri(env, thisVar); 626 attriCount_ = 0; 627 } 628 if (attrFunc_ && attriCount_ && !bRec) { 629 break; 630 } 631 } 632 } 633 } 634 DealExclamationGroup()635 TagEnum XmlPullParser::DealExclamationGroup() 636 { 637 switch (strXml_[position_ + 2]) { // 2: number of args 638 case 'D': 639 return TagEnum::DOCDECL; 640 case '[': 641 return TagEnum::CDSECT; 642 case '-': 643 return TagEnum::COMMENT; 644 case 'E': 645 switch (strXml_[position_ + 3]) { // 3: number of args 646 case 'L': 647 return TagEnum::ELEMENTDECL; 648 case 'N': 649 return TagEnum::ENTITYDECL; 650 default: 651 break; 652 } 653 xmlPullParserError_ = "Unexpected <!"; 654 break; 655 case 'A': 656 return TagEnum::ATTLISTDECL; 657 case 'N': 658 return TagEnum::NOTATIONDECL; 659 default: 660 break; 661 } 662 return TagEnum::ERROR; 663 } 664 DealLtGroup()665 TagEnum XmlPullParser::DealLtGroup() 666 { 667 if (position_ + 3 >= max_ && !DealLength(4)) { // 4: number of args 3: number of args 668 xmlPullParserError_ = ("Dangling <"); 669 } 670 char cTemp = strXml_[position_ + 1]; 671 if (cTemp == '/') { 672 return TagEnum::END_TAG; 673 } else if (cTemp == '?') { 674 std::string strXml = strXml_.substr(position_ + 2, 4); // 2 and 4:position and length 675 MakeStrUpper(strXml); 676 if (max_ >= position_ + 5 && strXml == tagText_.XML) { // 5: number of args 677 return TagEnum::XML_DECLARATION; 678 } else { 679 return TagEnum::INSTRUCTION; 680 } 681 } else if (cTemp == '!') { 682 return DealExclamationGroup(); 683 } else { 684 return TagEnum::START_TAG; 685 } 686 } 687 ParseTagType(bool inDeclaration)688 TagEnum XmlPullParser::ParseTagType(bool inDeclaration) 689 { 690 if (bStartDoc_) { 691 bStartDoc_ = false; 692 return TagEnum::START_DOCUMENT; 693 } 694 if (position_ >= max_ && !DealLength(1)) { 695 return TagEnum::END_DOCUMENT; 696 } 697 switch (strXml_[position_]) { 698 case '&': 699 if (apiVersion_ >= APIVerIsolation_.API12) { 700 return TagEnum::ENTITY_REFERENCE; 701 } else { 702 return inDeclaration ? TagEnum::ENTITY_REFERENCE : TagEnum::TEXT; 703 } 704 case '<': 705 return DealLtGroup(); 706 case '%': 707 return inDeclaration ? TagEnum::PARAMETER_ENTITY_REF : TagEnum::TEXT; 708 default: 709 return TagEnum::TEXT; 710 } 711 } 712 MakeStrUpper(std::string & src) const713 void XmlPullParser::MakeStrUpper(std::string &src) const 714 { 715 size_t i = 0; 716 717 while (i < src.size()) { 718 if (src[i] >= 'A' && src[i] <= 'Z') { 719 src[i] += 32; // 32: number of args 720 } 721 ++i; 722 } 723 } 724 SkipText(std::string chars)725 void XmlPullParser::SkipText(std::string chars) 726 { 727 if (position_ + chars.size() > max_ && !DealLength(chars.size())) { 728 xmlPullParserError_ = "expected: '" + chars + "' but was EOF"; 729 return; 730 } 731 size_t len = chars.length(); 732 if (strXml_.substr(position_, len) != chars) { 733 xmlPullParserError_ = "expected: \"" + chars + "\" but was \"" + strXml_.substr(position_, len) + "...\""; 734 } 735 position_ += len; 736 } 737 PriorDealChar()738 int XmlPullParser::PriorDealChar() 739 { 740 if (position_ < max_ || DealLength(1)) { 741 return strXml_[position_]; 742 } 743 return -1; 744 } 745 SkipChar(char expected)746 void XmlPullParser::SkipChar(char expected) 747 { 748 int c = PriorDealChar(); 749 if (c != expected) { 750 xmlPullParserError_ = "expected:"; 751 if (c == -1) { 752 return; 753 } 754 } 755 position_++; 756 } 757 ParseNameInner(size_t start)758 std::string XmlPullParser::ParseNameInner(size_t start) 759 { 760 std::string result = ""; 761 char c = 0; 762 while (true) { 763 if (position_ >= max_) { 764 result.append(strXml_, start, position_ - start); 765 if (!DealLength(1)) { 766 return result; 767 } 768 start = position_; 769 } 770 c = strXml_[position_]; 771 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || 772 (c >= '0' && c <= '9') || c == '_' || c == '-' || 773 c == ':' || c == '.') { 774 position_++; 775 continue; 776 } 777 result.append(strXml_, start, position_ - start); 778 return result; 779 } 780 } 781 ParseName()782 std::string XmlPullParser::ParseName() 783 { 784 if (position_ >= max_ && !DealLength(1)) { 785 xmlPullParserError_ = "name expected"; 786 return ""; 787 } 788 size_t start = position_; 789 char c = strXml_[position_]; 790 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || 791 c == '_' || c == ':' || relaxed) { 792 position_++; 793 } else { 794 xmlPullParserError_ = "The node name contains invalid characters: "; 795 xmlPullParserError_ += c; 796 return ""; 797 } 798 return ParseNameInner(start); 799 } 800 SkipInvalidChar()801 void XmlPullParser::SkipInvalidChar() 802 { 803 while (position_ < max_ || DealLength(1)) { 804 unsigned char temp = strXml_[position_]; 805 if (temp > ' ') { 806 break; 807 } 808 position_++; 809 } 810 } 811 ParseEntityFunc(size_t start,std::string & out,bool isEntityToken,TextEnum textEnum)812 void XmlPullParser::ParseEntityFunc(size_t start, std::string &out, bool isEntityToken, TextEnum textEnum) 813 { 814 std::string strEntity = out.substr(start + 1, out.length() - 1); 815 if (isEntityToken) { 816 name_ = strEntity; 817 } 818 if (strEntity.size() && strEntity[0] == '#') { 819 int c = 0; 820 if (strEntity.size() >= 2 && strEntity[1] == 'x') { // 2: number of args 821 c = std::stoi(strEntity.substr(2), nullptr, 16); // 16: number of args 2: number of args 822 } else { 823 c = std::stoi(strEntity.substr(1), nullptr); 824 } 825 out = ""; 826 out += static_cast<char>(c); 827 bUnresolved_ = false; 828 return; 829 } 830 if (textEnum == TextEnum::ENTITY_DECL) { 831 return; 832 } 833 if (DEFAULT_ENTITIES.count(strEntity) != 0) { 834 out = out.substr(0, start); 835 bUnresolved_ = false; 836 out.append(DEFAULT_ENTITIES[strEntity]); 837 return; 838 } 839 std::string resolved = " "; 840 if (documentEntities.size() != 0 && (resolved = strEntity) != "") { 841 out = ""; 842 bUnresolved_ = false; 843 if (bDocDecl) { 844 PushSrcLinkList(resolved); 845 } else { 846 out.append(resolved); 847 } 848 return; 849 } 850 if (sysInfo_ != "") { 851 out = ""; 852 return; 853 } 854 bUnresolved_ = true; 855 } 856 ParseEntity(std::string & out,bool isEntityToken,bool throwOnResolveFailure,TextEnum textEnum)857 void XmlPullParser::ParseEntity(std::string &out, 858 bool isEntityToken, 859 bool throwOnResolveFailure, 860 TextEnum textEnum) 861 { 862 size_t start = out.length(); 863 if (strXml_[position_++] != '&') { 864 xmlPullParserError_ = "Should not be reached"; 865 } 866 out += '&'; 867 while (true) { 868 int c = PriorDealChar(); 869 if (c == ';') { 870 out += ';'; 871 position_++; 872 break; 873 } else if (c >= 128 || // 128: number of args 874 (c >= '0' && c <= '9') || 875 (c >= 'a' && c <= 'z') || 876 (c >= 'A' && c <= 'Z') || 877 c == '_' || 878 c == '-' || 879 c == '#') { 880 position_++; 881 out.push_back(static_cast<char>(c)); 882 } else if (relaxed) { 883 return; 884 } else { 885 xmlPullParserError_ = "unterminated entity ref"; 886 break; 887 } 888 } 889 ParseEntityFunc(start, out, isEntityToken, textEnum); 890 } 891 ParseTagValueFunc(char & c,bool bFlag,TextEnum textEnum,size_t & start,std::string & result)892 bool XmlPullParser::ParseTagValueFunc(char &c, bool bFlag, TextEnum textEnum, 893 size_t &start, std::string &result) 894 { 895 if (c == '\r') { 896 if ((position_ + 1 < max_ || DealLength(2)) && strXml_[position_ + 1] == '\n') { // 2: number of args 897 position_++; 898 } 899 c = (textEnum == TextEnum::ATTRI) ? ' ' : '\n'; 900 } else if (c == '\n') { 901 c = ' '; 902 } else if (c == '&') { 903 bWhitespace_ = false; 904 ParseEntity(result, false, bFlag, textEnum); 905 start = position_; 906 return false; 907 } else if (c == '<') { 908 if (textEnum == TextEnum::ATTRI) { 909 xmlPullParserError_ = "Illegal: \"<\" inside attribute value"; 910 } 911 bWhitespace_ = false; 912 } else if (c == ']') { 913 if ((position_ + 2 < max_ || DealLength(3)) && // 2: number of args 3: number of args 914 strXml_[position_ + 1] == ']' && strXml_[position_ + 2] == '>') { // 2: number of args 915 xmlPullParserError_ = "Illegal: \"]]>\" outside CDATA section"; 916 } 917 bWhitespace_ = false; 918 } else if (c == '%') { 919 xmlPullParserError_ = "This parser doesn't support parameter entities"; 920 } else { 921 xmlPullParserError_ = "AssertionError"; 922 } 923 return true; 924 } 925 DealWhiteSpace(unsigned char c)926 void XmlPullParser::DealWhiteSpace(unsigned char c) 927 { 928 if (bWhitespace_ && c <= ' ') { 929 bWhitespace_ = true; 930 } else { 931 bWhitespace_ = false; 932 } 933 } 934 ParseTagValueInner(size_t & start,std::string & result,char delimiter,TextEnum textEnum,bool bFlag)935 size_t XmlPullParser::ParseTagValueInner(size_t &start, std::string &result, 936 char delimiter, TextEnum textEnum, bool bFlag) 937 { 938 if (position_ >= max_) { 939 if (start < position_) { 940 result.append(strXml_, start, position_ - start); 941 } 942 if (!DealLength(1)) { 943 result = (result != "" ? result : ""); 944 return 0; 945 } 946 start = position_; 947 } 948 unsigned char c = strXml_[position_]; 949 if (c == delimiter || 950 (delimiter == ' ' && (c <= ' ' || c == '>')) || 951 (c == '&' && !bFlag)) { 952 return 1; 953 } 954 if (c != '\r' && (c != '\n' || textEnum != TextEnum::ATTRI) && 955 c != '&' && c != '<' && (c != ']' || textEnum != TextEnum::TEXT) && 956 (c != '%' || textEnum != TextEnum::ENTITY_DECL)) { 957 DealWhiteSpace(c); 958 position_++; 959 return 2; // 2: break flag 960 } 961 result.append(strXml_, start, position_ - start); 962 return c; 963 } 964 ParseTagValue(char delimiter,bool resolveEntities,bool throwOnResolveFailure,TextEnum textEnum)965 std::string XmlPullParser::ParseTagValue(char delimiter, bool resolveEntities, 966 bool throwOnResolveFailure, TextEnum textEnum) 967 { 968 size_t start = position_; 969 std::string result = ""; 970 if (textEnum == TextEnum::TEXT && text_ != "") { 971 result.append(text_); 972 } 973 while (true) { 974 char cRecv = static_cast<char>(ParseTagValueInner(start, result, delimiter, textEnum, resolveEntities)); 975 if (cRecv == 0) { 976 return result; 977 } else if (cRecv == 1) { 978 break; 979 } else if (cRecv == 2) { // 2: break flag 980 continue; 981 } else if (!ParseTagValueFunc(cRecv, throwOnResolveFailure, textEnum, start, result)) { 982 continue; 983 } 984 ++position_; 985 result = result + static_cast<char>(cRecv); 986 start = position_; 987 } 988 result.append(strXml_, start, position_ - start); 989 return result; 990 } 991 GetNamespace(const std::string & prefix)992 std::string XmlPullParser::GetNamespace(const std::string &prefix) 993 { 994 size_t temp = GetNSCount(depth) << 1; 995 if (temp) { 996 size_t i = temp - 2; // 2: number of args 997 for (; i >= 0; i -= 2) { // 2: number of args 998 if (prefix == "" && nspStack_[i] == "") { 999 return nspStack_[i + 1]; 1000 } else if (prefix == nspStack_[i]) { 1001 return nspStack_[i + 1]; 1002 } 1003 if (!i) { 1004 break; 1005 } 1006 } 1007 } 1008 return ""; 1009 } 1010 Replace(std::string & strTemp,std::string strSrc,std::string strDes) const1011 void XmlPullParser::Replace(std::string& strTemp, std::string strSrc, std::string strDes) const 1012 { 1013 size_t iPos = 0; 1014 while ((iPos = strTemp.find(strSrc)) != std::string::npos) { 1015 strTemp.replace(iPos, strSrc.size(), strDes); 1016 } 1017 } 1018 ParseNspFunc(size_t & i,const std::string & attrName,bool & any)1019 void XmlPullParser::ParseNspFunc(size_t &i, const std::string &attrName, bool &any) 1020 { 1021 size_t j = (nspCounts_[depth]++) << 1; 1022 size_t uiSize = nspStack_.size(); 1023 if (uiSize < j + 2) { // 2: number of args 1024 nspStack_.resize(j + 16); // 16: number of args 1025 } 1026 nspStack_[j] = attrName; 1027 nspStack_[j + 1] = attributes[i + 3]; // 3: number of args 1028 if (attrName != "" && attributes[i + 3].empty()) { // 3: number of args 1029 xmlPullParserError_ = "illegal empty namespace"; 1030 } 1031 if (bKeepNsAttri) { 1032 attributes[i] = "http://www.w3.org/2000/xmlns/"; 1033 any = true; 1034 } else { 1035 for (size_t iCount = i; iCount < ((--attriCount_) << 2); ++iCount) { // 2: number of args 1036 attributes[iCount] = attributes[iCount + 4]; // 4: number of args 1037 } 1038 i -= 4; // 4: 1039 } 1040 } 1041 ParseNspFunction()1042 void XmlPullParser::ParseNspFunction() 1043 { 1044 int i = (attriCount_ << 2) - 4; // 4: number of args 2: number of args 1045 for (; i >= 0; i -= 4) { // 4: number of args 1046 std::string attrName = attributes[i + 2]; // 2: number of args 1047 size_t cut = attrName.find(':'); 1048 if (cut == 0 && !relaxed) { 1049 xmlPullParserError_ = "illegal attribute name: "; 1050 } else if (cut != std::string::npos) { 1051 std::string attrPrefix = attrName.substr(0, cut); 1052 attrName = attrName.substr(cut + 1); 1053 std::string attrNs = GetNamespace(attrPrefix); 1054 if (attrNs == "" && !relaxed) { 1055 xmlPullParserError_ = ("Undefined Prefix: " + attrPrefix + " in "); 1056 } 1057 attributes[i] = attrNs; 1058 attributes[i + 1] = attrPrefix; 1059 attributes[i + 2] = attrName; // 2: number of args 1060 } 1061 } 1062 } 1063 ParseNsp()1064 bool XmlPullParser::ParseNsp() 1065 { 1066 bool any = false; 1067 size_t cut = 0; 1068 for (size_t i = 0; i < (attriCount_ << 2); i += 4) { // 2 and 4: number of args 1069 std::string attrName = attributes[i + 2]; // 2: number of args 1070 cut = attrName.find(':'); 1071 std::string prefix; 1072 if (cut != std::string::npos) { 1073 prefix = attrName.substr(0, cut); 1074 attrName = attrName.substr(cut + 1); 1075 } else if (attrName == ("xmlns")) { 1076 prefix = attrName; 1077 attrName = ""; 1078 } else { 1079 continue; 1080 } 1081 if (!(prefix == "xmlns")) { 1082 any = true; 1083 } else { 1084 ParseNspFunc(i, attrName, any); 1085 } 1086 } 1087 if (any) { 1088 ParseNspFunction(); 1089 } 1090 cut = name_.find(':'); 1091 if (cut == 0) { 1092 xmlPullParserError_ = "illegal tag name: " + name_; 1093 } 1094 if (cut != std::string::npos) { 1095 prefix_ = name_.substr(0, cut); 1096 name_ = name_.substr(cut + 1); 1097 } 1098 namespace_ = GetNamespace(prefix_); 1099 return any; 1100 } 1101 ParseStartTagFuncDeal(bool throwOnResolveFailure)1102 bool XmlPullParser::ParseStartTagFuncDeal(bool throwOnResolveFailure) 1103 { 1104 std::string attrName = ParseName(); 1105 if (attrName.empty()) { 1106 return false; 1107 } 1108 int i = (attriCount_++) * 4; // 4: number of args 1109 attributes.resize(attributes.size() + 4); // 4: number of args 1110 attributes[i] = ""; 1111 attributes[i + 1] = ""; 1112 attributes[i + 2] = attrName; // 2: number of args 1113 SkipInvalidChar(); 1114 if (position_ >= max_ && !DealLength(1)) { 1115 xmlPullParserError_ = "UNEXPECTED_EOF"; 1116 return false; 1117 } 1118 if (strXml_[position_] == '=') { 1119 position_++; 1120 SkipInvalidChar(); 1121 if (position_ >= max_) { 1122 xmlPullParserError_ = "UNEXPECTED_EOF"; 1123 return false; 1124 } 1125 char delimiter = strXml_[position_]; 1126 if (delimiter == '\'' || delimiter == '"') { 1127 position_++; 1128 } else if (relaxed) { 1129 delimiter = ' '; 1130 } else { 1131 xmlPullParserError_ = "attr value delimiter missing!"; 1132 return false; 1133 } 1134 attributes[i + 3] = ParseTagValue(delimiter, true, // 3: number of args 1135 throwOnResolveFailure, TextEnum::ATTRI); // 3: number of args 1136 if (delimiter != ' ' && PriorDealChar() == delimiter) { 1137 position_++; 1138 } 1139 } else { 1140 attributes[i + 3] = attrName; // 3: number of args 1141 } 1142 return true; 1143 } 1144 ParseStartTagFunc(bool xmldecl,bool throwOnResolveFailure)1145 TagEnum XmlPullParser::ParseStartTagFunc(bool xmldecl, bool throwOnResolveFailure) 1146 { 1147 while (true) { 1148 SkipInvalidChar(); 1149 if (position_ >= max_ && DealLength(1)) { 1150 xmlPullParserError_ = "UNEXPECTED_EOF"; 1151 return TagEnum::ERROR; 1152 } 1153 unsigned char temp = strXml_[position_]; 1154 if (xmldecl) { 1155 if (temp == '?') { 1156 position_++; 1157 SkipChar('>'); 1158 return TagEnum::XML_DECLARATION; 1159 } 1160 } else { 1161 if (temp == '/') { 1162 bEndFlag_ = true; 1163 position_++; 1164 SkipInvalidChar(); 1165 SkipChar('>'); 1166 break; 1167 } else if (temp == '>') { 1168 position_++; 1169 break; 1170 } 1171 } 1172 bool bRecv = ParseStartTagFuncDeal(throwOnResolveFailure); 1173 if (!bRecv) { 1174 return TagEnum::ERROR; 1175 } 1176 } 1177 return TagEnum::OK; 1178 } 1179 ParseStartTag(bool xmldecl,bool throwOnResolveFailure)1180 TagEnum XmlPullParser::ParseStartTag(bool xmldecl, bool throwOnResolveFailure) 1181 { 1182 if (!xmldecl) { 1183 SkipChar('<'); 1184 } 1185 name_ = ParseName(); 1186 attriCount_ = 0; 1187 TagEnum bRecv = ParseStartTagFunc(xmldecl, throwOnResolveFailure); 1188 if (bRecv != TagEnum::OK) { 1189 return bRecv; 1190 } 1191 size_t sp = depth++ * 4; // 4: number of args 1192 elementStack_.resize(sp + 4); // 4: number of args 1193 elementStack_[sp + 3] = name_; // 3: number of args 1194 if (depth >= nspCounts_.size()) { 1195 nspCounts_.resize(depth + 4); // 4: number of args 1196 } 1197 nspCounts_[depth] = nspCounts_[depth - 1]; 1198 if (!bIgnoreNS_) { 1199 ParseNsp(); 1200 } else { 1201 namespace_ = ""; 1202 } 1203 if (defaultAttributes.size() != 0) { 1204 std::map<std::string, std::string> elementDefaultAttributes = defaultAttributes[name_]; 1205 if (elementDefaultAttributes.size() != 0) { 1206 for (std::map<std::string, std::string>::iterator iter = elementDefaultAttributes.begin(); 1207 iter != elementDefaultAttributes.end(); ++iter) { 1208 } 1209 } 1210 } 1211 elementStack_[sp] = namespace_; 1212 elementStack_[sp + 1] = prefix_; 1213 elementStack_[sp + 2] = name_; // 2: number of args 1214 return TagEnum::OK; 1215 } 1216 ParseDeclaration()1217 void XmlPullParser::ParseDeclaration() 1218 { 1219 if (bufferStartLine_ != 0 || bufferStartColumn_ != 0 || position_ != 0) { 1220 xmlPullParserError_ = "processing instructions must not start with xml"; 1221 } 1222 SkipText(tagText_.START_PROCESSING_INSTRUCTION); 1223 ParseStartTag(true, true); 1224 if (attriCount_ < 1 || attributes[2] != "version") { // 2: number of args 1225 xmlPullParserError_ = "version expected"; 1226 } 1227 version_ = attributes[3]; // 3: number of args 1228 size_t pos = 1; 1229 if (pos < attriCount_ && (attributes[2 + 4]) == "encoding") { // 4: number of args 2: number of args 1230 encoding_ = attributes[3 + 4]; // 3: number of args 4: number of args 1231 pos++; 1232 } 1233 if (pos < attriCount_ && (attributes[4 * pos + 2]) == "standalone") { // 4: number of args 2: number of args 1234 std::string st = attributes[3 + 4 * pos]; // 3: number of args 4: number of args 1235 if (st == "yes") { 1236 bAlone_ = true; 1237 } else if (st == "no") { 1238 bAlone_ = false; 1239 } else { 1240 xmlPullParserError_ = "illegal standalone value: " + st; 1241 } 1242 pos++; 1243 } 1244 if (pos != attriCount_) { 1245 xmlPullParserError_ = "unexpected attributes in XML declaration"; 1246 } 1247 bWhitespace_ = true; 1248 text_ = ""; 1249 } 1250 ParseEndTag()1251 bool XmlPullParser::ParseEndTag() 1252 { 1253 SkipChar('<'); 1254 SkipChar('/'); 1255 name_ = ParseName(); 1256 if (name_.empty()) { 1257 return false; 1258 } 1259 SkipInvalidChar(); 1260 SkipChar('>'); 1261 if (depth == 0) { 1262 xmlPullParserError_ = "read end tag " + name_ + " with no tags open"; 1263 type = TagEnum::COMMENT; 1264 return true; 1265 } 1266 size_t sp = (depth - 1) * 4; // 4: number of args 1267 if (name_ == elementStack_[sp + 3]) { // 3: number of args 1268 namespace_ = elementStack_[sp]; 1269 prefix_ = elementStack_[sp + 1]; 1270 name_ = elementStack_[sp + 2]; // 2: number of args 1271 } else if (!relaxed) { 1272 xmlPullParserError_ = "expected: /" + elementStack_[sp + 3] + " read: " + name_; // 3: number of args 1273 } 1274 return true; 1275 } 1276 ParseDelimiterInfo(std::string delimiter,bool returnText)1277 std::string XmlPullParser::ParseDelimiterInfo(std::string delimiter, bool returnText) 1278 { 1279 size_t start = position_; 1280 std::string result = ""; 1281 if (returnText && text_ != "") { 1282 result.append(text_); 1283 } 1284 bool bFlag = true; 1285 while (bFlag) { 1286 if (position_ + (delimiter).length() > max_) { 1287 if (start < position_ && returnText) { 1288 result.append(strXml_, start, position_ - start); 1289 } 1290 if (!DealLength(delimiter.length())) { 1291 type = TagEnum::COMMENT; 1292 return ""; 1293 } 1294 start = position_; 1295 } 1296 size_t i = 0; 1297 for (; i < delimiter.length(); i++) { 1298 if (strXml_[position_ + i] != delimiter[i]) { 1299 position_++; 1300 break; 1301 } 1302 } 1303 if (i == delimiter.length()) { 1304 bFlag = false; 1305 } 1306 } 1307 size_t end = position_; 1308 position_ += delimiter.length(); 1309 if (!returnText) { 1310 return ""; 1311 } else { 1312 result.append(strXml_, start, end - start); 1313 return result; 1314 } 1315 } 1316 ParseDelimiter(bool returnText)1317 std::string XmlPullParser::ParseDelimiter(bool returnText) 1318 { 1319 int quote = PriorDealChar(); 1320 std::string delimiter; 1321 if (quote == '"') { 1322 delimiter = tagText_.DOUBLE_QUOTE; 1323 } else if (quote == '\'') { 1324 delimiter = tagText_.SINGLE_QUOTE; 1325 } else { 1326 xmlPullParserError_ = "Expected a quoted std::string "; 1327 } 1328 position_++; 1329 return ParseDelimiterInfo(delimiter, returnText); 1330 } 1331 ParserDoctInnerInfo(bool requireSystemName,bool assignFields)1332 bool XmlPullParser::ParserDoctInnerInfo(bool requireSystemName, bool assignFields) 1333 { 1334 SkipInvalidChar(); 1335 int c = PriorDealChar(); 1336 if (c == 'S') { 1337 SkipText(tagText_.SYSTEM); 1338 } else if (c == 'P') { 1339 SkipText(tagText_.PUBLIC); 1340 SkipInvalidChar(); 1341 if (assignFields) { 1342 pubInfo_ = ParseDelimiter(true); 1343 } else { 1344 ParseDelimiter(false); 1345 } 1346 } else { 1347 return false; 1348 } 1349 SkipInvalidChar(); 1350 if (!requireSystemName) { 1351 int delimiter = PriorDealChar(); 1352 if (delimiter != '"' && delimiter != '\'') { 1353 return true; // no system name! 1354 } 1355 } 1356 if (assignFields) { 1357 sysInfo_ = ParseDelimiter(true); 1358 } else { 1359 ParseDelimiter(false); 1360 } 1361 return true; 1362 } 1363 ParseComment(bool returnText)1364 void XmlPullParser::ParseComment(bool returnText) 1365 { 1366 SkipText(tagText_.START_COMMENT); 1367 if (relaxed) { 1368 std::string strTemp = ParseDelimiterInfo(tagText_.END_COMMENT, returnText); 1369 if (returnText) { 1370 text_ = strTemp; 1371 } 1372 } 1373 std::string commentText = ParseDelimiterInfo(tagText_.COMMENT_DOUBLE_DASH, returnText); 1374 if (PriorDealChar() != '>') { 1375 xmlPullParserError_ = "Comments may not contain -- "; 1376 } 1377 position_++; 1378 if (returnText) { 1379 text_ = commentText; 1380 } 1381 } 1382 ParseSpecText()1383 void XmlPullParser::ParseSpecText() 1384 { 1385 SkipInvalidChar(); 1386 int c = PriorDealChar(); 1387 if (c == '(') { 1388 int iDepth = 0; 1389 do { 1390 if (c == '(') { 1391 iDepth++; 1392 } else if (c == ')') { 1393 iDepth--; 1394 } else if (c == -1) { 1395 xmlPullParserError_ = "Unterminated element content spec "; 1396 } 1397 position_++; 1398 c = PriorDealChar(); 1399 } while (iDepth > 0); 1400 if (c == '*' || c == '?' || c == '+') { 1401 position_++; 1402 } 1403 } else if (c == tagText_.EMPTY[0]) { 1404 SkipText(tagText_.EMPTY); 1405 } else if (c == tagText_.ANY[0]) { 1406 SkipText(tagText_.ANY); 1407 } else { 1408 xmlPullParserError_ = "Expected element content spec "; 1409 } 1410 } 1411 ParseInnerEleDec()1412 void XmlPullParser::ParseInnerEleDec() 1413 { 1414 SkipText(tagText_.START_ELEMENT); 1415 SkipInvalidChar(); 1416 ParseName(); 1417 ParseSpecText(); 1418 SkipInvalidChar(); 1419 SkipChar('>'); 1420 } 1421 ParseInnerAttriDeclFunc(int & c)1422 void XmlPullParser::ParseInnerAttriDeclFunc(int &c) 1423 { 1424 if (c == '(') { 1425 position_++; 1426 while (true) { 1427 SkipInvalidChar(); 1428 ParseName(); 1429 SkipInvalidChar(); 1430 c = PriorDealChar(); 1431 if (c == ')') { 1432 position_++; 1433 break; 1434 } else if (c == '|') { 1435 position_++; 1436 } else { 1437 xmlPullParserError_ = "Malformed attribute type "; 1438 } 1439 } 1440 } else { 1441 ParseName(); 1442 } 1443 } 1444 ParseInnerAttriDecl()1445 void XmlPullParser::ParseInnerAttriDecl() 1446 { 1447 SkipText(tagText_.START_ATTLIST); 1448 SkipInvalidChar(); 1449 std::string elementName = ParseName(); 1450 while (true) { 1451 SkipInvalidChar(); 1452 int c = PriorDealChar(); 1453 if (c == '>') { 1454 position_++; 1455 return; 1456 } 1457 std::string attributeName = ParseName(); 1458 SkipInvalidChar(); 1459 if (position_ + 1 >= max_ && !DealLength(2)) { // 2: lengths 1460 xmlPullParserError_ = "Malformed attribute list "; 1461 } 1462 if (strXml_[position_] == tagText_.NOTATION[0] && strXml_[position_ + 1] == tagText_.NOTATION[1]) { 1463 SkipText(tagText_.NOTATION); 1464 SkipInvalidChar(); 1465 } 1466 c = PriorDealChar(); 1467 ParseInnerAttriDeclFunc(c); 1468 SkipInvalidChar(); 1469 c = PriorDealChar(); 1470 if (c == '#') { 1471 position_++; 1472 c = PriorDealChar(); 1473 if (c == 'R') { 1474 SkipText(tagText_.REQUIRED); 1475 } else if (c == 'I') { 1476 SkipText(tagText_.IMPLIED); 1477 } else if (c == 'F') { 1478 SkipText(tagText_.FIXED); 1479 } else { 1480 xmlPullParserError_ = "Malformed attribute type"; 1481 } 1482 SkipInvalidChar(); 1483 c = PriorDealChar(); 1484 } 1485 if (c == '"' || c == '\'') { 1486 position_++; 1487 std::string value = ParseTagValue(static_cast<char>(c), true, true, TextEnum::ATTRI); 1488 if (PriorDealChar() == c) { 1489 position_++; 1490 } 1491 } 1492 } 1493 } 1494 ParseEntityDecl()1495 void XmlPullParser::ParseEntityDecl() 1496 { 1497 SkipText(tagText_.START_ENTITY); 1498 bool generalEntity = true; 1499 SkipInvalidChar(); 1500 if (PriorDealChar() == '%') { 1501 generalEntity = false; 1502 position_++; 1503 SkipInvalidChar(); 1504 } 1505 std::string name = ParseName(); 1506 SkipInvalidChar(); 1507 int quote = PriorDealChar(); 1508 std::string entityValue; 1509 if (quote == '"' || quote == '\'') { 1510 position_++; 1511 entityValue = ParseTagValue(static_cast<char>(quote), true, false, TextEnum::ENTITY_DECL); 1512 if (PriorDealChar() == quote) { 1513 position_++; 1514 } 1515 } else if (ParserDoctInnerInfo(true, false)) { 1516 entityValue = ""; 1517 SkipInvalidChar(); 1518 if (PriorDealChar() == tagText_.NDATA[0]) { 1519 SkipText(tagText_.NDATA); 1520 SkipInvalidChar(); 1521 ParseName(); 1522 } 1523 } else { 1524 xmlPullParserError_ = "Expected entity value or external ID"; 1525 } 1526 if (generalEntity && bDocDecl) { 1527 documentEntities[name] = entityValue; 1528 } 1529 SkipInvalidChar(); 1530 SkipChar('>'); 1531 } 1532 ParseInneNotaDecl()1533 void XmlPullParser::ParseInneNotaDecl() 1534 { 1535 SkipText(tagText_.START_NOTATION); 1536 SkipInvalidChar(); 1537 ParseName(); 1538 if (!ParserDoctInnerInfo(false, false)) { 1539 xmlPullParserError_ = "Expected external ID or public ID for notation "; 1540 } 1541 SkipInvalidChar(); 1542 SkipChar('>'); 1543 } 1544 ReadInternalSubset()1545 void XmlPullParser::ReadInternalSubset() 1546 { 1547 SkipChar('['); 1548 while (true) { 1549 SkipInvalidChar(); 1550 if (PriorDealChar() == ']') { 1551 position_++; 1552 return; 1553 } 1554 TagEnum declarationType = ParseTagType(true); 1555 switch (declarationType) { 1556 case TagEnum::ELEMENTDECL: 1557 ParseInnerEleDec(); 1558 break; 1559 case TagEnum::ATTLISTDECL: 1560 ParseInnerAttriDecl(); 1561 break; 1562 case TagEnum::ENTITYDECL: 1563 ParseEntityDecl(); 1564 break; 1565 case TagEnum::NOTATIONDECL: 1566 ParseInneNotaDecl(); 1567 break; 1568 case TagEnum::INSTRUCTION: 1569 SkipText(tagText_.START_PROCESSING_INSTRUCTION); 1570 ParseDelimiterInfo(tagText_.END_PROCESSING_INSTRUCTION, false); 1571 break; 1572 case TagEnum::COMMENT: 1573 ParseComment(false); 1574 break; 1575 case TagEnum::PARAMETER_ENTITY_REF: 1576 xmlPullParserError_ = "Parameter entity references are not supported "; 1577 break; 1578 default: 1579 xmlPullParserError_ = "Unexpected token"; 1580 break; 1581 } 1582 } 1583 } 1584 ParseDoctype(bool saveDtdText)1585 void XmlPullParser::ParseDoctype(bool saveDtdText) 1586 { 1587 SkipText(tagText_.START_DOCTYPE); 1588 size_t startPosition = 0; 1589 if (saveDtdText) { 1590 keyInfo_ = ""; 1591 startPosition = position_; 1592 } 1593 SkipInvalidChar(); 1594 ParseName(); 1595 ParserDoctInnerInfo(true, true); 1596 SkipInvalidChar(); 1597 if (PriorDealChar() == '[') { 1598 ReadInternalSubset(); 1599 } 1600 SkipInvalidChar(); 1601 if (saveDtdText) { 1602 keyInfo_.append(strXml_, 0, position_); 1603 keyInfo_ = keyInfo_.substr(startPosition); 1604 text_ = keyInfo_; 1605 keyInfo_ = ""; 1606 } 1607 SkipChar('>'); 1608 } 1609 ParseText()1610 void XmlPullParser::ParseText() 1611 { 1612 text_ = ParseTagValue('<', true, false, TextEnum::TEXT); 1613 std::string strTemp = text_; 1614 Replace(strTemp, "\r", ""); 1615 Replace(strTemp, "\n", ""); 1616 Replace(strTemp, " ", ""); 1617 if ((depth == 0 && bWhitespace_) || strTemp.size() == 0) { 1618 type = TagEnum::WHITESPACE; 1619 } 1620 } 1621 ParseCdect()1622 void XmlPullParser::ParseCdect() 1623 { 1624 SkipText(tagText_.START_CDATA); 1625 text_ = ParseDelimiterInfo(tagText_.END_CDATA, true); 1626 } 1627 ParseOneTagFunc()1628 TagEnum XmlPullParser::ParseOneTagFunc() 1629 { 1630 switch (type) { 1631 case TagEnum::START_DOCUMENT: 1632 return type; 1633 case TagEnum::START_TAG: { 1634 if (ParseStartTag(false, false) == TagEnum::ERROR) { 1635 return TagEnum::ERROR; 1636 } 1637 return type;} 1638 case TagEnum::END_TAG: { 1639 if (ParseEndTag()) { 1640 return type; 1641 } 1642 return TagEnum::ERROR;} 1643 case TagEnum::END_DOCUMENT: 1644 return type; 1645 case TagEnum::ENTITY_REFERENCE: { 1646 std::string entityTextBuilder; 1647 ParseEntity(entityTextBuilder, true, false, TextEnum::TEXT); 1648 text_ = entityTextBuilder; 1649 return TagEnum::OK; 1650 } 1651 case TagEnum::TEXT: 1652 ParseText(); 1653 return TagEnum::OK; 1654 case TagEnum::CDSECT: 1655 ParseCdect(); 1656 return TagEnum::OK; 1657 case TagEnum::COMMENT: 1658 ParseComment(true); 1659 return TagEnum::OK; 1660 case TagEnum::INSTRUCTION: 1661 ParseInstruction(); 1662 return TagEnum::OK; 1663 case TagEnum::DOCDECL: 1664 ParseDoctype(true); 1665 return TagEnum::OK; 1666 default: 1667 xmlPullParserError_ = "Unexpected token"; 1668 return TagEnum::ERROR; 1669 } 1670 } 1671 ParseOneTag()1672 TagEnum XmlPullParser::ParseOneTag() 1673 { 1674 if (type == TagEnum::END_TAG) { 1675 depth--; 1676 } 1677 if (bEndFlag_) { 1678 bEndFlag_ = false; 1679 type = TagEnum::END_TAG; 1680 return type; 1681 } 1682 ParserPriorDeal(); 1683 while (true) { 1684 TagEnum typeTem = ParseOneTagFunc(); 1685 if (typeTem != TagEnum::OK) { 1686 return typeTem; 1687 } 1688 if (depth == 0 && (type == TagEnum::ENTITY_REFERENCE || type == TagEnum::TEXT || type == TagEnum::CDSECT)) { 1689 std::string errMsg = ""; 1690 if (!text_.empty()) { 1691 errMsg = ": " + text_; 1692 } 1693 xmlPullParserError_ = "Unexpected token" + errMsg; 1694 } 1695 if (type == TagEnum::DOCDECL && (!bDoctype_)) { 1696 ParseOneTag(); 1697 } 1698 return type; 1699 } 1700 } 1701 ParserPriorDeal()1702 void XmlPullParser::ParserPriorDeal() 1703 { 1704 type = ParseTagType(false); 1705 if (type == TagEnum::XML_DECLARATION) { 1706 ParseDeclaration(); 1707 type = ParseTagType(false); 1708 } 1709 text_ = ""; 1710 bWhitespace_ = true; 1711 prefix_ = ""; 1712 name_ = ""; 1713 namespace_ = ""; 1714 attriCount_ = 0; 1715 } 1716 ParseInstruction()1717 void XmlPullParser::ParseInstruction() 1718 { 1719 SkipText(tagText_.START_PROCESSING_INSTRUCTION); 1720 text_ = ParseDelimiterInfo(tagText_.END_PROCESSING_INSTRUCTION, true); 1721 } 1722 GetColumnNumber() const1723 int XmlPullParser::GetColumnNumber() const 1724 { 1725 size_t result = 0; 1726 for (size_t i = 0; i < position_; i++) { 1727 if (strXml_[i] == '\n') { 1728 result = 0; 1729 } else { 1730 result++; 1731 } 1732 } 1733 return result + 1; 1734 } 1735 GetDepth() const1736 int XmlPullParser::GetDepth() const 1737 { 1738 return depth; 1739 } 1740 GetLineNumber() const1741 int XmlPullParser::GetLineNumber() const 1742 { 1743 int result = bufferStartLine_; 1744 for (size_t i = 0; i < position_; i++) { 1745 if (strXml_[i] == '\n') { 1746 result++; 1747 } 1748 } 1749 return result + 1; 1750 } 1751 GetName() const1752 std::string XmlPullParser::GetName() const 1753 { 1754 return name_; 1755 } 1756 GetPrefix() const1757 std::string XmlPullParser::GetPrefix() const 1758 { 1759 return prefix_; 1760 } 1761 GetText() const1762 std::string XmlPullParser::GetText() const 1763 { 1764 if (type < TagEnum::TEXT || (type == TagEnum::ENTITY_REFERENCE && bUnresolved_)) { 1765 return ""; 1766 } else { 1767 return text_; 1768 } 1769 } 1770 IsEmptyElementTag() const1771 bool XmlPullParser::IsEmptyElementTag() const 1772 { 1773 return bEndFlag_; 1774 } 1775 GetAttributeCount() const1776 int XmlPullParser::GetAttributeCount() const 1777 { 1778 return attriCount_; 1779 } 1780 IsWhitespace() const1781 bool XmlPullParser::IsWhitespace() const 1782 { 1783 return bWhitespace_; 1784 } 1785 GetNamespace() const1786 std::string XmlPullParser::GetNamespace() const 1787 { 1788 return namespace_; 1789 } 1790 GetColumnNumber(napi_env env,napi_callback_info info)1791 napi_value XmlPullParser::ParseInfo::GetColumnNumber(napi_env env, napi_callback_info info) 1792 { 1793 napi_value thisVar = nullptr; 1794 napi_value mainVar = nullptr; 1795 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1796 void *obj = nullptr; 1797 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1798 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1799 napi_value result = nullptr; 1800 if (obj != nullptr) { 1801 int temp = (reinterpret_cast<XmlPullParser *>(obj))->GetColumnNumber(); 1802 napi_create_int32(env, temp, &result); 1803 } 1804 return result; 1805 } 1806 GetDepth(napi_env env,napi_callback_info info)1807 napi_value XmlPullParser::ParseInfo::GetDepth(napi_env env, napi_callback_info info) 1808 { 1809 napi_value thisVar = nullptr; 1810 napi_value mainVar = nullptr; 1811 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1812 void *obj = nullptr; 1813 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1814 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1815 napi_value result = nullptr; 1816 if (obj != nullptr) { 1817 int temp = (reinterpret_cast<XmlPullParser *>(obj))->GetDepth(); 1818 napi_create_int32(env, temp, &result); 1819 } 1820 return result; 1821 } 1822 GetLineNumber(napi_env env,napi_callback_info info)1823 napi_value XmlPullParser::ParseInfo::GetLineNumber(napi_env env, napi_callback_info info) 1824 { 1825 napi_value thisVar = nullptr; 1826 napi_value mainVar = nullptr; 1827 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1828 void *obj = nullptr; 1829 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1830 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1831 napi_value result = nullptr; 1832 if (obj != nullptr) { 1833 int temp = (reinterpret_cast<XmlPullParser *>(obj))->GetLineNumber(); 1834 napi_create_int32(env, temp, &result); 1835 } 1836 return result; 1837 } 1838 GetName(napi_env env,napi_callback_info info)1839 napi_value XmlPullParser::ParseInfo::GetName(napi_env env, napi_callback_info info) 1840 { 1841 napi_value thisVar = nullptr; 1842 napi_value mainVar = nullptr; 1843 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1844 void *obj = nullptr; 1845 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1846 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1847 napi_value result = nullptr; 1848 if (obj != nullptr) { 1849 std::string temp = (reinterpret_cast<XmlPullParser *>(obj))->GetName(); 1850 napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); 1851 } 1852 return result; 1853 } 1854 GetNamespace(napi_env env,napi_callback_info info)1855 napi_value XmlPullParser::ParseInfo::GetNamespace(napi_env env, napi_callback_info info) 1856 { 1857 napi_value thisVar = nullptr; 1858 napi_value mainVar = nullptr; 1859 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1860 void *obj = nullptr; 1861 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1862 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1863 napi_value result = nullptr; 1864 if (obj != nullptr) { 1865 std::string temp = (reinterpret_cast<XmlPullParser *>(obj))->GetNamespace(); 1866 napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); 1867 } 1868 return result; 1869 } 1870 GetPrefix(napi_env env,napi_callback_info info)1871 napi_value XmlPullParser::ParseInfo::GetPrefix(napi_env env, napi_callback_info info) 1872 { 1873 napi_value thisVar = nullptr; 1874 napi_value mainVar = nullptr; 1875 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1876 void *obj = nullptr; 1877 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1878 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1879 napi_value result = nullptr; 1880 if (obj != nullptr) { 1881 std::string temp = (reinterpret_cast<XmlPullParser *>(obj))->GetPrefix(); 1882 napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); 1883 } 1884 return result; 1885 } 1886 GetText(napi_env env,napi_callback_info info)1887 napi_value XmlPullParser::ParseInfo::GetText(napi_env env, napi_callback_info info) 1888 { 1889 napi_value thisVar = nullptr; 1890 napi_value mainVar = nullptr; 1891 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1892 void *obj = nullptr; 1893 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1894 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1895 napi_value result = nullptr; 1896 if (obj != nullptr) { 1897 std::string temp = (reinterpret_cast<XmlPullParser *>(obj))->GetText(); 1898 napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); 1899 } 1900 return result; 1901 } 1902 IsEmptyElementTag(napi_env env,napi_callback_info info)1903 napi_value XmlPullParser::ParseInfo::IsEmptyElementTag(napi_env env, napi_callback_info info) 1904 { 1905 napi_value thisVar = nullptr; 1906 napi_value mainVar = nullptr; 1907 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1908 void *obj = nullptr; 1909 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1910 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1911 napi_value result = nullptr; 1912 if (obj != nullptr) { 1913 bool temp = (reinterpret_cast<XmlPullParser *>(obj))->IsEmptyElementTag(); 1914 napi_get_boolean(env, temp, &result); 1915 } 1916 return result; 1917 } 1918 IsWhitespace(napi_env env,napi_callback_info info)1919 napi_value XmlPullParser::ParseInfo::IsWhitespace(napi_env env, napi_callback_info info) 1920 { 1921 napi_value thisVar = nullptr; 1922 napi_value mainVar = nullptr; 1923 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1924 void *obj = nullptr; 1925 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1926 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1927 napi_value result = nullptr; 1928 if (obj != nullptr) { 1929 bool temp = (reinterpret_cast<XmlPullParser *>(obj))->IsWhitespace(); 1930 napi_get_boolean(env, temp, &result); 1931 } 1932 return result; 1933 } 1934 GetAttributeCount(napi_env env,napi_callback_info info)1935 napi_value XmlPullParser::ParseInfo::GetAttributeCount(napi_env env, napi_callback_info info) 1936 { 1937 napi_value thisVar = nullptr; 1938 napi_value mainVar = nullptr; 1939 NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); 1940 void *obj = nullptr; 1941 napi_get_named_property(env, thisVar, "MainInfo", &mainVar); 1942 NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); 1943 napi_value result = nullptr; 1944 if (obj != nullptr) { 1945 int temp = (reinterpret_cast<XmlPullParser *>(obj))->GetAttributeCount(); 1946 napi_create_int32(env, temp, &result); 1947 } 1948 return result; 1949 } 1950 } // namespace OHOS::Xml 1951 1952