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 #ifndef XML_JS_XML_H
17 #define XML_JS_XML_H
18 
19 #include <algorithm>
20 #include <cstring>
21 #include <map>
22 #include <string>
23 #include <vector>
24 #include "napi/native_api.h"
25 #include "napi/native_node_api.h"
26 #include "native_engine/native_engine.h"
27 #include "tools/log.h"
28 
29 namespace OHOS::xml {
30     class XmlSerializer {
31     public:
32         /**
33          * Constructor for XmlSerializer.
34          *
35          * @param pStart is the pointer.
36          * @param bufferLengthis the length of the ArrayBuffer or
37          * DataView memory used to receive the written xml information.
38          */
39         XmlSerializer(char *pStart, size_t bufferLength, const std::string &encoding = "utf-8") :pStart_(pStart),
40             iLength_(bufferLength), encoding_(encoding) {};
41 
42         /**
43          * XmlSerializer destructor.
44          */
~XmlSerializer()45         ~XmlSerializer() {}
46 
47         /**
48          * Set the Attributes method.
49          *
50          * @param name The parameter is the key value of the property.
51          * @param value The parameter is the value of the property.
52          */
53         void SetAttributes(const std::string &name, const std::string &value);
54 
55         /**
56          * Writes an empty element.
57          *
58          * @param name The parameter is the element name of the empty element.
59          */
60         void AddEmptyElement(std::string name);
61 
62         /**
63          * Set the Declaration method.
64          */
65         void SetDeclaration();
66 
67         /**
68          * Writes the element start tag with the given name.
69          *
70          * @param name The parameter is the element name of the current element.
71          */
72         void StartElement(const std::string &name);
73 
74         /**
75          * Write element end tag.
76          */
77         void EndElement();
78 
79         /**
80          * The namespace into which the current element tag is written.
81          *
82          * @param prefix The parameter is the prefix of the current element and its children.
83          * @param nsTemp The parameter is the namespace of the current element and its children.
84          */
85         void SetNamespace(std::string prefix, const std::string &nsTemp);
86 
87         /**
88          * Write the comment property.
89          *
90          * @param comment The parameter is the comment content of the current element.
91          */
92         void SetComment(const std::string &comment);
93 
94         /**
95          * Write CDATA attributes.
96          *
97          * @param comment The parameter is the content of the CDATA attribute.
98          */
99         void SetCData(std::string data);
100 
101         /**
102          * Write CDATA attributes.
103          *
104          * @param comment The parameter is the content of the CDATA attribute.
105          */
106         void SetText(const std::string &text);
107 
108         /**
109          * Write DocType property.
110          *
111          * @param text The parameter is the content of the DocType property.
112          */
113         void SetDocType(const std::string &text);
114 
115         /**
116          * write an escape.
117          *
118          * @param s The parameter is the passed in escaped string.
119          */
120         void WriteEscaped(std::string s);
121 
122         /**
123          * SplicNsp functio.
124          */
125         void SplicNsp();
126 
127         /**
128          * NextItem function.
129          */
130         void NextItem();
131 
132         /**
133          * Throw exception function.
134          */
135         std::string XmlSerializerError();
136 
137         /**
138          * Process the value of the string passed by napi.
139          *
140          * @param env The parameter is NAPI environment variables.
141          * @param napiStr The parameter is pass parameters.
142          * @param result The parameter is return the processed value.
143          */
144         static napi_status DealNapiStrValue(napi_env env, const napi_value napiStr, std::string &result);
145 
146         friend class XmlTest;
147 
148     private:
149         std::string Replace(std::string str, const std::string &subStr, const std::string &repStr);
150         char *pStart_ {nullptr};
151         size_t iPos_ {};
152         size_t iLength_ {};
153         std::string xmlSerializerError_ {};
154         std::string encoding_ {};
155         size_t depth_ {};
156         std::string type {};
157         std::vector<std::string> elementStack = { "", "", ""};
158         std::map<int, std::map<int, std::string>> multNsp;
159         int curNspNum {};
160         std::string out_ {};
161         bool isHasDecl {};
162     };
163 
164     enum class TagEnum {
165         XML_DECLARATION = -1,
166         START_DOCUMENT,
167         END_DOCUMENT,
168         START_TAG,
169         END_TAG,
170         TEXT,
171         CDSECT,
172         COMMENT,
173         DOCDECL,
174         INSTRUCTION,
175         ENTITY_REFERENCE,
176         WHITESPACE,
177         ELEMENTDECL,
178         ENTITYDECL,
179         ATTLISTDECL,
180         NOTATIONDECL,
181         PARAMETER_ENTITY_REF,
182         OK,
183         ERROR
184     };
185 
186     enum class TextEnum {
187         ATTRI,
188         TEXT,
189         ENTITY_DECL
190     };
191     class XmlPullParser {
192     public:
193         class ParseInfo {
194         public:
195             /**
196              * Get the current depth of the element.
197              * @param env The parameter is NAPI environment variables.
198              * @param info The parameter is the current depth of the returned element.
199              */
200             static napi_value GetDepth(napi_env env, napi_callback_info info);
201 
202             /**
203              * Get the current column number, starting at 1.
204              * @param env The parameter is NAPI environment variables.
205              * @param info The parameter is to return the current line number.
206              */
207             static napi_value GetColumnNumber(napi_env env, napi_callback_info info);
208 
209             /**
210              * Get the current line number, starting at 1.
211              * @param env The parameter is NAPI environment variables.
212              * @param info The parameter is to return the current column number.
213              */
214             static napi_value GetLineNumber(napi_env env, napi_callback_info info);
215 
216             /**
217              * Get the number of attributes of the current start tag.
218              * @param env The parameter is NAPI environment variables.
219              * @param info The parameter is the number of attributes of the current start tag.
220              */
221             static napi_value GetAttributeCount(napi_env env, napi_callback_info info);
222 
223             /**
224              * Get the current element name.
225              * @param env The parameter is NAPI environment variables.
226              * @param info The parameter is to return the current element name.
227              */
228             static napi_value GetName(napi_env env, napi_callback_info info);
229 
230             /**
231              * Get the namespace of the current element.
232              * @param env The parameter is NAPI environment variables.
233              * @param info The parameter is the namespace that returns the current element.
234              */
235             static napi_value GetNamespace(napi_env env, napi_callback_info info);
236 
237             /**
238              * Get the current element prefix.
239              * @param env The parameter is NAPI environment variables.
240              * @param info The parameter is to return the current element prefix.
241              */
242             static napi_value GetPrefix(napi_env env, napi_callback_info info);
243 
244             /**
245              * Get the text content of the current event.
246              * @param env The parameter is NAPI environment variables.
247              * @param info The parameter is to return the text content of the current event.
248              */
249             static napi_value GetText(napi_env env, napi_callback_info info);
250 
251             /**
252              * Check whether the current element is an empty element.
253              * @param env The parameter is NAPI environment variables.
254              * @param info The parameter is to returns true The current element is an empty element.
255              */
256             static napi_value IsEmptyElementTag(napi_env env, napi_callback_info info);
257 
258             /**
259              * Determines whether the current text event contains only space characters.
260              * @param env The parameter is NAPI environment variables.
261              * @param info The parameter is to returns true, the current text event contains only space characters.
262              */
263             static napi_value IsWhitespace(napi_env env, napi_callback_info info);
264         };
265         struct TagText {
266             const std::string START_CDATA = "<![CDATA[";
267             const std::string END_CDATA = "]]>";
268             const std::string START_COMMENT = "<!--";
269             const std::string END_COMMENT = "-->";
270             const std::string COMMENT_DOUBLE_DASH = "--";
271             const std::string END_PROCESSING_INSTRUCTION = "?>";
272             const std::string START_DOCTYPE = "<!DOCTYPE";
273             const std::string SYSTEM = "SYSTEM";
274             const std::string PUBLIC = "PUBLIC";
275             const std::string DOUBLE_QUOTE = "\"";
276             const std::string SINGLE_QUOTE = "\\";
277             const std::string START_ELEMENT = "<!ELEMENT";
278             const std::string EMPTY = "EMPTY";
279             const std::string ANY = "ANY";
280             const std::string START_ATTLIST = "<!ATTLIST";
281             const std::string NOTATION = "NOTATION";
282             const std::string REQUIRED = "REQUIRED";
283             const std::string IMPLIED = "IMPLIED";
284             const std::string FIXED = "FIXED";
285             const std::string START_ENTITY = "<!ENTITY";
286             const std::string NDATA = "NDATA";
287             const std::string START_NOTATION = "<!NOTATION";
288             const std::string ILLEGAL_TYPE = "Wrong event type";
289             const std::string START_PROCESSING_INSTRUCTION = "<?";
290             const std::string XML = "xml ";
291         };
292         struct APIVersion {
293             const int32_t API12 = 12;
294         };
295         struct SrcLinkList {
296             SrcLinkList* next;
297             std::string strBuffer;
298             int position;
299             size_t max;
SrcLinkListSrcLinkList300             SrcLinkList()
301             {
302                 this->next = nullptr;
303                 this->strBuffer = "";
304                 this->position = -1;
305                 this->max = -1;
306             };
SrcLinkListSrcLinkList307             SrcLinkList(SrcLinkList* pNext, const std::string &strTemp, int iPos, int iMax) :next(pNext),
308                 strBuffer(strTemp), position(iPos), max(iMax) {}
309         };
XmlPullParser(napi_env env,const std::string & strXml,const std::string & encoding)310         XmlPullParser(napi_env env, const std::string &strXml, const std::string &encoding) :env_(env), strXml_(strXml),
311             encoding_(encoding)
312         {
313             NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
314             if (engine != nullptr) {
315                 apiVersion_ = engine->GetApiVersion() % API_VERSION_MOD;
316             }
317         };
~XmlPullParser()318         ~XmlPullParser()
319         {
320             while (srcLinkList_) {
321                 PopSrcLinkList();
322             }
323         };
324         int GetDepth() const;
325         int GetColumnNumber() const;
326         int GetLineNumber() const;
327         int GetAttributeCount() const;
328         std::string GetName() const;
329         std::string GetNamespace() const;
330         std::string GetPrefix() const;
331         std::string GetText() const;
332         bool IsEmptyElementTag() const;
333         bool IsWhitespace() const;
334         void PushSrcLinkList(std::string strBuffer);
335         void PopSrcLinkList();
336         bool DealLength(size_t minimum);
337         void Replace(std::string &strTemp, std::string strSrc, std::string strDes) const;
338         size_t GetNSCount(size_t iTemp);
339         std::string DealCdata(std::string data);
340         void Parse(napi_env env, napi_value thisVar, bool deprecated);
341         std::string GetNamespace(const std::string &prefix);
342         napi_value DealOptionInfo(napi_env env, napi_value napiObj);
343         TagEnum ParseTagType(bool inDeclaration);
344         void SkipText(std::string chars);
345         int PriorDealChar();
346         void SkipChar(char expected);
347         std::string ParseNameInner(size_t start);
348         std::string ParseName();
349         void SkipInvalidChar();
350         void ParseEntity(std::string& out, bool isEntityToken, bool throwOnResolveFailure, TextEnum textEnum);
351         std::string ParseTagValue(char delimiter, bool resolveEntities, bool throwOnResolveFailure, TextEnum textEnum);
352         bool ParseNsp();
353         TagEnum ParseStartTag(bool xmldecl, bool throwOnResolveFailure);
354         void ParseDeclaration();
355         bool ParseEndTag();
356         std::string ParseDelimiterInfo(std::string delimiter, bool returnText);
357         std::string ParseDelimiter(bool returnText);
358         bool ParserDoctInnerInfo(bool requireSystemName, bool assignFields);
359         void ParseComment(bool returnText);
360         void ParseSpecText();
361         void ParseInnerEleDec();
362         void ParseInnerAttriDecl();
363         void ParseEntityDecl();
364         void ParseInneNotaDecl();
365         void ReadInternalSubset();
366         void ParseDoctype(bool saveDtdText);
367         TagEnum ParseOneTag();
368         void ParserPriorDeal();
369         void ParseInstruction();
370         void ParseText();
371         void ParseCdect();
372         std::string XmlPullParserError() const;
373         bool ParseAttri(napi_env env, napi_value thisVar) const;
374         bool ParseToken(napi_env env, napi_value thisVar) const;
375         void ParseNspFunction();
376         void ParseNspFunc(size_t &i, const std::string &attrName, bool &any);
377         void ParseInnerAttriDeclFunc(int &c);
378         TagEnum DealExclamationGroup();
379         void ParseEntityFunc(size_t start, std::string &out, bool isEntityToken, TextEnum textEnum);
380         bool ParseStartTagFuncDeal(bool throwOnResolveFailure);
381         TagEnum ParseStartTagFunc(bool xmldecl, bool throwOnResolveFailure);
382         TagEnum ParseOneTagFunc();
383         size_t ParseTagValueInner(size_t &start, std::string &result, char delimiter, TextEnum textEnum, bool bFlag);
384         bool ParseTagValueFunc(char &c, bool bFlag, TextEnum textEnum, size_t &start, std::string &result);
385         void MakeStrUpper(std::string &src) const;
386         TagEnum DealLtGroup();
387         void DealWhiteSpace(unsigned char c);
388         friend class XmlTest;
389     private:
390         bool bDoctype_ {};
391         bool bIgnoreNS_ {};
392         bool bStartDoc_ {true};
393         napi_value tagFunc_ {nullptr};
394         napi_value attrFunc_ {nullptr};
395         napi_value tokenFunc_ {nullptr};
396         napi_env env_ {nullptr};
397         TagText tagText_;
398         APIVersion APIVerIsolation_;
399         std::string strXml_ {};
400         std::string version_ {};
401         std::string encoding_ {};
402         int32_t apiVersion_ {0};
403         int32_t API_VERSION_MOD {100};
404         std::string prefix_ {};
405         std::string namespace_ {};
406         std::string name_ {};
407         std::string text_ {};
408         std::string sysInfo_ {};
409         std::string pubInfo_ {};
410         std::string keyInfo_ {};
411         std::string xmlPullParserError_ {};
412         std::vector<size_t> nspCounts_;
413         std::vector<std::string> nspStack_;
414         std::vector<std::string> elementStack_;
415         std::vector<std::string> attributes;
416         std::map<std::string, std::string> documentEntities;
417         std::map<std::string, std::map<std::string, std::string>> defaultAttributes;
418         std::map<std::string, std::string> DEFAULT_ENTITIES = {
419             {"lt;", "<"}, {"gt;", ">"}, {"amp;", "&"}, {"apos;", "'"}, {"quot;", "\""}
420         };
421         size_t position_ {};
422         size_t depth {};
423         size_t max_ {};
424         size_t bufferStartLine_ {};
425         size_t bufferStartColumn_ {};
426         size_t attriCount_ {};
427         TagEnum type = TagEnum::START_DOCUMENT;
428         bool bWhitespace_ {};
429         SrcLinkList* srcLinkList_ = new SrcLinkList;
430         bool bEndFlag_ {};
431         bool bAlone_ {};
432         bool bUnresolved_ {};
433         bool relaxed {};
434         bool bKeepNsAttri {};
435         bool bDocDecl {};
436     };
437 } // namespace OHOS::Xml
438 #endif // XML_JS_XML_H
439