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
29namespace 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         */
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;
300            SrcLinkList()
301            {
302                this->next = nullptr;
303                this->strBuffer = "";
304                this->position = -1;
305                this->max = -1;
306            };
307            SrcLinkList(SrcLinkList* pNext, const std::string &strTemp, int iPos, int iMax) :next(pNext),
308                strBuffer(strTemp), position(iPos), max(iMax) {}
309        };
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        };
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        void Parse(napi_env env, napi_value thisVar);
340        std::string GetNamespace(const std::string &prefix);
341        napi_value DealOptionInfo(napi_env env, napi_value napiObj);
342        TagEnum ParseTagType(bool inDeclaration);
343        void SkipText(std::string chars);
344        int PriorDealChar();
345        void SkipChar(char expected);
346        std::string ParseNameInner(size_t start);
347        std::string ParseName();
348        void SkipInvalidChar();
349        void ParseEntity(std::string& out, bool isEntityToken, bool throwOnResolveFailure, TextEnum textEnum);
350        std::string ParseTagValue(char delimiter, bool resolveEntities, bool throwOnResolveFailure, TextEnum textEnum);
351        bool ParseNsp();
352        TagEnum ParseStartTag(bool xmldecl, bool throwOnResolveFailure);
353        void ParseDeclaration();
354        bool ParseEndTag();
355        std::string ParseDelimiterInfo(std::string delimiter, bool returnText);
356        std::string ParseDelimiter(bool returnText);
357        bool ParserDoctInnerInfo(bool requireSystemName, bool assignFields);
358        void ParseComment(bool returnText);
359        void ParseSpecText();
360        void ParseInnerEleDec();
361        void ParseInnerAttriDecl();
362        void ParseEntityDecl();
363        void ParseInneNotaDecl();
364        void ReadInternalSubset();
365        void ParseDoctype(bool saveDtdText);
366        TagEnum ParseOneTag();
367        void ParserPriorDeal();
368        void ParseInstruction();
369        void ParseText();
370        void ParseCdect();
371        std::string XmlPullParserError() const;
372        bool ParseAttri(napi_env env, napi_value thisVar) const;
373        bool ParseToken(napi_env env, napi_value thisVar) const;
374        void ParseNspFunction();
375        void ParseNspFunc(size_t &i, const std::string &attrName, bool &any);
376        void ParseInnerAttriDeclFunc(int &c);
377        TagEnum DealExclamationGroup();
378        void ParseEntityFunc(size_t start, std::string &out, bool isEntityToken, TextEnum textEnum);
379        bool ParseStartTagFuncDeal(bool throwOnResolveFailure);
380        TagEnum ParseStartTagFunc(bool xmldecl, bool throwOnResolveFailure);
381        TagEnum ParseOneTagFunc();
382        size_t ParseTagValueInner(size_t &start, std::string &result, char delimiter, TextEnum textEnum, bool bFlag);
383        bool ParseTagValueFunc(char &c, bool bFlag, TextEnum textEnum, size_t &start, std::string &result);
384        void MakeStrUpper(std::string &src) const;
385        TagEnum DealLtGroup();
386        void DealWhiteSpace(unsigned char c);
387        friend class XmlTest;
388    private:
389        bool bDoctype_ {};
390        bool bIgnoreNS_ {};
391        bool bStartDoc_ {true};
392        napi_value tagFunc_ {nullptr};
393        napi_value attrFunc_ {nullptr};
394        napi_value tokenFunc_ {nullptr};
395        napi_env env_ {nullptr};
396        TagText tagText_;
397        APIVersion APIVerIsolation_;
398        std::string strXml_ {};
399        std::string version_ {};
400        std::string encoding_ {};
401        int32_t apiVersion_ {0};
402        int32_t API_VERSION_MOD {100};
403        std::string prefix_ {};
404        std::string namespace_ {};
405        std::string name_ {};
406        std::string text_ {};
407        std::string sysInfo_ {};
408        std::string pubInfo_ {};
409        std::string keyInfo_ {};
410        std::string xmlPullParserError_ {};
411        std::vector<size_t> nspCounts_;
412        std::vector<std::string> nspStack_;
413        std::vector<std::string> elementStack_;
414        std::vector<std::string> attributes;
415        std::map<std::string, std::string> documentEntities;
416        std::map<std::string, std::map<std::string, std::string>> defaultAttributes;
417        std::map<std::string, std::string> DEFAULT_ENTITIES = {
418            {"lt;", "<"}, {"gt;", ">"}, {"amp;", "&"}, {"apos;", "'"}, {"quot;", "\""}
419        };
420        size_t position_ {};
421        size_t depth {};
422        size_t max_ {};
423        size_t bufferStartLine_ {};
424        size_t bufferStartColumn_ {};
425        size_t attriCount_ {};
426        TagEnum type = TagEnum::START_DOCUMENT;
427        bool bWhitespace_ {};
428        SrcLinkList* srcLinkList_ = new SrcLinkList;
429        bool bEndFlag_ {};
430        bool bAlone_ {};
431        bool bUnresolved_ {};
432        bool relaxed {};
433        bool bKeepNsAttri {};
434        bool bDocDecl {};
435    };
436} // namespace OHOS::Xml
437#endif // XML_JS_XML_H
438