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