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 "tooling/base/pt_json.h"
17
18#include "libpandabase/macros.h"
19
20namespace panda::ecmascript::tooling {
21std::unique_ptr<PtJson> PtJson::CreateObject()
22{
23    return std::make_unique<PtJson>(cJSON_CreateObject());
24}
25
26std::unique_ptr<PtJson> PtJson::CreateArray()
27{
28    return std::make_unique<PtJson>(cJSON_CreateArray());
29}
30
31void PtJson::ReleaseRoot()
32{
33    if (object_ != nullptr) {
34        cJSON_Delete(object_);
35        object_ = nullptr;
36    }
37}
38
39std::unique_ptr<PtJson> PtJson::Parse(const std::string &data)
40{
41    cJSON *value = cJSON_ParseWithOpts(data.c_str(), nullptr, true);
42    return std::make_unique<PtJson>(value);
43}
44
45std::string PtJson::Stringify() const
46{
47    if (object_ == nullptr) {
48        return "";
49    }
50
51    char *str = cJSON_PrintUnformatted(object_);
52    if (str == nullptr) {
53        return "";
54    }
55
56    std::string result(str);
57    cJSON_free(str);
58    return result;
59}
60
61bool PtJson::Add(const char *key, bool value) const
62{
63    ASSERT(key != nullptr && !Contains(key));
64
65    cJSON *node = cJSON_CreateBool(value);
66    if (node == nullptr) {
67        return false;
68    }
69
70    cJSON_bool ret = cJSON_AddItemToObject(object_, key, node);
71    if (ret == 0) {
72        cJSON_Delete(node);
73        return false;
74    }
75
76    return true;
77}
78
79bool PtJson::Add(const char *key, int32_t value) const
80{
81    return Add(key, static_cast<double>(value));
82}
83
84bool PtJson::Add(const char *key, int64_t value) const
85{
86    return Add(key, static_cast<double>(value));
87}
88
89bool PtJson::Add(const char *key, uint32_t value) const
90{
91    return Add(key, static_cast<double>(value));
92}
93
94bool PtJson::Add(const char *key, double value) const
95{
96    ASSERT(key != nullptr && !Contains(key));
97
98    cJSON *node = cJSON_CreateNumber(value);
99    if (node == nullptr) {
100        return false;
101    }
102
103    cJSON_bool ret = cJSON_AddItemToObject(object_, key, node);
104    if (ret == 0) {
105        cJSON_Delete(node);
106        return false;
107    }
108
109    return true;
110}
111
112bool PtJson::Add(const char *key, const char *value) const
113{
114    ASSERT(key != nullptr && !Contains(key));
115
116    cJSON *node = cJSON_CreateString(value);
117    if (node == nullptr) {
118        return false;
119    }
120
121    cJSON_bool ret = cJSON_AddItemToObject(object_, key, node);
122    if (ret == 0) {
123        cJSON_Delete(node);
124        return false;
125    }
126
127    return true;
128}
129
130bool PtJson::Add(const char *key, const std::unique_ptr<PtJson> &value) const
131{
132    ASSERT(key != nullptr && !Contains(key));
133
134    cJSON *node = value->GetJson();
135    if (node == nullptr) {
136        return false;
137    }
138
139    cJSON_bool ret = cJSON_AddItemToObject(object_, key, node);
140    if (ret == 0) {
141        return false;
142    }
143
144    return true;
145}
146
147bool PtJson::Push(bool value) const
148{
149    cJSON *node = cJSON_CreateBool(value);
150    if (node == nullptr) {
151        return false;
152    }
153
154    cJSON_bool ret = cJSON_AddItemToArray(object_, node);
155    if (ret == 0) {
156        cJSON_Delete(node);
157        return false;
158    }
159
160    return true;
161}
162
163bool PtJson::Push(int32_t value) const
164{
165    return Push(static_cast<double>(value));
166}
167
168bool PtJson::Push(int64_t value) const
169{
170    return Push(static_cast<double>(value));
171}
172
173bool PtJson::Push(uint32_t value) const
174{
175    return Push(static_cast<double>(value));
176}
177
178bool PtJson::Push(double value) const
179{
180    cJSON *node = cJSON_CreateNumber(value);
181    if (node == nullptr) {
182        return false;
183    }
184
185    cJSON_bool ret = cJSON_AddItemToArray(object_, node);
186    if (ret == 0) {
187        cJSON_Delete(node);
188        return false;
189    }
190
191    return true;
192}
193
194bool PtJson::Push(const char *value) const
195{
196    cJSON *node = cJSON_CreateString(value);
197    if (node == nullptr) {
198        return false;
199    }
200
201    cJSON_bool ret = cJSON_AddItemToArray(object_, node);
202    if (ret == 0) {
203        cJSON_Delete(node);
204        return false;
205    }
206
207    return true;
208}
209
210bool PtJson::Push(const std::unique_ptr<PtJson> &value) const
211{
212    if (value == nullptr) {
213        return false;
214    }
215
216    cJSON *node = value->GetJson();
217    if (node == nullptr) {
218        return false;
219    }
220
221    cJSON_bool ret = cJSON_AddItemToArray(object_, node);
222    if (ret == 0) {
223        return false;
224    }
225
226    return true;
227}
228
229bool PtJson::Remove(const char *key) const
230{
231    ASSERT(key != nullptr && Contains(key));
232
233    cJSON_DeleteItemFromObject(object_, key);
234    return true;
235}
236
237bool PtJson::Contains(const char *key) const
238{
239    cJSON *node = cJSON_GetObjectItemCaseSensitive(object_, key);
240    return node != nullptr;
241}
242
243std::string PtJson::GetKey() const
244{
245    if (object_ == nullptr || object_->string == nullptr) {
246        return "";
247    }
248
249    return std::string(object_->string);
250}
251
252cJSON *PtJson::GetJson() const
253{
254    return object_;
255}
256
257bool PtJson::IsBool() const
258{
259    return cJSON_IsBool(object_) != 0;
260}
261
262bool PtJson::IsNumber() const
263{
264    return cJSON_IsNumber(object_) != 0;
265}
266
267bool PtJson::IsString() const
268{
269    return cJSON_IsString(object_) != 0;
270}
271
272bool PtJson::IsObject() const
273{
274    return cJSON_IsObject(object_) != 0;
275}
276
277bool PtJson::IsArray() const
278{
279    return cJSON_IsArray(object_) != 0;
280}
281
282bool PtJson::IsNull() const
283{
284    return cJSON_IsNull(object_) != 0;
285}
286
287bool PtJson::GetBool(bool defaultValue) const
288{
289    if (!IsBool()) {
290        return defaultValue;
291    }
292
293    return cJSON_IsTrue(object_) != 0;
294}
295
296int32_t PtJson::GetInt(int32_t defaultValue) const
297{
298    if (!IsNumber()) {
299        return defaultValue;
300    }
301
302    return static_cast<int32_t>(object_->valuedouble);
303}
304
305int64_t PtJson::GetInt64(int64_t defaultValue) const
306{
307    if (!IsNumber()) {
308        return defaultValue;
309    }
310
311    return static_cast<int64_t>(object_->valuedouble);
312}
313
314uint32_t PtJson::GetUInt(uint32_t defaultValue) const
315{
316    if (!IsNumber()) {
317        return defaultValue;
318    }
319
320    return static_cast<uint32_t>(object_->valuedouble);
321}
322
323uint64_t PtJson::GetUInt64(uint64_t defaultValue) const
324{
325    if (!IsNumber()) {
326        return defaultValue;
327    }
328
329    return static_cast<uint64_t>(object_->valuedouble);
330}
331
332double PtJson::GetDouble(double defaultValue) const
333{
334    if (!IsNumber()) {
335        return defaultValue;
336    }
337
338    return object_->valuedouble;
339}
340
341std::string PtJson::GetString() const
342{
343    if (!IsString()) {
344        return "";
345    }
346
347    return std::string(object_->valuestring);
348}
349
350int32_t PtJson::GetSize() const
351{
352    return cJSON_GetArraySize(object_);
353}
354
355std::unique_ptr<PtJson> PtJson::Get(int32_t index) const
356{
357    return std::make_unique<PtJson>(cJSON_GetArrayItem(object_, index));
358}
359
360Result PtJson::GetBool(const char *key, bool *value) const
361{
362    cJSON *item = cJSON_GetObjectItem(object_, key);
363    if (item == nullptr) {
364        return Result::NOT_EXIST;
365    }
366    if (cJSON_IsBool(item) == 0) {
367        return Result::TYPE_ERROR;
368    }
369
370    *value = cJSON_IsTrue(item) != 0;
371    return Result::SUCCESS;
372}
373
374Result PtJson::GetInt(const char *key, int32_t *value) const
375{
376    double result;
377    Result ret = GetDouble(key, &result);
378    if (ret == Result::SUCCESS) {
379        *value = static_cast<int32_t>(result);
380    }
381    return ret;
382}
383
384Result PtJson::GetInt64(const char *key, int64_t *value) const
385{
386    double result;
387    Result ret = GetDouble(key, &result);
388    if (ret == Result::SUCCESS) {
389        *value = static_cast<int64_t>(result);
390    }
391    return ret;
392}
393
394Result PtJson::GetUInt(const char *key, uint32_t *value) const
395{
396    double result;
397    Result ret = GetDouble(key, &result);
398    if (ret == Result::SUCCESS) {
399        *value = static_cast<uint32_t>(result);
400    }
401    return ret;
402}
403
404Result PtJson::GetUInt64(const char *key, uint64_t *value) const
405{
406    double result;
407    Result ret = GetDouble(key, &result);
408    if (ret == Result::SUCCESS) {
409        *value = static_cast<uint64_t>(result);
410    }
411    return ret;
412}
413
414Result PtJson::GetDouble(const char *key, double *value) const
415{
416    cJSON *item = cJSON_GetObjectItem(object_, key);
417    if (item == nullptr) {
418        return Result::NOT_EXIST;
419    }
420    if (cJSON_IsNumber(item) == 0) {
421        return Result::TYPE_ERROR;
422    }
423
424    *value = item->valuedouble;
425    return Result::SUCCESS;
426}
427
428Result PtJson::GetString(const char *key, std::string *value) const
429{
430    cJSON *item = cJSON_GetObjectItem(object_, key);
431    if (item == nullptr) {
432        return Result::NOT_EXIST;
433    }
434    if (cJSON_IsString(item) == 0) {
435        return Result::TYPE_ERROR;
436    }
437
438    *value = item->valuestring;
439    return Result::SUCCESS;
440}
441
442Result PtJson::GetObject(const char *key, std::unique_ptr<PtJson> *value) const
443{
444    cJSON *item = cJSON_GetObjectItem(object_, key);
445    if (item == nullptr) {
446        return Result::NOT_EXIST;
447    }
448    if (cJSON_IsObject(item) == 0) {
449        return Result::TYPE_ERROR;
450    }
451
452    *value = std::make_unique<PtJson>(item);
453    return Result::SUCCESS;
454}
455
456Result PtJson::GetArray(const char *key, std::unique_ptr<PtJson> *value) const
457{
458    cJSON *item = cJSON_GetObjectItem(object_, key);
459    if (item == nullptr) {
460        return Result::NOT_EXIST;
461    }
462    if (cJSON_IsArray(item) == 0) {
463        return Result::TYPE_ERROR;
464    }
465
466    *value = std::make_unique<PtJson>(item);
467    return Result::SUCCESS;
468}
469
470Result PtJson::GetAny(const char *key, std::unique_ptr<PtJson> *value) const
471{
472    cJSON *item = cJSON_GetObjectItem(object_, key);
473    if (item == nullptr) {
474        return Result::NOT_EXIST;
475    }
476
477    *value = std::make_unique<PtJson>(item);
478    return Result::SUCCESS;
479}
480}  // namespace panda::ecmascript
481