• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 2023 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 "json_object.h"
17 
18 #include <algorithm>
19 #include <cmath>
20 #include <queue>
21 
22 #include "doc_errno.h"
23 #include "log_print.h"
24 
25 namespace DocumentDB {
26 namespace {
IsNumber(const std::string & str)27 bool IsNumber(const std::string &str)
28 {
29     return std::all_of(str.begin(), str.end(), [](char c) {
30         return std::isdigit(c);
31     });
32 }
33 } // namespace
34 
ValueObject(bool val)35 ValueObject::ValueObject(bool val)
36 {
37     valueType = ValueType::VALUE_BOOL;
38     boolValue = val;
39 }
40 
ValueObject(double val)41 ValueObject::ValueObject(double val)
42 {
43     valueType = ValueType::VALUE_NUMBER;
44     doubleValue = val;
45 }
46 
ValueObject(const char * val)47 ValueObject::ValueObject(const char *val)
48 {
49     valueType = ValueType::VALUE_STRING;
50     stringValue = val;
51 }
52 
GetValueType() const53 ValueObject::ValueType ValueObject::GetValueType() const
54 {
55     return valueType;
56 }
57 
GetBoolValue() const58 bool ValueObject::GetBoolValue() const
59 {
60     return boolValue;
61 }
62 
GetIntValue() const63 int64_t ValueObject::GetIntValue() const
64 {
65     return static_cast<int64_t>(std::llround(doubleValue));
66 }
67 
GetDoubleValue() const68 double ValueObject::GetDoubleValue() const
69 {
70     return doubleValue;
71 }
72 
GetStringValue() const73 std::string ValueObject::GetStringValue() const
74 {
75     return stringValue;
76 }
77 
Parse(const std::string & jsonStr,int & errCode,bool caseSensitive,bool isFilter)78 JsonObject JsonObject::Parse(const std::string &jsonStr, int &errCode, bool caseSensitive, bool isFilter)
79 {
80     JsonObject obj;
81     errCode = obj.Init(jsonStr, isFilter);
82     obj.caseSensitive_ = caseSensitive;
83     return obj;
84 }
85 
JsonObject()86 JsonObject::JsonObject()
87 {
88     cjson_ = nullptr;
89 }
90 
~JsonObject()91 JsonObject::~JsonObject()
92 {
93     if (isOwner_) {
94         cJSON_Delete(cjson_);
95     }
96 }
97 
operator ==(const JsonObject & other) const98 bool JsonObject::operator==(const JsonObject &other) const
99 {
100     return (cJSON_Compare(this->cjson_, other.cjson_, true) != 0); // CaseSensitive
101 }
102 
IsNull() const103 bool JsonObject::IsNull() const
104 {
105     return (cjson_ == nullptr);
106 }
107 
GetType() const108 JsonObject::Type JsonObject::GetType() const
109 {
110     if (cjson_->type == cJSON_Object) {
111         return JsonObject::Type::JSON_OBJECT;
112     } else if (cjson_->type == cJSON_Array) {
113         return JsonObject::Type::JSON_ARRAY;
114     }
115     return JsonObject::Type::JSON_LEAF;
116 }
117 
GetDeep()118 int JsonObject::GetDeep()
119 {
120     if (cjson_ == nullptr) {
121         GLOGE("cJson is nullptr,deep is 0");
122         return 0;
123     }
124     if (jsonDeep_ != 0) {
125         return jsonDeep_;
126     }
127     jsonDeep_ = GetDeep(cjson_);
128     return jsonDeep_;
129 }
130 
GetDeep(cJSON * cjson)131 int JsonObject::GetDeep(cJSON *cjson)
132 {
133     if (cjson->child == nullptr) {
134         jsonDeep_ = 0;
135         return 0; // leaf node
136     }
137 
138     int depth = -1;
139     cJSON *child = cjson->child;
140     while (child != nullptr) {
141         depth = std::max(depth, GetDeep(child) + 1);
142         child = child->next;
143     }
144     jsonDeep_ = depth;
145     return depth;
146 }
147 
CheckNumber(cJSON * item)148 int JsonObject::CheckNumber(cJSON *item)
149 {
150     std::queue<cJSON *> cjsonQueue;
151     cjsonQueue.push(item);
152     while (!cjsonQueue.empty()) {
153         cJSON *node = cjsonQueue.front();
154         cjsonQueue.pop();
155         if (node == nullptr) {
156             return -E_INVALID_ARGS;
157         }
158         if (cJSON_IsNumber(node)) { // node is not null all the time
159             double value = cJSON_GetNumberValue(node);
160             if (value > __DBL_MAX__ || value < -__DBL_MAX__) {
161                 return -E_INVALID_ARGS;
162             }
163         }
164         if (node->child != nullptr) {
165             cjsonQueue.push(node->child);
166         }
167         if (node->next != nullptr) {
168             cjsonQueue.push(node->next);
169         }
170     }
171     return E_OK;
172 }
173 
Init(const std::string & str,bool isFilter)174 int JsonObject::Init(const std::string &str, bool isFilter)
175 {
176     const char *end = NULL;
177     isOwner_ = true;
178     cjson_ = cJSON_ParseWithOpts(str.c_str(), &end, true);
179     if (cjson_ == nullptr) {
180         GLOGE("Json's format is wrong");
181         return -E_INVALID_JSON_FORMAT;
182     }
183 
184     if (cjson_->type != cJSON_Object) {
185         GLOGE("after Parse,cjson_'s type is not cJSON_Object");
186         return -E_INVALID_ARGS;
187     }
188 
189     int ret = CheckNumber(cjson_);
190     if (ret == -E_INVALID_ARGS) {
191         GLOGE("Int value is larger than double");
192         return -E_INVALID_ARGS;
193     }
194     if (!isFilter) {
195         bool isFirstFloor = true;
196         ret = CheckJsonRepeatField(cjson_, isFirstFloor);
197         if (ret != E_OK) {
198             return ret;
199         }
200     }
201     return E_OK;
202 }
203 
CheckJsonRepeatField(cJSON * object,bool isFirstFloor)204 int JsonObject::CheckJsonRepeatField(cJSON *object, bool isFirstFloor)
205 {
206     if (object == nullptr) {
207         return -E_INVALID_ARGS;
208     }
209     int ret = E_OK;
210     int type = object->type;
211     if (type != cJSON_Object && type != cJSON_Array) {
212         return ret;
213     }
214     std::set<std::string> fieldSet;
215     cJSON *subObj = object->child;
216     while (subObj != nullptr) {
217         ret = CheckSubObj(fieldSet, subObj, type, isFirstFloor);
218         if (ret != E_OK) {
219             break;
220         }
221         subObj = subObj->next;
222     }
223     return ret;
224 }
225 
IsFieldNameLegal(const std::string & fieldName)226 bool IsFieldNameLegal(const std::string &fieldName)
227 {
228     for (auto oneChar : fieldName) {
229         if (!((isalpha(oneChar)) || (isdigit(oneChar)) || (oneChar == '_'))) {
230             return false;
231         }
232     }
233     return true;
234 }
235 
CheckSubObj(std::set<std::string> & fieldSet,cJSON * subObj,int parentType,bool isFirstFloor)236 int JsonObject::CheckSubObj(std::set<std::string> &fieldSet, cJSON *subObj, int parentType, bool isFirstFloor)
237 {
238     if (subObj == nullptr) {
239         return -E_INVALID_ARGS;
240     }
241     std::string fieldName;
242     if (subObj->string != nullptr) {
243         fieldName = subObj->string;
244         if (!isFirstFloor) {
245             if (!IsFieldNameLegal(fieldName)) {
246                 return -E_INVALID_ARGS;
247             }
248         }
249         if (!fieldName.empty() && isdigit(fieldName[0])) {
250             return -E_INVALID_ARGS;
251         }
252     }
253     isFirstFloor = false;
254     if (parentType == cJSON_Array) {
255         return CheckJsonRepeatField(subObj, isFirstFloor);
256     }
257     if (fieldName.empty()) {
258         return -E_INVALID_JSON_FORMAT;
259     }
260     if (fieldSet.find(fieldName) == fieldSet.end()) {
261         fieldSet.insert(fieldName);
262     } else {
263         return -E_INVALID_JSON_FORMAT;
264     }
265     return CheckJsonRepeatField(subObj, isFirstFloor);
266 }
267 
Print() const268 std::string JsonObject::Print() const
269 {
270     if (cjson_ == nullptr) {
271         return "";
272     }
273     char *ret = cJSON_PrintUnformatted(cjson_);
274     std::string str = (ret == nullptr ? "" : ret);
275     cJSON_free(ret);
276     return str;
277 }
278 
GetObjectItem(const std::string & field,int & errCode)279 JsonObject JsonObject::GetObjectItem(const std::string &field, int &errCode)
280 {
281     if (cjson_ == nullptr || cjson_->type != cJSON_Object) {
282         errCode = -E_INVALID_ARGS;
283         return JsonObject();
284     }
285 
286     JsonObject item;
287     item.caseSensitive_ = caseSensitive_;
288     if (caseSensitive_) {
289         item.cjson_ = cJSON_GetObjectItemCaseSensitive(cjson_, field.c_str());
290     } else {
291         item.cjson_ = cJSON_GetObjectItem(cjson_, field.c_str());
292     }
293     if (item.cjson_ == nullptr) {
294         errCode = -E_NOT_FOUND;
295     }
296     return item;
297 }
298 
GetNext() const299 JsonObject JsonObject::GetNext() const
300 {
301     if (cjson_ == nullptr) {
302         return JsonObject();
303     }
304     JsonObject next;
305     next.caseSensitive_ = caseSensitive_;
306     if (cjson_->next == nullptr) {
307         return JsonObject();
308     }
309     next.cjson_ = cjson_->next;
310     return next;
311 }
312 
GetChild() const313 JsonObject JsonObject::GetChild() const
314 {
315     if (cjson_ == nullptr) {
316         return JsonObject();
317     }
318     JsonObject child;
319     child.caseSensitive_ = caseSensitive_;
320     if (cjson_->child == nullptr) {
321         return JsonObject();
322     }
323     child.cjson_ = cjson_->child;
324     return child;
325 }
326 
DeleteItemFromObject(const std::string & field)327 int JsonObject::DeleteItemFromObject(const std::string &field)
328 {
329     if (field.empty()) {
330         return E_OK;
331     }
332     cJSON_DeleteItemFromObjectCaseSensitive(cjson_, field.c_str());
333     return E_OK;
334 }
335 
AddItemToObject(const std::string & fieldName,const JsonObject & item)336 int JsonObject::AddItemToObject(const std::string &fieldName, const JsonObject &item)
337 {
338     if (cjson_ == nullptr) {
339         return -E_ERROR;
340     }
341 
342     if (item.IsNull()) {
343         GLOGD("Add null object.");
344         return E_OK;
345     }
346     if (cjson_->type == cJSON_Array) {
347         int n = 0;
348         cJSON *child = cjson_->child;
349         while (child != nullptr) {
350             child = child->next;
351             n++;
352         }
353         if (IsNumber(fieldName) && n <= std::stoi(fieldName)) {
354             GLOGE("Add item object to array over size.");
355             return -E_NO_DATA;
356         }
357     }
358     if (cjson_->type != cJSON_Object) {
359         GLOGE("type conflict.");
360         return -E_DATA_CONFLICT;
361     }
362     cJSON *cpoyItem = cJSON_Duplicate(item.cjson_, true);
363     cJSON_AddItemToObject(cjson_, fieldName.c_str(), cpoyItem);
364     return E_OK;
365 }
366 
AddItemToObject(const std::string & fieldName)367 int JsonObject::AddItemToObject(const std::string &fieldName)
368 {
369     if (cjson_->type == cJSON_Array) {
370         int n = 0;
371         cJSON *child = cjson_->child;
372         while (child != nullptr) {
373             child = child->next;
374             n++;
375         }
376         if (IsNumber(fieldName) && n <= std::stoi(fieldName)) {
377             GLOGE("Add item object to array over size.");
378             return -E_NO_DATA;
379         }
380     }
381     if (cjson_->type != cJSON_Object) {
382         GLOGE("type conflict.");
383         return -E_DATA_CONFLICT;
384     }
385     cJSON *emptyitem = cJSON_CreateObject();
386     cJSON_AddItemToObject(cjson_, fieldName.c_str(), emptyitem);
387     return E_OK;
388 }
389 
GetItemValue() const390 ValueObject JsonObject::GetItemValue() const
391 {
392     if (cjson_ == nullptr) {
393         return ValueObject();
394     }
395     ValueObject value;
396     switch (cjson_->type) {
397         case cJSON_False:
398         case cJSON_True:
399             return ValueObject(cjson_->type == cJSON_True);
400         case cJSON_NULL:
401             return ValueObject();
402         case cJSON_Number:
403             return ValueObject(cjson_->valuedouble);
404         case cJSON_String:
405             return ValueObject(cjson_->valuestring);
406         case cJSON_Array:
407         case cJSON_Object:
408         default:
409             GLOGW("Invalid json type: %d", cjson_->type);
410             break;
411     }
412 
413     return value;
414 }
415 
ReplaceItemInObject(const std::string & fieldName,const JsonObject & newItem,int & errCode)416 void JsonObject::ReplaceItemInObject(const std::string &fieldName, const JsonObject &newItem, int &errCode)
417 {
418     if (!newItem.IsNull() || !this->IsNull()) {
419         if (this->GetType() == JsonObject::Type::JSON_OBJECT) {
420             if (!(this->GetObjectItem(fieldName.c_str(), errCode).IsNull())) {
421                 cJSON *copyItem = cJSON_Duplicate(newItem.cjson_, true);
422                 cJSON_ReplaceItemInObjectCaseSensitive(this->cjson_, fieldName.c_str(), copyItem);
423             } else {
424                 cJSON *copyItem = cJSON_Duplicate(newItem.cjson_, true);
425                 cJSON_AddItemToObject(this->cjson_, fieldName.c_str(), copyItem);
426             }
427         }
428     }
429 }
430 
ReplaceItemInArray(const int & index,const JsonObject & newItem,int & errCode)431 void JsonObject::ReplaceItemInArray(const int &index, const JsonObject &newItem, int &errCode)
432 {
433     if (!newItem.IsNull() || !this->IsNull()) {
434         if (this->GetType() == JsonObject::Type::JSON_ARRAY) {
435             cJSON *copyItem = cJSON_Duplicate(newItem.cjson_, true);
436             cJSON_ReplaceItemInArray(this->cjson_, index, copyItem);
437         }
438     }
439 }
440 
InsertItemObject(int which,const JsonObject & newItem)441 int JsonObject::InsertItemObject(int which, const JsonObject &newItem)
442 {
443     if (cjson_ == nullptr) {
444         return E_OK;
445     }
446     if (newItem.IsNull()) {
447         GLOGD("Add null object.");
448         return E_OK;
449     }
450     cJSON *cpoyItem = cJSON_Duplicate(newItem.cjson_, true);
451     cJSON_InsertItemInArray(cjson_, which, cpoyItem);
452     return E_OK;
453 }
454 
GetItemField() const455 std::string JsonObject::GetItemField() const
456 {
457     if (cjson_ == nullptr) {
458         return "";
459     }
460 
461     if (cjson_->string == nullptr) {
462         cJSON *tail = cjson_;
463         while (tail->next != nullptr) {
464             tail = tail->next;
465         }
466 
467         int index = 0;
468         cJSON *head = cjson_;
469         while (head->prev != tail) {
470             head = head->prev;
471             index++;
472         }
473         return std::to_string(index);
474     } else {
475         return cjson_->string;
476     }
477 }
478 
GetItemField(int & errCode) const479 std::string JsonObject::GetItemField(int &errCode) const
480 {
481     if (cjson_ == nullptr || cjson_->string == nullptr) {
482         errCode = E_INVALID_ARGS;
483         return "";
484     }
485     errCode = E_OK;
486     return cjson_->string;
487 }
488 
GetChild(cJSON * cjson,const std::string & field,bool caseSens)489 cJSON *GetChild(cJSON *cjson, const std::string &field, bool caseSens)
490 {
491     if (cjson->type == cJSON_Object) {
492         if (caseSens) {
493             return cJSON_GetObjectItemCaseSensitive(cjson, field.c_str());
494         } else {
495             return cJSON_GetObjectItem(cjson, field.c_str());
496         }
497     } else if (cjson->type == cJSON_Array) {
498         if (!IsNumber(field)) {
499             GLOGW("Invalid json field path, expect array index.");
500             return nullptr;
501         }
502         return cJSON_GetArrayItem(cjson, std::stoi(field));
503     }
504 
505     GLOGW("Invalid json field type, expect object or array.");
506     return nullptr;
507 }
508 
GetChildPowerMode(cJSON * cjson,const std::string & field,bool caseSens)509 cJSON *GetChildPowerMode(cJSON *cjson, const std::string &field, bool caseSens)
510 {
511     if (cjson->type != cJSON_Object && cjson->type != cJSON_Array) {
512         GLOGW("Invalid json field type, expect object or array.");
513         return nullptr;
514     } else if (cjson->type == cJSON_Object) {
515         if (caseSens) {
516             return cJSON_GetObjectItemCaseSensitive(cjson, field.c_str());
517         } else {
518             return cJSON_GetObjectItem(cjson, field.c_str());
519         }
520     }
521 
522     // type is cJSON_Array
523     if (!IsNumber(field)) {
524         cjson = cjson->child;
525         while (cjson != nullptr) {
526             cJSON *resultItem = GetChild(cjson, field, caseSens);
527             if (resultItem != nullptr) {
528                 return resultItem;
529             }
530             cjson = cjson->next;
531         }
532         return nullptr;
533     }
534     return cJSON_GetArrayItem(cjson, std::stoi(field));
535 }
536 
MoveToPath(cJSON * cjson,const JsonFieldPath & jsonPath,bool caseSens)537 cJSON *MoveToPath(cJSON *cjson, const JsonFieldPath &jsonPath, bool caseSens)
538 {
539     for (const auto &field : jsonPath) {
540         cjson = GetChild(cjson, field, caseSens);
541         if (cjson == nullptr) {
542             break;
543         }
544     }
545     return cjson;
546 }
547 
MoveToPathPowerMode(cJSON * cjson,const JsonFieldPath & jsonPath,bool caseSens)548 cJSON *MoveToPathPowerMode(cJSON *cjson, const JsonFieldPath &jsonPath, bool caseSens)
549 {
550     for (const auto &field : jsonPath) {
551         cjson = GetChildPowerMode(cjson, field, caseSens);
552         if (cjson == nullptr) {
553             break;
554         }
555     }
556     return cjson;
557 }
558 
IsFieldExists(const JsonFieldPath & jsonPath) const559 bool JsonObject::IsFieldExists(const JsonFieldPath &jsonPath) const
560 {
561     return (MoveToPath(cjson_, jsonPath, caseSensitive_) != nullptr);
562 }
563 
IsFieldExistsPowerMode(const JsonFieldPath & jsonPath) const564 bool JsonObject::IsFieldExistsPowerMode(const JsonFieldPath &jsonPath) const
565 {
566     return (MoveToPathPowerMode(cjson_, jsonPath, caseSensitive_) != nullptr);
567 }
568 
FindItem(const JsonFieldPath & jsonPath,int & errCode) const569 JsonObject JsonObject::FindItem(const JsonFieldPath &jsonPath, int &errCode) const
570 {
571     if (jsonPath.empty()) {
572         JsonObject curr = JsonObject();
573         curr.cjson_ = cjson_;
574         curr.caseSensitive_ = caseSensitive_;
575         curr.isOwner_ = false;
576         return curr;
577     }
578 
579     cJSON *findItem = MoveToPath(cjson_, jsonPath, caseSensitive_);
580     if (findItem == nullptr) {
581         GLOGE("Find item failed. json field path not found.");
582         errCode = -E_JSON_PATH_NOT_EXISTS;
583         return {};
584     }
585 
586     JsonObject item;
587     item.caseSensitive_ = caseSensitive_;
588     item.cjson_ = findItem;
589     return item;
590 }
591 
592 // Compared with the non-powerMode mode, the node found by this function is an Array, and target is an object,
593 // if the Array contains the same object as the target, it can match this object in this mode.
FindItemPowerMode(const JsonFieldPath & jsonPath,int & errCode) const594 JsonObject JsonObject::FindItemPowerMode(const JsonFieldPath &jsonPath, int &errCode) const
595 {
596     if (jsonPath.empty()) {
597         JsonObject curr = JsonObject();
598         curr.cjson_ = cjson_;
599         curr.caseSensitive_ = caseSensitive_;
600         curr.isOwner_ = false;
601         return curr;
602     }
603 
604     cJSON *findItem = MoveToPathPowerMode(cjson_, jsonPath, caseSensitive_);
605     if (findItem == nullptr) {
606         GLOGE("Find item failed. json field path not found.");
607         errCode = -E_JSON_PATH_NOT_EXISTS;
608         return {};
609     }
610     JsonObject item;
611     item.caseSensitive_ = caseSensitive_;
612     item.cjson_ = findItem;
613     return item;
614 }
615 
GetObjectByPath(const JsonFieldPath & jsonPath,int & errCode) const616 ValueObject JsonObject::GetObjectByPath(const JsonFieldPath &jsonPath, int &errCode) const
617 {
618     JsonObject objGot = FindItem(jsonPath, errCode);
619     if (errCode != E_OK) {
620         GLOGE("Get json value object failed. %d", errCode);
621         return {};
622     }
623     return objGot.GetItemValue();
624 }
625 
DeleteItemDeeplyOnTarget(const JsonFieldPath & path)626 int JsonObject::DeleteItemDeeplyOnTarget(const JsonFieldPath &path)
627 {
628     if (path.empty()) {
629         return -E_INVALID_ARGS;
630     }
631 
632     std::string fieldName = path.back();
633     JsonFieldPath patherPath = path;
634     patherPath.pop_back();
635 
636     cJSON *nodeFather = MoveToPath(cjson_, patherPath, caseSensitive_);
637     if (nodeFather == nullptr) {
638         return -E_JSON_PATH_NOT_EXISTS;
639     }
640 
641     if (nodeFather->type == cJSON_Object) {
642         if (caseSensitive_) {
643             cJSON_DeleteItemFromObjectCaseSensitive(nodeFather, fieldName.c_str());
644             if (nodeFather->child == nullptr && path.size() > 1) {
645                 JsonFieldPath fatherPath(path.begin(), path.end() - 1);
646                 DeleteItemDeeplyOnTarget(fatherPath);
647             }
648         } else {
649             cJSON_DeleteItemFromObject(nodeFather, fieldName.c_str());
650             if (nodeFather->child == nullptr && path.size() > 1) {
651                 JsonFieldPath fatherPath(path.begin(), path.end() - 1);
652                 DeleteItemDeeplyOnTarget(fatherPath);
653             }
654         }
655     } else if (nodeFather->type == cJSON_Array) {
656         if (!IsNumber(fieldName)) {
657             GLOGW("Invalid json field path, expect array index.");
658             return -E_JSON_PATH_NOT_EXISTS;
659         }
660         cJSON_DeleteItemFromArray(nodeFather, std::stoi(fieldName));
661         if (nodeFather->child == nullptr && path.size() > 1) {
662             JsonFieldPath fatherPath(path.begin(), path.end() - 1);
663             DeleteItemDeeplyOnTarget(fatherPath);
664         }
665     }
666 
667     return E_OK;
668 }
669 } // namespace DocumentDB
670