/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "js_xml.h" #include "securec.h" namespace OHOS::xml { XmlSerializer::XmlSerializer(napi_env env, char *pStart, size_t bufferLength, std::string encoding) { env_ = env; encoding_ = encoding; pStart_ = pStart; iLength_ = bufferLength; } napi_status XmlSerializer::DealNapiStrValue(napi_env env, const napi_value napi_StrValue, std::string &result) { char *buffer = nullptr; size_t bufferSize = 0; napi_status status = napi_ok; status = napi_get_value_string_utf8(env, napi_StrValue, nullptr, -1, &bufferSize); if (status != napi_ok) { return status; } if (bufferSize > 0) { buffer = new char[bufferSize + 1]; napi_get_value_string_utf8(env, napi_StrValue, buffer, bufferSize + 1, &bufferSize); } if (buffer != nullptr) { result = buffer; delete []buffer; buffer = nullptr; } return status; } void XmlSerializer::SplicNsp() { elementStack[depth_ * 3] = elementStack[(depth_ - 1) * 3]; // 3: number of args elementStack[depth_ * 3 + 1] = elementStack[(depth_ - 1) * 3 + 1]; // 3: number of args if (multNsp[depth_ - 1].size() == 0) { return; } if (type == "isAttri" || type == "isStart") { for (int i = 0; i< CurNspNum; ++i) { out_.append(" xmlns:"); out_.append(multNsp[depth_ - 1][i * 2]); // 2: number of args out_.append("=\""); out_.append(multNsp[depth_ - 1][i * 2 + 1]); // 2: number of args out_.append("\""); } multNsp[depth_ - 1].clear(); CurNspNum = 0; } } void XmlSerializer::NextItem() { out_.append("\r\n"); for (int i = 0; i < depth_; i++) { out_.append(" "); } } std::string Replace(std::string str, std::string str1, std::string str2) { size_t iPos = 0; while ((iPos = str.find(str1)) != std::string::npos) { str = str.substr(0, iPos) + str2 + str.substr(iPos + str1.size()); } return str; } void XmlSerializer::SetDeclaration() { out_ = ""; out_.append(""); type = "isDecl"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::SetNamespace(std::string prefix, std::string ns_Temp) { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(">"); } elementStack[depth_ * 3] = prefix; // 3: number of args elementStack[depth_ * 3 + 1] = ns_Temp; // 3: number of args multNsp[depth_][CurNspNum*2] = elementStack[depth_ * 3]; // 3: number of args 2: number of args multNsp[depth_][CurNspNum * 2 + 1] = elementStack[depth_ * 3 + 1]; // 3: number of args 2: number of args ++CurNspNum; type = "isNsp"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::StartElement(std::string name) { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(">"); } if (type != "" && type != "isDecl") { NextItem(); } elementStack[depth_*3 + 2] = name; // 3: number of args 2: number of args out_.append("<"); if (elementStack[depth_ * 3] != "") { // 3: number of args out_.append(elementStack[depth_ * 3]); // 3: number of args out_.append(":"); } else if (depth_ != 0) { if (elementStack[(depth_ - 1) * 3] != "") { // 3: number of args elementStack[depth_ * 3] = elementStack[(depth_ - 1) * 3]; // 3: number of args out_.append(elementStack[depth_ * 3]); // 3: number of args out_.append(":"); } } out_.append(elementStack[depth_ * 3 + 2]); // 3: number of args 2: number of args type = "isStart"; ++depth_; elementStack.push_back(""); elementStack.push_back(""); elementStack.push_back(""); size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::SetAttributes(std::string name, std::string value) { out_ = ""; if (type != "isStart" && type != "isAttri") { xmlSerializerError_ = "illegal position for attribute"; } out_.append(" "); out_.append(name); out_.append("=\""); WriteEscaped(value); out_.append("\""); type = "isAttri"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::EndElement() { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(" />"); type = "isEndTag"; --depth_; return; } --depth_; if (type != "isText") { NextItem(); } out_.append(""); size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::AddEmptyElement(std::string name) { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(">"); } if (type != "") { NextItem(); } out_.append("<"); out_.append(name); out_.append("/>"); type = "isAddEmpElem"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::SetText(std::string text) { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(">"); } WriteEscaped(text); type = "isText"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::SetCommnet(std::string comment) { out_ = ""; if (type == "isStart" || type =="isAttri") { SplicNsp(); out_.append(">"); } NextItem(); out_ += ""; type = "isCom"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::SetCData(std::string data) { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(">"); } NextItem(); data = Replace(data, "]]>", "]]]]>"); out_ += ""; type = "isCData"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::SetDocType(std::string text) { out_ = ""; if (type == "isStart" || type == "isAttri") { SplicNsp(); out_.append(">"); } NextItem(); out_ += ""; type = "isDocType"; size_t iLenTemp = out_.length(); if (iLength_ > iPos_ + iLenTemp - 1) { if (!memcpy_s(pStart_ + iPos_, iLength_ - iPos_, out_.c_str(), iLenTemp)) { iPos_ += iLenTemp; } } } void XmlSerializer::WriteEscaped(std::string s) { int len = s.length(); for (int i = 0; i < len; i++) { char c = s[i]; switch (c) { case '\'': out_.append("'"); break; case '\"': out_.append("""); break; case '&': out_.append("&"); break; case '>': out_.append(">"); break; case '<': out_.append("<"); break; default: out_ += c; } } } std::string XmlSerializer::XmlSerializerError() { return xmlSerializerError_; } napi_value XmlPullParser::DealOptionInfo(napi_value napiObj, napi_callback_info info) { std::vector vctOptions = {"supportDoctype", "ignoreNameSpace", "tagValueCallbackFunction", "attributeValueCallbackFunction", "tokenValueCallbackFunction"}; size_t vctLength = vctOptions.size(); for (size_t i = 0; i < vctLength; ++i) { napi_value recvTemp = nullptr; bool bRecv = false; napi_get_named_property(env_, napiObj, vctOptions[i].c_str(), &recvTemp); napi_valuetype valuetype; NAPI_CALL(env_, napi_typeof(env_, recvTemp, &valuetype)); if (valuetype == napi_boolean && (napi_get_value_bool(env_, recvTemp, &bRecv)) == napi_ok) { switch (i) { case 0: // 0:supportDoctype bDoctype_ = bRecv; break; case 1: // 1:ignoreNameSpace bIgnoreNS_ = bRecv; break; default: break; } } else if (valuetype == napi_function) { NAPI_ASSERT(env_, recvTemp != nullptr, "Parameter is empty."); switch (i) { case 2: // 2:tagValueCallbackFunction tagFunc_ = recvTemp; break; case 3: // 3:attributeValueCallbackFunction attrFunc_ = recvTemp; break; case 4: // 4:tokenValueCallbackFunction tokenFunc_ = recvTemp; break; default: break; } } } return nullptr; } void XmlPullParser::PushSrcLinkList(std::string strBuffer) { SrcLinkList* pNew = new SrcLinkList; srcLinkList_->next = pNew; pNew->strBuffer = strBuffer; pNew->position = 0; pNew->max = strBuffer.size(); srcLinkList_ = pNew; } void XmlPullParser::PopSrcLinkList() { SrcLinkList* pTemp = srcLinkList_; srcLinkList_ = srcLinkList_->next; if (pTemp != nullptr) { delete pTemp; pTemp = nullptr; } } bool XmlPullParser::DealLength(int minimun) { while (srcLinkList_->next != nullptr) { if (position_ < max_) { xmlPullParserError_ = "Unbalanced entity!"; } PopSrcLinkList(); if (max_ - position_ >= minimun) { return true; } } for (int i = 0; i < position_; i++) { if (strXml_[i] == '\n') { bufferStartLine_++; bufferStartColumn_ = 0; } else { bufferStartColumn_++; } } if (keyInfo_ != "") { keyInfo_.append(strXml_, 0, position_); } if (max_ != position_) { max_ -= position_; for (size_t i = 0; i < max_; ++i) { strXml_[i] = strXml_[position_ + i]; } } else { max_ = 0; } if (position_ != strXml_.size()) { position_ = 0; } if (strXml_.size() - max_ > 0 && position_ == 0) { max_ += strXml_.size() - max_; if (max_ >= minimun) { return true; } } return false; } int XmlPullParser::GetNSCount(int iTemp) { if (iTemp > depth) { xmlPullParserError_ = " IndexOutOfBoundsException"; } return nspCounts_[depth]; } std::string XmlPullParser::XmlPullParserError() { return xmlPullParserError_; } bool XmlPullParser::ParseToken(napi_value thisVar) { napi_value returnVal = nullptr; size_t argc = 2; // 2: number of args napi_value key = nullptr; napi_create_int32(env_, (int)type, &key); napi_value parseInfo = nullptr; napi_create_object(env_, &parseInfo); auto object = new ParseInfo(); napi_wrap(env_, parseInfo, object, nullptr, nullptr, nullptr); static napi_property_descriptor XmlDesc[] = { DECLARE_NAPI_FUNCTION("getDepth", XmlPullParser::ParseInfo::GetDepth), DECLARE_NAPI_FUNCTION("getColumnNumber", XmlPullParser::ParseInfo::GetColumnNumber), DECLARE_NAPI_FUNCTION("getLineNumber", XmlPullParser::ParseInfo::GetLineNumber), DECLARE_NAPI_FUNCTION("getAttributeCount", XmlPullParser::ParseInfo::GetAttributeCount), DECLARE_NAPI_FUNCTION("getName", XmlPullParser::ParseInfo::GetName), DECLARE_NAPI_FUNCTION("getNamespace", XmlPullParser::ParseInfo::GetNamespace), DECLARE_NAPI_FUNCTION("getPrefix", XmlPullParser::ParseInfo::GetPrefix), DECLARE_NAPI_FUNCTION("getText", XmlPullParser::ParseInfo::GetText), DECLARE_NAPI_FUNCTION("isEmptyElementTag", XmlPullParser::ParseInfo::IsEmptyElementTag), DECLARE_NAPI_FUNCTION("isWhitespace", XmlPullParser::ParseInfo::IsWhitespace) }; napi_define_properties(env_, parseInfo, sizeof(XmlDesc) / sizeof(XmlDesc[0]), XmlDesc); napi_set_named_property(env_, parseInfo, "MainInfo", thisVar); napi_value argv[2] = {key, parseInfo}; // 2: number of args napi_call_function(env_, parseInfo, tokenFunc_, argc, argv, &returnVal); bool bRec = false; napi_get_value_bool(env_, returnVal, &bRec); return bRec; } bool XmlPullParser::ParseAttri(napi_value thisVar) { for (size_t i = 0 ; i< attriCount_ ; ++i) { napi_value returnVal = nullptr; size_t argc = 3; // 3: number of args napi_value global = nullptr; napi_get_global(env_, &global); napi_value key = nullptr; napi_create_string_utf8(env_, attributes[i * 4 + 2].c_str(), // 4 and 2: number of args attributes[i * 4 + 2].size(), &key); // 4 and 2: number of args napi_value value = nullptr; napi_create_string_utf8(env_, attributes[i * 4 + 3].c_str(), // 4 and 2: number of args attributes[i * 4 + 3].size(), &value); // 3 and 4: number of args napi_value argv[3] = {key, value, thisVar}; napi_call_function(env_, global, attrFunc_, argc, argv, &returnVal); bool bRec = false; napi_get_value_bool(env_, returnVal, &bRec); return bRec; } return true; } void XmlPullParser::Parse(napi_value thisVar) { if (tagFunc_ || attrFunc_ || tokenFunc_) { while (type != TagEnum::END_DOCUMENT) { ParseOneTag(); bool bRec = false; if (tagFunc_ && type == TagEnum::START_TAG) { napi_value returnVal = nullptr; size_t argc = 3; // 3: number of args napi_value global = nullptr; napi_get_global(env_, &global); napi_value key = nullptr; napi_create_string_utf8(env_, name_.c_str(), name_.size(), &key); napi_value value = nullptr; napi_create_string_utf8(env_, text_.c_str(), text_.size(), &value); napi_value argv[3] = {key, value, thisVar}; napi_call_function(env_, global, tagFunc_, argc, argv, &returnVal); napi_get_value_bool(env_, returnVal, &bRec); } if (tagFunc_ && type == TagEnum::START_TAG && !bRec) { break; } if (attrFunc_ && attriCount_) { bRec = ParseAttri(thisVar); } if (attrFunc_ && attriCount_ && !bRec) { break; } if (tokenFunc_) { bRec = ParseToken(thisVar); } if (tokenFunc_ && !bRec) { break; } } } } TagEnum XmlPullParser::ParseTagTypeFunc() { switch (strXml_[position_ + 2]) { // 2: number of args case 'D': return TagEnum::DOCDECL; case '[': return TagEnum::CDSECT; case '-': return TagEnum::COMMENT; case 'E': switch (strXml_[position_ + 3]) { // 3: number of args case 'L': return TagEnum::ELEMENTDECL; case 'N': return TagEnum::ENTITYDECL; } xmlPullParserError_ = "Unexpected = max_ && !DealLength(1)) { return TagEnum::END_DOCUMENT; } switch (strXml_[position_]) { case '&': return TagEnum::ENTITY_REFERENCE; case '<': if (position_ + 3 >= max_ && !DealLength(4)) { // 4: number of args 3: number of args xmlPullParserError_ = ("Dangling <"); } switch (strXml_[position_ + 1]) { case '/': return TagEnum::END_TAG; case '?': if ((position_ + 5 < max_ || DealLength(6)) // 5: number of args 6: number of args && (strXml_[position_ + 2] == 'x' || strXml_[position_ + 2] == 'X') // 2: number of args && (strXml_[position_ + 3] == 'm' || strXml_[position_ + 3] == 'M') // 3: number of args && (strXml_[position_ + 4] == 'l' || strXml_[position_ + 4] == 'L') // 4: number of args && (strXml_[position_ + 5] == ' ')) { // 5: number of args return TagEnum::XML_DECLARATION; } else { return TagEnum::INSTRUCTION; } case '!': return ParseTagTypeFunc(); default: return TagEnum::START_TAG; } case '%': return inDeclaration ? TagEnum::PARAMETER_ENTITY_REF : TagEnum::TEXT; default: return TagEnum::TEXT; } } void XmlPullParser::SkipText(std::string chars) { if (position_ + chars.size() > max_ && !DealLength(chars.size())) { xmlPullParserError_ = "expected: '" + chars + "' but was EOF"; return; } int len = chars.length(); if (strXml_.substr(position_, len) != chars) { xmlPullParserError_ = "expected: \"" + chars + "\" but was \"" + strXml_.substr(position_, len) + "...\""; } position_ += len; } int XmlPullParser::PriorDealChar() { if (position_ < max_ || DealLength(1)) { return strXml_[position_]; } return -1; } void XmlPullParser::SkipChar(char expected) { int c = PriorDealChar(); if (c != expected) { xmlPullParserError_ = "expected:"; if (c == -1) { return; } } position_++; } std::string XmlPullParser::ParseName() { if (position_ >= max_ && !DealLength(1)) { xmlPullParserError_ = "name expected"; return ""; } int start = position_; std::string result = ""; char c = strXml_[position_]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == ':' || relaxed) { position_++; } else { xmlPullParserError_ = "name expected"; return ""; } while (true) { if (position_ >= max_) { result.append(strXml_, start, position_ - start); if (!DealLength(1)) { return result; } start = position_; } c = strXml_[position_]; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-' || c == ':' || c == '.') { position_++; continue; } if (result == "") { result.append(strXml_, start, position_ - start); return result; } else { result.append(strXml_, start, position_ - start); return result; } } } void XmlPullParser::SkipInvalidChar() { while (position_ < max_ || DealLength(1)) { int c = strXml_[position_]; if (c > ' ') { break; } position_++; } } void XmlPullParser::ParseEntityFunc(int start, std::string &out, bool isEntityToken, TextEnum textEnum) { std::string strEntity = out.substr(start + 1, out.length() - 1); if (isEntityToken) { name_ = strEntity; } if (strEntity.size() && strEntity[0] == '#') { int c = 0; if (strEntity.size()>=2 && strEntity[1] == 'x') { // 2: number of args c = std::stoi(strEntity.substr(2), nullptr, 16); // 16: number of args 2: number of args } else { c = std::stoi(strEntity.substr(1), nullptr); } out = ""; out += static_cast(c); bUnresolved_ = false; return; } if (textEnum == TextEnum::ENTITY_DECL) { return; } if (DEFAULT_ENTITIES.count(strEntity) != 0) { out = ""; bUnresolved_ = false; out.append(strEntity); return; } std::string resolved = " "; if (documentEntities.size() != 0 && (resolved = strEntity) != "") { out = ""; bUnresolved_ = false; if (bDocDecl) { PushSrcLinkList(resolved); } else { out.append(resolved); } return; } if (sysInfo_ != "") { out = ""; return; } bUnresolved_ = true; } void XmlPullParser::ParseEntity(std::string &out, bool isEntityToken, bool throwOnResolveFailure, TextEnum textEnum) { int start = out.length(); if (strXml_[position_++] != '&') { xmlPullParserError_ = "Should not be reached"; } out += '&'; while (true) { int c = PriorDealChar(); if (c == ';') { out += ';'; position_++; break; } else if (c >= 128 // 128: number of args || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || c == '-' || c == '#') { position_++; out.push_back(static_cast(c)); } else if (relaxed) { return; } else { xmlPullParserError_ = "unterminated entity ref"; } } ParseEntityFunc(start, out, isEntityToken, textEnum); } bool XmlPullParser::ParseTagValueFunc(char c, bool throwOnResolveFailure, TextEnum textEnum, int &start, std::string& result) { if (c == '\r') { if ((position_ + 1 < max_ || DealLength(2)) && strXml_[position_ + 1] == '\n') { // 2: number of args position_++; } c = (textEnum == TextEnum::ATTRI) ? ' ' : '\n'; } else if (c == '\n') { c = ' '; } else if (c == '&') { bWhitespace_ = false; ParseEntity(result, false, throwOnResolveFailure, textEnum); start = position_; return false; } else if (c == '<') { if (textEnum == TextEnum::ATTRI) { xmlPullParserError_ = "Illegal: \"<\" inside attribute value"; } bWhitespace_ = false; } else if (c == ']') { if ((position_ + 2 < max_ || DealLength(3)) // 2: number of args 3: number of args && strXml_[position_ + 1] == ']' && strXml_[position_ + 2] == '>') { // 2: number of args xmlPullParserError_ = "Illegal: \"]]>\" outside CDATA section"; } bWhitespace_ = false; } else if (c == '%') { xmlPullParserError_ = "This parser doesn't support parameter entities"; } else { xmlPullParserError_ = "AssertionError"; } return true; } std::string XmlPullParser::ParseTagValue(char delimiter, bool resolveEntities, bool throwOnResolveFailure, TextEnum textEnum) { int start = position_; std::string result = " "; if (textEnum == TextEnum::TEXT && text_ != "") { result.append(text_); } while (true) { if (position_ >= max_) { if (start < position_) { result.append(strXml_, start, position_ - start); } if (!DealLength(1)) { return result != "" ? result : ""; } start = position_; } char c = strXml_[position_]; if (c == delimiter || (delimiter == ' ' && (c <= ' ' || c == '>')) || (c == '&' && !resolveEntities)) { break; } if (c != '\r' && (c != '\n' || textEnum != TextEnum::ATTRI) && c != '&' && c != '<' && (c != ']' || textEnum != TextEnum::TEXT) && (c != '%' || textEnum != TextEnum::ENTITY_DECL)) { bWhitespace_ &= (c <= ' '); position_++; continue; } result.append(strXml_, start, position_ - start); if(!ParseTagValueFunc(c, throwOnResolveFailure, textEnum, start, result)) { continue; } position_++; result = result + c; start = position_; } result.append(strXml_, start, position_ - start); return result; } std::string XmlPullParser::GetNamespace(std::string prefix) { if (prefix == "xml") { return "http://www.w3.org/XML/1998/namespace"; } if (prefix == "xmlns") { return "http://www.w3.org/2000/xmlns/"; } for (int i = (GetNSCount(depth) << 1) - 2; i >= 0; i -= 2) { // 2: number of args if (prefix == "") { if (nspStack_[i] == "") { return nspStack_[i + 1]; } } else if (prefix == nspStack_[i]) { return nspStack_[i + 1]; } } return ""; } void XmlPullParser::Replace(std::string& strTemp, std::string strSrc, std::string strDes) { size_t iPos = 0; while ((iPos = strTemp.find(strSrc)) != std::string::npos) { strTemp.replace(iPos, strSrc.size(), strDes); } } void XmlPullParser::ParseNspFunc(int &i, std::string &attrName, bool &any) { int j = (nspCounts_[depth]++) << 1; size_t ui_size = nspStack_.size(); if (ui_size < j + 2) { // 2: number of args nspStack_.resize(j + 16); // 16: number of args } nspStack_[j] = attrName; nspStack_[j + 1] = attributes[i + 3]; // 3: number of args if (attrName != "" && attributes[i + 3].empty()) { // 3: number of args xmlPullParserError_ = "illegal empty namespace"; } if (bKeepNsAttri) { attributes[i] = "http://www.w3.org/2000/xmlns/"; any = true; } else { for (size_t iCount = i; iCount < ((--attriCount_) << 2); ++iCount) { // 2: number of args attributes[iCount] = attributes[iCount + 4]; // 4: number of args } i -= 4; // 4: } } void XmlPullParser::ParseNspFunc_() { for (int i = (attriCount_ << 2) - 4; i >= 0; i -= 4) { // 4: number of args 2: number of args std::string attrName = attributes[i + 2]; // 2: number of args int cut = attrName.find(':'); if (cut == 0 && !relaxed) { xmlPullParserError_ = "illegal attribute name: "; } else if (cut != -1) { std::string attrPrefix = attrName.substr(0, cut); attrName = attrName.substr(cut + 1); std::string attrNs = GetNamespace(attrPrefix); if (attrNs == "" && !relaxed) { xmlPullParserError_ = ("Undefined Prefix: " + attrPrefix + " in "); } attributes[i] = attrNs; attributes[i + 1] = attrPrefix; attributes[i + 2] = attrName; // 2: number of args } } } bool XmlPullParser::ParseNsp() { bool any = false; for (int i = 0; i < (attriCount_ << 2); i += 4) { // 2 and 4: number of args std::string attrName = attributes[i + 2]; // 2: number of args int cut = attrName.find(':'); std::string prefix; if (cut != -1) { prefix = attrName.substr(0, cut); attrName = attrName.substr(cut + 1); } else if (attrName == ("xmlns")) { prefix = attrName; attrName = ""; } else { continue; } if (!(prefix == "xmlns")) { any = true; } else { ParseNspFunc(i, attrName, any); } } if (any) { ParseNspFunc_(); } int cut = name_.find(':'); if (cut == 0) { xmlPullParserError_ = "illegal tag name: " + name_; } if (cut != -1) { prefix_ = name_.substr(0, cut); name_ = name_.substr(cut + 1); } namespace_ = GetNamespace(prefix_); if (namespace_ == "") { namespace_ = ""; } return any; } bool XmlPullParser::ParseStartTagFuncDeal(bool throwOnResolveFailure) { std::string attrName = ParseName(); int i = (attriCount_++) * 4; // 4: number of args attributes.resize(attributes.size() + 4); // 4: number of args attributes[i] = ""; attributes[i + 1] = ""; attributes[i + 2] = attrName; // 2: number of args SkipInvalidChar(); if (position_ >= max_ && !DealLength(1)) { xmlPullParserError_ = "UNEXPECTED_EOF"; return false; } if (strXml_[position_] == '=') { position_++; SkipInvalidChar(); if (position_ >= max_) { xmlPullParserError_ = "UNEXPECTED_EOF"; return false; } char delimiter = strXml_[position_]; if (delimiter == '\'' || delimiter == '"') { position_++; } else if (relaxed) { delimiter = ' '; } else { xmlPullParserError_ = "attr value delimiter missing!"; } attributes[i + 3] = ParseTagValue(delimiter, true, // 3: number of args throwOnResolveFailure, TextEnum::ATTRI); // 3: number of args if (delimiter != ' ' && PriorDealChar() == delimiter) { position_++; } } else if (relaxed) { attributes[i + 3] = attrName; // 3: number of args } else { attributes[i + 3] = attrName; // 3: number of args } return true; } bool XmlPullParser::ParseStartTagFunc(bool xmldecl, bool throwOnResolveFailure) { while (true) { SkipInvalidChar(); if (position_ >= max_ && DealLength(1)) { xmlPullParserError_ = "UNEXPECTED_EOF"; return false; } int c = strXml_[position_]; if (xmldecl) { if (c == '?') { position_++; SkipChar('>'); return false; } } else { if (c == '/') { bEndFlag_ = true; position_++; SkipInvalidChar(); SkipChar('>'); break; } else if (c == '>') { position_++; break; } } bool bRecv = ParseStartTagFuncDeal(throwOnResolveFailure); if (!bRecv) { return false; } } return true; } void XmlPullParser::ParseStartTag(bool xmldecl, bool throwOnResolveFailure) { if (!xmldecl) { SkipChar('<'); } name_ = ParseName(); attriCount_ = 0; bool bRecv = ParseStartTagFunc(xmldecl, throwOnResolveFailure); if (!bRecv) { return; } int sp = depth++ * 4; // 4: number of args elementStack_.resize(sp + 4); // 4: number of args elementStack_[sp + 3] = name_; // 3: number of args if (depth >= nspCounts_.size()) { nspCounts_.resize(depth + 4); // 4: number of args } nspCounts_[depth] = nspCounts_[depth - 1]; if (!bIgnoreNS_) { ParseNsp(); } else { namespace_ = ""; } if (defaultAttributes.size() != 0) { std::map elementDefaultAttributes = defaultAttributes[name_]; if (elementDefaultAttributes.size() != 0) { for (std::map::iterator iter = elementDefaultAttributes.begin(); iter != elementDefaultAttributes.end(); ++iter) { } } } elementStack_[sp] = namespace_; elementStack_[sp + 1] = prefix_; elementStack_[sp + 2] = name_; // 2: number of args } void XmlPullParser::ParseDeclaration() { if (bufferStartLine_ != 0 || bufferStartColumn_ != 0 || position_ != 0) { xmlPullParserError_ = "processing instructions must not start with xml"; } SkipText(tagText_.START_PROCESSING_INSTRUCTION); ParseStartTag(true, true); if (attriCount_ < 1 || attributes[2] != "version") { // 2: number of args xmlPullParserError_ = "version expected"; } version_ = attributes[3]; // 3: number of args int pos = 1; if (pos < attriCount_ && (attributes[2 + 4]) == "encoding") { // 4: number of args 2: number of args encoding_ = attributes[3 + 4]; // 3: number of args 4: number of args pos++; } if (pos < attriCount_ && (attributes[4 * pos + 2]) == "standalone") { // 4: number of args 2: number of args std::string st = attributes[3 + 4 * pos]; // 3: number of args 4: number of args if (st == "yes") { bAlone_ = true; } else if (st == "no") { bAlone_ = false; } else { xmlPullParserError_ = "illegal standalone value: " + st; } pos++; } if (pos != attriCount_) { xmlPullParserError_ = "unexpected attributes in XML declaration"; } bWhitespace_ = true; text_ = ""; } void XmlPullParser::ParseEndTag() { SkipChar('<'); SkipChar('/'); name_ = ParseName(); SkipInvalidChar(); SkipChar('>'); int sp = (depth - 1) * 4; // 4: number of args if (depth == 0) { xmlPullParserError_ = "read end tag " + name_ + " with no tags open"; type = TagEnum::COMMENT; return; } if (name_ == elementStack_[sp + 3]) { // 3: number of args namespace_ = elementStack_[sp]; prefix_ = elementStack_[sp + 1]; name_ = elementStack_[sp + 2]; // 2: number of args } else if (!relaxed) { xmlPullParserError_ = "expected: /" + elementStack_[sp + 3] + " read: " + name_; // 3: number of args } } std::string XmlPullParser::ParseDelimiterInfo(std::string delimiter, bool returnText) { int start = position_; std::string result = ""; if (returnText && text_ != "") { result.append(text_); } bool bFlag = true; while (bFlag) { if (position_ + (delimiter).length() > max_) { if (start < position_ && returnText) { result.append(strXml_, start, position_ - start); } if (!DealLength(delimiter.length())) { type = TagEnum::COMMENT; return ""; } start = position_; } int i = 0; for (; i < delimiter.length(); i++) { if (strXml_[position_ + i] != delimiter[i]) { position_++; break; } } if (i == delimiter.length()) { bFlag = false; } } int end = position_; position_ += delimiter.length(); if (!returnText) { return ""; } else { result.append(strXml_, start, end - start); return result; } } std::string XmlPullParser::ParseDelimiter(bool returnText) { int quote = PriorDealChar(); std::string delimiter; if (quote == '"') { delimiter = tagText_.DOUBLE_QUOTE; } else if (quote == '\'') { delimiter = tagText_.SINGLE_QUOTE; } else { xmlPullParserError_ = "Expected a quoted std::string "; } position_++; return ParseDelimiterInfo(delimiter, returnText); } bool XmlPullParser::ParserDoctInnerInfo(bool requireSystemName, bool assignFields) { SkipInvalidChar(); int c = PriorDealChar(); if (c == 'S') { SkipText(tagText_.SYSTEM); } else if (c == 'P') { SkipText(tagText_.PUBLIC); SkipInvalidChar(); if (assignFields) { pubInfo_ = ParseDelimiter(true); } else { ParseDelimiter(false); } } else { return false; } SkipInvalidChar(); if (!requireSystemName) { int delimiter = PriorDealChar(); if (delimiter != '"' && delimiter != '\'') { return true; // no system name! } } if (assignFields) { sysInfo_ = ParseDelimiter(true); } else { ParseDelimiter(false); } return true; } void XmlPullParser::ParseComment(bool returnText) { SkipText(tagText_.START_COMMENT); if (relaxed) { std::string strTemp = ParseDelimiterInfo(tagText_.END_COMMENT, returnText); if (returnText) { text_ = strTemp; } } std::string commentText = ParseDelimiterInfo(tagText_.COMMENT_DOUBLE_DASH, returnText); if (PriorDealChar() != '>') { xmlPullParserError_ = "Comments may not contain -- "; } position_++; if (returnText) { text_ = commentText; } } void XmlPullParser::ParseSpecText() { SkipInvalidChar(); int c = PriorDealChar(); if (c == '(') { int iDepth = 0; do { if (c == '(') { iDepth++; } else if (c == ')') { iDepth--; } else if (c == -1) { xmlPullParserError_ = "Unterminated element content spec "; } position_++; c = PriorDealChar(); } while (iDepth > 0); if (c == '*' || c == '?' || c == '+') { position_++; } } else if (c == tagText_.EMPTY[0]) { SkipText(tagText_.EMPTY); } else if (c == tagText_.ANY[0]) { SkipText(tagText_.ANY); } else { xmlPullParserError_ = "Expected element content spec "; } } void XmlPullParser::ParseInnerEleDec() { SkipText(tagText_.START_ELEMENT); SkipInvalidChar(); ParseName(); ParseSpecText(); SkipInvalidChar(); SkipChar('>'); } void XmlPullParser::ParseInnerAttriDeclFunc(int &c) { if (c == '(') { position_++; while (true) { SkipInvalidChar(); ParseName(); SkipInvalidChar(); c = PriorDealChar(); if (c == ')') { position_++; break; } else if (c == '|') { position_++; } else { xmlPullParserError_ = "Malformed attribute type "; } } } else { ParseName(); } } void XmlPullParser::ParseInnerAttriDecl() { SkipText(tagText_.START_ATTLIST); SkipInvalidChar(); std::string elementName = ParseName(); while (true) { SkipInvalidChar(); int c = PriorDealChar(); if (c == '>') { position_++; return; } std::string attributeName = ParseName(); SkipInvalidChar(); if (position_ + 1 >= max_ && !DealLength(2)) { // 2: lengths xmlPullParserError_ = "Malformed attribute list "; } if (strXml_[position_] == tagText_.NOTATION[0] && strXml_[position_ + 1] == tagText_.NOTATION[1]) { SkipText(tagText_.NOTATION); SkipInvalidChar(); } c = PriorDealChar(); ParseInnerAttriDeclFunc(c); SkipInvalidChar(); c = PriorDealChar(); if (c == '#') { position_++; c = PriorDealChar(); if (c == 'R') { SkipText(tagText_.REQUIRED); } else if (c == 'I') { SkipText(tagText_.IMPLIED); } else if (c == 'F') { SkipText(tagText_.FIXED); } else { xmlPullParserError_ = "Malformed attribute type"; } SkipInvalidChar(); c = PriorDealChar(); } if (c == '"' || c == '\'') { position_++; std::string value = ParseTagValue(static_cast(c), true, true, TextEnum::ATTRI); if (PriorDealChar() == c) { position_++; } } } } void XmlPullParser::ParseEntityDecl() { SkipText(tagText_.START_ENTITY); bool generalEntity = true; SkipInvalidChar(); if (PriorDealChar() == '%') { generalEntity = false; position_++; SkipInvalidChar(); } std::string name = ParseName(); SkipInvalidChar(); int quote = PriorDealChar(); std::string entityValue; if (quote == '"' || quote == '\'') { position_++; entityValue = ParseTagValue(static_cast(quote), true, false, TextEnum::ENTITY_DECL); if (PriorDealChar() == quote) { position_++; } } else if (ParserDoctInnerInfo(true, false)) { entityValue = ""; SkipInvalidChar(); if (PriorDealChar() == tagText_.NDATA[0]) { SkipText(tagText_.NDATA); SkipInvalidChar(); ParseName(); } } else { xmlPullParserError_ = "Expected entity value or external ID"; } SkipInvalidChar(); SkipChar('>'); } void XmlPullParser::ParseInneNotaDecl() { SkipText(tagText_.START_NOTATION); SkipInvalidChar(); ParseName(); if (!ParserDoctInnerInfo(false, false)) { xmlPullParserError_ = "Expected external ID or public ID for notation "; } SkipInvalidChar(); SkipChar('>'); } void XmlPullParser::readInternalSubset() { SkipChar('['); while (true) { SkipInvalidChar(); if (PriorDealChar() == ']') { position_++; return; } TagEnum declarationType = ParseTagType(true); switch (declarationType) { case TagEnum::ELEMENTDECL: ParseInnerEleDec(); break; case TagEnum::ATTLISTDECL: ParseInnerAttriDecl(); break; case TagEnum::ENTITYDECL: ParseEntityDecl(); break; case TagEnum::NOTATIONDECL: ParseInneNotaDecl(); break; case TagEnum::INSTRUCTION: SkipText(tagText_.START_PROCESSING_INSTRUCTION); ParseDelimiterInfo(tagText_.END_PROCESSING_INSTRUCTION, false); break; case TagEnum::COMMENT: ParseComment(false); break; case TagEnum::PARAMETER_ENTITY_REF: break; xmlPullParserError_ = "Parameter entity references are not supported "; default: break; xmlPullParserError_ = "Unexpected token"; } } } void XmlPullParser::ParseDoctype(bool saveDtdText) { SkipText(tagText_.START_DOCTYPE); int startPosition = -1; if (saveDtdText) { keyInfo_ = ""; startPosition = position_; } SkipInvalidChar(); ParseName(); ParserDoctInnerInfo(true, true); SkipInvalidChar(); if (PriorDealChar() == '[') { readInternalSubset(); } SkipInvalidChar(); if (saveDtdText) { keyInfo_.append(strXml_, 0, position_); keyInfo_ = keyInfo_.substr(startPosition); text_ = keyInfo_; keyInfo_ = ""; } SkipChar('>'); } void XmlPullParser::ParseText() { text_ = ParseTagValue('<', false, false, TextEnum::TEXT); std::string strTemp = text_; Replace(strTemp, "\r", ""); Replace(strTemp, "\n", ""); Replace(strTemp, " ", ""); if ((depth == 0 && bWhitespace_) || strTemp.size() == 0) { type = TagEnum::WHITESPACE; } } void XmlPullParser::ParseCdect() { SkipText(tagText_.START_CDATA); text_ = ParseDelimiterInfo(tagText_.END_CDATA, true); } TagEnum XmlPullParser::ParseOneTagFunc() { switch (type) { case TagEnum::START_DOCUMENT: return type; case TagEnum::START_TAG: { ParseStartTag(false, false); return type; } case TagEnum::END_TAG: { ParseEndTag(); return type; } case TagEnum::END_DOCUMENT: return type; case TagEnum::ENTITY_REFERENCE: { std::string entityTextBuilder; ParseEntity(entityTextBuilder, true, false, TextEnum::TEXT); text_ = entityTextBuilder; return TagEnum::OK; } case TagEnum::TEXT: ParseText(); return TagEnum::OK; case TagEnum::CDSECT: ParseCdect(); return TagEnum::OK; case TagEnum::COMMENT: ParseComment(true); return TagEnum::OK; case TagEnum::INSTRUCTION: ParseInstruction(); return TagEnum::OK; case TagEnum::DOCDECL: ParseDoctype(true); return TagEnum::OK; default: xmlPullParserError_ = "Unexpected token"; return TagEnum::ERROR1; } } TagEnum XmlPullParser::ParseOneTag() { if (type == TagEnum::END_TAG) { depth--; } if (bEndFlag_) { bEndFlag_ = false; type = TagEnum::END_TAG; return type; } ParserPriorDeal(); while (true) { TagEnum typeTem = ParseOneTagFunc(); if (typeTem == TagEnum::ERROR1) { return TagEnum::ERROR1; } else if (typeTem != TagEnum::OK) { return typeTem; } if (depth == 0 && (type == TagEnum::ENTITY_REFERENCE || type == TagEnum::TEXT || type == TagEnum::CDSECT)) { xmlPullParserError_ = "Unexpected token"; } if (type == TagEnum::DOCDECL && (!bDoctype_)) { ParseOneTag(); } return type; if (type == TagEnum::WHITESPACE) { text_ = ""; } TagEnum typeTemp = ParseTagType(false); if (text_ != "" && !(text_ == "") && typeTemp < TagEnum::TEXT) { type = TagEnum::TEXT; return type; } type = typeTemp; } } void XmlPullParser::ParserPriorDeal() { type = ParseTagType(false); if (type == TagEnum::XML_DECLARATION) { ParseDeclaration(); type = ParseTagType(false); } text_ = ""; bWhitespace_ = true; prefix_ = ""; name_ = ""; namespace_ = ""; attriCount_ = 0; } void XmlPullParser::ParseInstruction() { SkipText(tagText_.START_PROCESSING_INSTRUCTION); text_ = ParseDelimiterInfo(tagText_.END_PROCESSING_INSTRUCTION, true); } int XmlPullParser::GetColumnNumber() { int result = bufferStartColumn_; for (int i = 0; i < position_; i++) { if (strXml_[i] == '\n') { result = 0; } else { result++; } } return result + 1; } int XmlPullParser::GetDepth() { return depth; } int XmlPullParser::GetLineNumber() { int result = bufferStartLine_; for (int i = 0; i < position_; i++) { if (strXml_[i] == '\n') { result++; } } return result + 1; } std::string XmlPullParser::GetName() { return name_; } std::string XmlPullParser::GetPrefix() { return prefix_; } std::string XmlPullParser::GetText() { if (type < TagEnum::TEXT || (type == TagEnum::ENTITY_REFERENCE && bUnresolved_)) { return ""; } else { return text_; } } bool XmlPullParser::IsEmptyElementTag() { if (type != TagEnum::START_TAG) { xmlPullParserError_ = tagText_.ILLEGAL_TYPE; } return bEndFlag_; } int XmlPullParser::GetAttributeCount() { return attriCount_; } bool XmlPullParser::IsWhitespace() { if (type != TagEnum::TEXT && type != TagEnum::WHITESPACE && type != TagEnum::CDSECT) { xmlPullParserError_ = tagText_.ILLEGAL_TYPE; } return bWhitespace_; } std::string XmlPullParser::GetNamespace() { return namespace_; } napi_value XmlPullParser::ParseInfo::GetColumnNumber(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); int temp = (reinterpret_cast(obj))->GetColumnNumber(); napi_value result = nullptr; napi_create_int32(env, temp, &result); return result; } napi_value XmlPullParser::ParseInfo::GetDepth(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); int tempDepth = (reinterpret_cast(obj))->GetDepth(); napi_value result = nullptr; napi_create_int32(env, tempDepth, &result); return result; } napi_value XmlPullParser::ParseInfo::GetLineNumber(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); int temp = (reinterpret_cast(obj))->GetLineNumber(); napi_value result = nullptr; napi_create_int32(env, temp, &result); return result; } napi_value XmlPullParser::ParseInfo::GetName(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); std::string temp = (reinterpret_cast(obj))->GetName(); napi_value result = nullptr; napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); return result; } napi_value XmlPullParser::ParseInfo::GetNamespace(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); std::string temp = (reinterpret_cast(obj))->GetNamespace(); napi_value result = nullptr; napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); return result; } napi_value XmlPullParser::ParseInfo::GetPrefix(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); std::string temp = (reinterpret_cast(obj))->GetPrefix(); napi_value result = nullptr; napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); return result; } napi_value XmlPullParser::ParseInfo::GetText(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); std::string temp = (reinterpret_cast(obj))->GetText(); napi_value result = nullptr; napi_create_string_utf8(env, temp.c_str(), temp.length(), &result); return result; } napi_value XmlPullParser::ParseInfo::IsEmptyElementTag(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); bool temp = (reinterpret_cast(obj))->IsEmptyElementTag(); napi_value result = nullptr; napi_get_boolean(env, temp, &result); return result; } napi_value XmlPullParser::ParseInfo::IsWhitespace(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); bool temp = (reinterpret_cast(obj))->IsWhitespace(); napi_value result = nullptr; napi_get_boolean(env, temp, &result); return result; } napi_value XmlPullParser::ParseInfo::GetAttributeCount(napi_env env, napi_callback_info info) { napi_value thisVar = nullptr; napi_value mainVar = nullptr; NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr)); void *obj = nullptr; napi_get_named_property(env, thisVar, "MainInfo", &mainVar); NAPI_CALL(env, napi_unwrap(env, mainVar, &obj)); int temp = (reinterpret_cast(obj))->GetAttributeCount(); napi_value result = nullptr; napi_create_int32(env, temp, &result); return result; } } // namespace