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 "native_module_xml.h"
17 #include "js_xml.h"
18 #include "tools/ets_error.h"
19 
20 extern const char _binary_js_xml_js_start[];
21 extern const char _binary_js_xml_js_end[];
22 extern const char _binary_xml_abc_start[];
23 extern const char _binary_xml_abc_end[];
24 
25 namespace OHOS::xml {
26 using namespace OHOS::Tools;
27 static const int32_t ERROR_CODE = 401; // 401 : the parameter type is incorrect
28 
XmlSerializerConstructor(napi_env env,napi_callback_info info)29     static napi_value XmlSerializerConstructor(napi_env env, napi_callback_info info)
30     {
31         napi_value thisVar = nullptr;
32         void *data = nullptr;
33         size_t argc = 2;
34         napi_value args[2] = { nullptr }; // 2:The number of parameters is 2
35         XmlSerializer *object = nullptr;
36         size_t iLength = 0;
37         size_t offPos = 0;
38         napi_value arraybuffer = nullptr;
39         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, &data));
40         NAPI_ASSERT(env, argc == 1 || argc == 2, "Wrong number of arguments"); // 2: number of args
41 
42         bool bFlag = false;
43         napi_is_arraybuffer(env, args[0], &bFlag);
44         if (bFlag) {
45             napi_get_arraybuffer_info(env, args[0], &data, &iLength);
46         } else {
47             napi_is_dataview(env, args[0], &bFlag);
48             if (bFlag) {
49                 napi_get_dataview_info(env, args[0], &iLength, &data, &arraybuffer, &offPos);
50             } else {
51                 napi_throw_error(env, "401", "Parameter error. The type of Parameter must be ArrayBuffer or DataView.");
52                 return nullptr;
53             }
54         }
55 
56         if (argc == 1) {
57             object = new XmlSerializer(reinterpret_cast<char*>(data), iLength);
58         } else if (argc == 2) { // 2:When the input parameter is set to 2
59             std::string encoding = "";
60             napi_valuetype valuetype;
61             NAPI_CALL(env, napi_typeof(env, args[1], &valuetype));
62             NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
63             napi_status status = napi_ok;
64             status = XmlSerializer::DealNapiStrValue(env, args[1], encoding);
65             if (status == napi_ok) {
66                 object = new XmlSerializer(reinterpret_cast<char*>(data), iLength, encoding);
67             }
68         }
69         napi_status status = napi_wrap(env, thisVar, object,
70             [](napi_env environment, void *data, void *hint) {
71                 auto obj = reinterpret_cast<XmlSerializer*>(data);
72                 if (obj != nullptr) {
73                     delete obj;
74                     obj = nullptr;
75                 }
76             }, nullptr, nullptr);
77         if (status != napi_ok && object != nullptr) {
78             HILOG_ERROR("XmlPullParserConstructor:: napi_wrap failed");
79             delete object;
80             object = nullptr;
81         }
82         return thisVar;
83     }
84 
XmlPullParserConstructor(napi_env env,napi_callback_info info)85     static napi_value XmlPullParserConstructor(napi_env env, napi_callback_info info)
86     {
87         napi_value thisVar = nullptr;
88         void *data = nullptr;
89         size_t argc = 2;
90         napi_value args[2] = { nullptr }; // 2:two args
91         XmlPullParser *object = nullptr;
92         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, &data));
93         NAPI_ASSERT(env, argc == 1 || argc == 2, "Wrong number of arguments"); // 2:two args
94         napi_valuetype valuetype = napi_null;
95         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
96         NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type: DataView or ArrayBuffer expected.");
97         bool bFlag = false;
98         size_t len = 0;
99         size_t offPos = 0;
100         napi_value arraybuffer = nullptr;
101         napi_is_arraybuffer(env, args[0], &bFlag);
102         if (bFlag) {
103             napi_get_arraybuffer_info(env, args[0], &data, &len);
104         } else {
105             napi_is_dataview(env, args[0], &bFlag);
106             if (bFlag) {
107                 napi_get_dataview_info(env, args[0], &len, &data, &arraybuffer, &offPos);
108             } else {
109                 napi_throw_error(env, "401", "Parameter error. The type of Parameter must be ArrayBuffer or DataView.");
110                 return nullptr;
111             }
112         }
113         if (data) {
114             std::string strEnd(reinterpret_cast<char*>(data), len);
115             if (argc == 1) {
116                 object = new XmlPullParser(env, strEnd, "utf-8");
117             } else if (argc == 2) { // 2:When the input parameter is set to 2
118                 NAPI_CALL(env, napi_typeof(env, args[1], &valuetype));
119                 NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
120                 std::string strEncoding = "";
121                 XmlSerializer::DealNapiStrValue(env, args[1], strEncoding);
122                 object = new XmlPullParser(env, strEnd, strEncoding);
123             }
124         }
125         napi_status status = napi_wrap(env, thisVar, object,
126             [](napi_env env, void *data, void *hint) {
127                 auto obj = reinterpret_cast<XmlPullParser*>(data);
128                 if (obj != nullptr) {
129                     delete obj;
130                     obj = nullptr;
131                 }
132             }, nullptr, nullptr);
133         if (status != napi_ok && object != nullptr) {
134             HILOG_ERROR("XmlPullParserConstructor:: napi_wrap failed");
135             delete object;
136             object = nullptr;
137         }
138         return thisVar;
139     }
140 
SetAttributes(napi_env env,napi_callback_info info)141     static napi_value SetAttributes(napi_env env, napi_callback_info info)
142     {
143         napi_value thisVar = nullptr;
144         size_t argc = 2;
145         napi_value args[2] = { nullptr }; // 2:two args
146         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
147         NAPI_ASSERT(env, argc == 2, "Wrong number of arguments"); // 2: number of args
148         napi_valuetype valuetype = napi_null;
149         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
150         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type. string expected.");
151         NAPI_CALL(env, napi_typeof(env, args[1], &valuetype));
152         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type. string expected.");
153         XmlSerializer *object = nullptr;
154         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
155         std::string name;
156         std::string value;
157         XmlSerializer::DealNapiStrValue(env, args[0], name);
158         XmlSerializer::DealNapiStrValue(env, args[1], value);
159         object->SetAttributes(name, value);
160         napi_value result = nullptr;
161         NAPI_CALL(env, napi_get_undefined(env, &result));
162         return result;
163     }
164 
AddEmptyElement(napi_env env,napi_callback_info info)165     static napi_value AddEmptyElement(napi_env env, napi_callback_info info)
166     {
167         napi_value thisVar = nullptr;
168         size_t argc = 1;
169         napi_value args[1] = { 0 };
170         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
171         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments.");
172 
173         napi_valuetype valuetype;
174         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
175         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
176         XmlSerializer *object = nullptr;
177         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
178         std::string name;
179         object->DealNapiStrValue(env, args[0], name);
180         object->AddEmptyElement(name);
181 
182         napi_value result = nullptr;
183         NAPI_CALL(env, napi_get_undefined(env, &result));
184         return result;
185     }
186 
SetDeclaration(napi_env env,napi_callback_info info)187     static napi_value SetDeclaration(napi_env env, napi_callback_info info)
188     {
189         napi_value thisVar = nullptr;
190         NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
191         XmlSerializer *object = nullptr;
192         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
193         object->SetDeclaration();
194         napi_value result = nullptr;
195         NAPI_CALL(env, napi_get_undefined(env, &result));
196         return result;
197     }
198 
StartElement(napi_env env,napi_callback_info info)199     static napi_value StartElement(napi_env env, napi_callback_info info)
200     {
201         size_t argc = 1;
202         napi_value args[1] = { nullptr };
203         napi_value thisVar = nullptr;
204         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
205         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
206         XmlSerializer *object = nullptr;
207         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
208         std::string name;
209         object->DealNapiStrValue(env, args[0], name);
210         object->StartElement(name);
211         napi_value result = nullptr;
212         NAPI_CALL(env, napi_get_undefined(env, &result));
213         return result;
214     }
215 
EndElement(napi_env env,napi_callback_info info)216     static napi_value EndElement(napi_env env, napi_callback_info info)
217     {
218         napi_value thisVar = nullptr;
219         NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
220         XmlSerializer *object = nullptr;
221         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
222         object->EndElement();
223         napi_value result = nullptr;
224         NAPI_CALL(env, napi_get_undefined(env, &result));
225         return result;
226     }
227 
SetNamespace(napi_env env,napi_callback_info info)228     static napi_value SetNamespace(napi_env env, napi_callback_info info)
229     {
230         napi_value thisVar = nullptr;
231         size_t argc = 2;
232         napi_value args[2] = { nullptr }; // 2:two args
233         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
234         NAPI_ASSERT(env, argc == 2, "Wrong number of arguments"); // 2:two args
235         napi_valuetype valuetype = napi_null;
236         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
237         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
238         NAPI_CALL(env, napi_typeof(env, args[1], &valuetype));
239         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
240         XmlSerializer *object = nullptr;
241         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
242         std::string prefix;
243         std::string nsTemp;
244         XmlSerializer::DealNapiStrValue(env, args[0], prefix);
245         XmlSerializer::DealNapiStrValue(env, args[1], nsTemp);
246         object->SetNamespace(prefix, nsTemp);
247         napi_value result = nullptr;
248         NAPI_CALL(env, napi_get_undefined(env, &result));
249         return result;
250     }
251 
SetComment(napi_env env,napi_callback_info info)252     static napi_value SetComment(napi_env env, napi_callback_info info)
253     {
254         napi_value thisVar = nullptr;
255         size_t argc = 1;
256         napi_value args[1] = { nullptr };
257         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
258         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments.");
259         napi_valuetype valuetype = napi_null;
260         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
261         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
262         XmlSerializer *object = nullptr;
263         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
264         std::string comment;
265         object->DealNapiStrValue(env, args[0], comment);
266         object->SetComment(comment);
267         napi_value result = nullptr;
268         NAPI_CALL(env, napi_get_undefined(env, &result));
269         return result;
270     }
271 
SetCData(napi_env env,napi_callback_info info)272     static napi_value SetCData(napi_env env, napi_callback_info info)
273     {
274         napi_value thisVar = nullptr;
275         size_t argc = 1;
276         napi_value args[1] = { nullptr };
277         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
278         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
279         napi_valuetype valuetype = napi_null;
280         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
281         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
282         XmlSerializer *object = nullptr;
283         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
284         std::string data;
285         XmlSerializer::DealNapiStrValue(env, args[0], data);
286         object->SetCData(data);
287         napi_value result = nullptr;
288         NAPI_CALL(env, napi_get_undefined(env, &result));
289         return result;
290     }
291 
SetText(napi_env env,napi_callback_info info)292     static napi_value SetText(napi_env env, napi_callback_info info)
293     {
294         napi_value thisVar = nullptr;
295         size_t argc = 1;
296         napi_value args[1] = { nullptr };
297         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
298         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
299         napi_valuetype valuetype = napi_null;
300         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
301         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
302         XmlSerializer *object = nullptr;
303         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
304         std::string text;
305         XmlSerializer::DealNapiStrValue(env, args[0], text);
306         object->SetText(text);
307         napi_value result = nullptr;
308         NAPI_CALL(env, napi_get_undefined(env, &result));
309         return result;
310     }
311 
SetDocType(napi_env env,napi_callback_info info)312     static napi_value SetDocType(napi_env env, napi_callback_info info)
313     {
314         napi_value thisVar = nullptr;
315         size_t argc = 1;
316         napi_value args[1] = { nullptr };
317         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
318         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments");
319         napi_valuetype valuetype = napi_null;
320         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
321         NAPI_ASSERT(env, valuetype == napi_string, "Wrong argument type: string expected.");
322         XmlSerializer *object = nullptr;
323         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
324         std::string text;
325         XmlSerializer::DealNapiStrValue(env, args[0], text);
326         object->SetDocType(text);
327         napi_value result = nullptr;
328         NAPI_CALL(env, napi_get_undefined(env, &result));
329         return result;
330     }
XmlSerializerError(napi_env env,napi_callback_info info)331     static napi_value XmlSerializerError(napi_env env, napi_callback_info info)
332     {
333         napi_value thisVar = nullptr;
334         napi_value result = nullptr;
335         NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
336         XmlSerializer *object = nullptr;
337         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
338         std::string temp = object->XmlSerializerError();
339         size_t templen = temp.size();
340         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), templen, &result));
341         return result;
342     }
343 
XmlSerializerInit(napi_env env,napi_value exports)344     napi_value XmlSerializerInit(napi_env env, napi_value exports)
345     {
346         const char *xmlSerializerClass = "XmlSerializer";
347         napi_value xmlClass = nullptr;
348         napi_property_descriptor xmlDesc[] = {
349             DECLARE_NAPI_FUNCTION("setAttributes", SetAttributes),
350             DECLARE_NAPI_FUNCTION("addEmptyElement", AddEmptyElement),
351             DECLARE_NAPI_FUNCTION("setDeclaration", SetDeclaration),
352             DECLARE_NAPI_FUNCTION("startElement", StartElement),
353             DECLARE_NAPI_FUNCTION("endElement", EndElement),
354             DECLARE_NAPI_FUNCTION("setNamespace", SetNamespace),
355             DECLARE_NAPI_FUNCTION("setComment", SetComment),
356             DECLARE_NAPI_FUNCTION("setCDATA", SetCData),
357             DECLARE_NAPI_FUNCTION("setText", SetText),
358             DECLARE_NAPI_FUNCTION("setDocType", SetDocType),
359             DECLARE_NAPI_FUNCTION("XmlSerializerError", XmlSerializerError)
360         };
361         NAPI_CALL(env, napi_define_class(env, xmlSerializerClass, strlen(xmlSerializerClass), XmlSerializerConstructor,
362                                          nullptr, sizeof(xmlDesc) / sizeof(xmlDesc[0]), xmlDesc, &xmlClass));
363         napi_property_descriptor desc[] = {
364             DECLARE_NAPI_PROPERTY("XmlSerializer", xmlClass)
365         };
366         napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
367         return exports;
368     }
369 
Parse(napi_env env,napi_callback_info info)370     static napi_value Parse(napi_env env, napi_callback_info info)
371     {
372         napi_value thisVar = nullptr;
373         size_t argc = 1;
374         napi_value args[1] = { nullptr };
375         NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr));
376         NAPI_ASSERT(env, argc == 1, "Wrong number of arguments, one expected.");
377         napi_valuetype valuetype;
378         NAPI_CALL(env, napi_typeof(env, args[0], &valuetype));
379         NAPI_ASSERT(env, valuetype == napi_object, "Wrong argument type: object expected.");
380         XmlPullParser *object = nullptr;
381         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
382         object->DealOptionInfo(env, args[0]);
383         object->Parse(env, thisVar, true);
384         napi_value result = nullptr;
385         NAPI_CALL(env, napi_get_undefined(env, &result));
386         return result;
387     }
388 
ParseXml(napi_env env,napi_callback_info info)389     static napi_value ParseXml(napi_env env, napi_callback_info info)
390     {
391         napi_value thisVar = nullptr;
392         size_t argc = 1;
393         napi_value args[1] = { nullptr };
394         napi_get_cb_info(env, info, &argc, args, &thisVar, nullptr);
395         XmlPullParser *xmlPullParser = nullptr;
396         napi_unwrap(env, thisVar, reinterpret_cast<void**>(&xmlPullParser));
397         napi_value result = nullptr;
398         if (xmlPullParser == nullptr) {
399             ErrorHelper::ThrowError(env, ERROR_CODE, "Parameter error. Parameter verification failed.");
400             napi_get_boolean(env, false, &result);
401             return result;
402         }
403         xmlPullParser->DealOptionInfo(env, args[0]);
404         xmlPullParser->Parse(env, thisVar, false);
405         std::string errStr = xmlPullParser->XmlPullParserError();
406         napi_get_boolean(env, !errStr.empty(), &result);
407         return result;
408     }
409 
XmlPullParserError(napi_env env,napi_callback_info info)410     static napi_value XmlPullParserError(napi_env env, napi_callback_info info)
411     {
412         napi_value thisVar = nullptr;
413         napi_value result = nullptr;
414         NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
415         XmlPullParser *object = nullptr;
416         NAPI_CALL(env, napi_unwrap(env, thisVar, reinterpret_cast<void**>(&object)));
417         std::string temp = object->XmlPullParserError();
418         size_t templen = temp.size();
419         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), templen, &result));
420         return result;
421     }
422 
XmlPullParserInit(napi_env env,napi_value exports)423     napi_value XmlPullParserInit(napi_env env, napi_value exports)
424     {
425         const char *xmlPullParserClass = "XmlPullParser";
426         napi_value xmlClass = nullptr;
427         napi_property_descriptor xmlDesc[] = {
428             DECLARE_NAPI_FUNCTION("parse", Parse),
429             DECLARE_NAPI_FUNCTION("parseXml", ParseXml),
430             DECLARE_NAPI_FUNCTION("XmlPullParserError", XmlPullParserError)
431         };
432         NAPI_CALL(env, napi_define_class(env, xmlPullParserClass, strlen(xmlPullParserClass),
433             XmlPullParserConstructor, nullptr, sizeof(xmlDesc) / sizeof(xmlDesc[0]),
434             xmlDesc, &xmlClass));
435         napi_property_descriptor desc[] = {
436             DECLARE_NAPI_PROPERTY("XmlPullParser", xmlClass)
437         };
438         napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
439         return exports;
440     };
441 
Init(napi_env env,napi_value exports)442     static napi_value Init(napi_env env, napi_value exports)
443     {
444         XmlSerializerInit(env, exports);
445         XmlPullParserInit(env, exports);
446         return exports;
447     }
448 
449     extern "C"
NAPI_xml_GetJSCode(const char ** buf,int * bufLen)450     __attribute__((visibility("default"))) void NAPI_xml_GetJSCode(const char **buf, int *bufLen)
451     {
452         if (buf != nullptr) {
453             *buf = _binary_js_xml_js_start;
454         }
455 
456         if (bufLen != nullptr) {
457             *bufLen = _binary_js_xml_js_end - _binary_js_xml_js_start;
458         }
459     }
460     extern "C"
NAPI_xml_GetABCCode(const char ** buf,int * buflen)461     __attribute__((visibility("default"))) void NAPI_xml_GetABCCode(const char** buf, int* buflen)
462     {
463         if (buf != nullptr) {
464             *buf = _binary_xml_abc_start;
465         }
466         if (buflen != nullptr) {
467             *buflen = _binary_xml_abc_end - _binary_xml_abc_start;
468         }
469     }
470 
471 
472     static napi_module_with_js xmlModule = {
473         .nm_version = 1,
474         .nm_flags = 0,
475         .nm_filename = nullptr,
476         .nm_register_func = Init,
477         .nm_modname = "xml",
478         .nm_priv = reinterpret_cast<void*>(0),
479         .nm_get_abc_code = NAPI_xml_GetABCCode,
480         .nm_get_js_code = NAPI_xml_GetJSCode,
481     };
XmlRegisterModule()482     extern "C" __attribute__((constructor)) void XmlRegisterModule()
483     {
484         napi_module_with_js_register(&xmlModule);
485     }
486 } // namespace OHOS::Xml
487