/* * Copyright (c) 2022 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. */ #ifndef XML_JS_XML_H #define XML_JS_XML_H #include <algorithm> #include <cstring> #include <map> #include <string> #include <vector> #include "napi/native_api.h" #include "napi/native_node_api.h" #include "utils/log.h" namespace OHOS::xml { class XmlSerializer { public: /** * Constructor for XmlSerializer. * * @param pStart is the pointer. * @param bufferLengthis the length of the ArrayBuffer or * DataView memory used to receive the written xml information. */ XmlSerializer(char *pStart, size_t bufferLength, const std::string &encoding = "utf-8") :pStart_(pStart), iLength_(bufferLength), encoding_(encoding) {}; /** * XmlSerializer destructor. */ ~XmlSerializer() {} /** * Set the Attributes method. * * @param name The parameter is the key value of the property. * @param value The parameter is the value of the property. */ void SetAttributes(const std::string &name, const std::string &value); /** * Writes an empty element. * * @param name The parameter is the element name of the empty element. */ void AddEmptyElement(std::string name); /** * Set the Declaration method. */ void SetDeclaration(); /** * Writes the element start tag with the given name. * * @param name The parameter is the element name of the current element. */ void StartElement(const std::string &name); /** * Write element end tag. */ void EndElement(); /** * The namespace into which the current element tag is written. * * @param prefix The parameter is the prefix of the current element and its children. * @param nsTemp The parameter is the namespace of the current element and its children. */ void SetNamespace(std::string prefix, const std::string &nsTemp); /** * Write the comment property. * * @param comment The parameter is the comment content of the current element. */ void SetComment(const std::string &comment); /** * Write CDATA attributes. * * @param comment The parameter is the content of the CDATA attribute. */ void SetCData(std::string data); /** * Write CDATA attributes. * * @param comment The parameter is the content of the CDATA attribute. */ void SetText(const std::string &text); /** * Write DocType property. * * @param text The parameter is the content of the DocType property. */ void SetDocType(const std::string &text); /** * write an escape. * * @param s The parameter is the passed in escaped string. */ void WriteEscaped(std::string s); /** * SplicNsp functio. */ void SplicNsp(); /** * NextItem function. */ void NextItem(); /** * Throw exception function. */ std::string XmlSerializerError(); /** * Process the value of the string passed by napi. * * @param env The parameter is NAPI environment variables. * @param napiStr The parameter is pass parameters. * @param result The parameter is return the processed value. */ static napi_status DealNapiStrValue(napi_env env, const napi_value napiStr, std::string &result); friend class XmlTest; private: char *pStart_; size_t iPos_ = 0; size_t iLength_; std::string xmlSerializerError_; std::string encoding_; size_t depth_ = 0; std::string type; std::vector<std::string> elementStack = { "", "", ""}; std::map<int, std::map<int, std::string>> multNsp; int CurNspNum = 0; std::string out_; bool isHasDecl = false; }; enum class TagEnum { XML_DECLARATION = -1, START_DOCUMENT, END_DOCUMENT, START_TAG, END_TAG, TEXT, CDSECT, COMMENT, DOCDECL, INSTRUCTION, ENTITY_REFERENCE, WHITESPACE, ELEMENTDECL, ENTITYDECL, ATTLISTDECL, NOTATIONDECL, PARAMETER_ENTITY_REF, OK, ERROR1 }; enum class TextEnum { ATTRI, TEXT, ENTITY_DECL }; class XmlPullParser { public: class ParseInfo { public: /** * Get the current depth of the element. * @param env The parameter is NAPI environment variables. * @param info The parameter is the current depth of the returned element. */ static napi_value GetDepth(napi_env env, napi_callback_info info); /** * Get the current column number, starting at 1. * @param env The parameter is NAPI environment variables. * @param info The parameter is to return the current line number. */ static napi_value GetColumnNumber(napi_env env, napi_callback_info info); /** * Get the current line number, starting at 1. * @param env The parameter is NAPI environment variables. * @param info The parameter is to return the current column number. */ static napi_value GetLineNumber(napi_env env, napi_callback_info info); /** * Get the number of attributes of the current start tag. * @param env The parameter is NAPI environment variables. * @param info The parameter is the number of attributes of the current start tag. */ static napi_value GetAttributeCount(napi_env env, napi_callback_info info); /** * Get the current element name. * @param env The parameter is NAPI environment variables. * @param info The parameter is to return the current element name. */ static napi_value GetName(napi_env env, napi_callback_info info); /** * Get the namespace of the current element. * @param env The parameter is NAPI environment variables. * @param info The parameter is the namespace that returns the current element. */ static napi_value GetNamespace(napi_env env, napi_callback_info info); /** * Get the current element prefix. * @param env The parameter is NAPI environment variables. * @param info The parameter is to return the current element prefix. */ static napi_value GetPrefix(napi_env env, napi_callback_info info); /** * Get the text content of the current event. * @param env The parameter is NAPI environment variables. * @param info The parameter is to return the text content of the current event. */ static napi_value GetText(napi_env env, napi_callback_info info); /** * Check whether the current element is an empty element. * @param env The parameter is NAPI environment variables. * @param info The parameter is to returns true The current element is an empty element. */ static napi_value IsEmptyElementTag(napi_env env, napi_callback_info info); /** * Determines whether the current text event contains only space characters. * @param env The parameter is NAPI environment variables. * @param info The parameter is to returns true, the current text event contains only space characters. */ static napi_value IsWhitespace(napi_env env, napi_callback_info info); }; struct TagText { const std::string START_CDATA = "<![CDATA["; const std::string END_CDATA = "]]>"; const std::string START_COMMENT = "<!--"; const std::string END_COMMENT = "-->"; const std::string COMMENT_DOUBLE_DASH = "--"; const std::string END_PROCESSING_INSTRUCTION = "?>"; const std::string START_DOCTYPE = "<!DOCTYPE"; const std::string SYSTEM = "SYSTEM"; const std::string PUBLIC = "PUBLIC"; const std::string DOUBLE_QUOTE = "\""; const std::string SINGLE_QUOTE = "\\"; const std::string START_ELEMENT = "<!ELEMENT"; const std::string EMPTY = "EMPTY"; const std::string ANY = "ANY"; const std::string START_ATTLIST = "<!ATTLIST"; const std::string NOTATION = "NOTATION"; const std::string REQUIRED = "REQUIRED"; const std::string IMPLIED = "IMPLIED"; const std::string FIXED = "FIXED"; const std::string START_ENTITY = "<!ENTITY"; const std::string NDATA = "NDATA"; const std::string START_NOTATION = "<!NOTATION"; const std::string ILLEGAL_TYPE = "Wrong event type"; const std::string START_PROCESSING_INSTRUCTION = "<?"; const std::string XML = "xml "; }; struct SrcLinkList { SrcLinkList* next; std::string strBuffer; int position; size_t max; SrcLinkList() { this->next = nullptr; this->strBuffer = ""; this->position = -1; this->max = -1; }; SrcLinkList(SrcLinkList* pNext, const std::string &strTemp, int iPos, int iMax) :next(pNext), strBuffer(strTemp), position(iPos), max(iMax) {} }; XmlPullParser(const std::string &strXml, const std::string &encoding) : strXml_(strXml), encoding_(encoding) {}; ~XmlPullParser() { while (srcLinkList_) { PopSrcLinkList(); } }; int GetDepth() const; int GetColumnNumber() const; int GetLineNumber() const; int GetAttributeCount() const; std::string GetName() const; std::string GetNamespace() const; std::string GetPrefix() const; std::string GetText() const; bool IsEmptyElementTag() const; bool IsWhitespace() const; void PushSrcLinkList(std::string strBuffer); void PopSrcLinkList(); bool DealLength(size_t minimum); void Replace(std::string &strTemp, std::string strSrc, std::string strDes) const; size_t GetNSCount(size_t iTemp); void Parse(napi_env env, napi_value thisVar); std::string GetNamespace(const std::string &prefix); napi_value DealOptionInfo(napi_env env, napi_value napiObj); TagEnum ParseTagType(bool inDeclaration); void SkipText(std::string chars); int PriorDealChar(); void SkipChar(char expected); std::string ParseNameInner(size_t start); std::string ParseName(); void SkipInvalidChar(); void ParseEntity(std::string& out, bool isEntityToken, bool throwOnResolveFailure, TextEnum textEnum); std::string ParseTagValue(char delimiter, bool resolveEntities, bool throwOnResolveFailure, TextEnum textEnum); bool ParseNsp(); void ParseStartTag(bool xmldecl, bool throwOnResolveFailure); void ParseDeclaration(); void ParseEndTag(); std::string ParseDelimiterInfo(std::string delimiter, bool returnText); std::string ParseDelimiter(bool returnText); bool ParserDoctInnerInfo(bool requireSystemName, bool assignFields); void ParseComment(bool returnText); void ParseSpecText(); void ParseInnerEleDec(); void ParseInnerAttriDecl(); void ParseEntityDecl(); void ParseInneNotaDecl(); void ReadInternalSubset(); void ParseDoctype(bool saveDtdText); TagEnum ParseOneTag(); void ParserPriorDeal(); void ParseInstruction(); void ParseText(); void ParseCdect(); std::string XmlPullParserError() const; bool ParseAttri(napi_env env, napi_value thisVar) const; bool ParseToken(napi_env env, napi_value thisVar) const; void ParseNspFunction(); void ParseNspFunc(size_t &i, const std::string &attrName, bool &any); void ParseInnerAttriDeclFunc(int &c); TagEnum DealExclamationGroup(); void ParseEntityFunc(size_t start, std::string &out, bool isEntityToken, TextEnum textEnum); bool ParseStartTagFuncDeal(bool throwOnResolveFailure); bool ParseStartTagFunc(bool xmldecl, bool throwOnResolveFailure); TagEnum ParseOneTagFunc(); size_t ParseTagValueInner(size_t &start, std::string &result, char delimiter, TextEnum textEnum, bool bFlag); bool ParseTagValueFunc(char &c, bool bFlag, TextEnum textEnum, size_t &start, std::string &result); void MakeStrUpper(std::string &src) const; TagEnum DealLtGroup(); void DealWhiteSpace(unsigned char c); friend class XmlTest; private: bool bDoctype_ = false; bool bIgnoreNS_ = false; bool bStartDoc_ = true; napi_value tagFunc_ = nullptr; napi_value attrFunc_ = nullptr; napi_value tokenFunc_ = nullptr; TagText tagText_; std::string strXml_ = ""; std::string version_ = ""; std::string encoding_ = ""; std::string prefix_ = ""; std::string namespace_ = ""; std::string name_ = ""; std::string text_ = ""; std::string sysInfo_ = ""; std::string pubInfo_ = ""; std::string keyInfo_ = ""; std::string xmlPullParserError_ = ""; std::vector<size_t> nspCounts_; std::vector<std::string> nspStack_; std::vector<std::string> elementStack_; std::vector<std::string> attributes; std::map<std::string, std::string> documentEntities; std::map<std::string, std::map<std::string, std::string>> defaultAttributes; std::map<std::string, std::string> DEFAULT_ENTITIES = { {"lt;", "<"}, {"gt;", ">"}, {"amp;", "&"}, {"apos;", "'"}, {"quot;", "\""} }; size_t position_ = 0; size_t depth = 0; size_t max_ = 0; size_t bufferStartLine_ = 0; size_t bufferStartColumn_ = 0; size_t attriCount_ = 0; TagEnum type = TagEnum::START_DOCUMENT; bool bWhitespace_ = false; SrcLinkList* srcLinkList_ = new SrcLinkList; bool bEndFlag_ = false; bool bAlone_ = false; bool bUnresolved_ = false; bool relaxed = false; bool bKeepNsAttri = false; bool bDocDecl = false; }; } // namespace OHOS::Xml #endif // XML_JS_XML_H