1 | /* |
2 | * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
5 | * You may not use this file except in compliance with the License. |
6 | * A copy of the License is located at |
7 | * |
8 | * http://aws.amazon.com/apache2.0 |
9 | * |
10 | * or in the "license" file accompanying this file. This file is distributed |
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
12 | * express or implied. See the License for the specific language governing |
13 | * permissions and limitations under the License. |
14 | */ |
15 | |
16 | #include <aws/core/utils/json/JsonSerializer.h> |
17 | |
18 | #include <iterator> |
19 | #include <algorithm> |
20 | #include <aws/core/utils/memory/stl/AWSStringStream.h> |
21 | |
22 | using namespace Aws::Utils; |
23 | using namespace Aws::Utils::Json; |
24 | |
25 | JsonValue::JsonValue() : m_wasParseSuccessful(true) |
26 | { |
27 | m_value = nullptr; |
28 | } |
29 | |
30 | JsonValue::JsonValue(cJSON* value) : |
31 | m_value(cJSON_Duplicate(value, true /* recurse */)), |
32 | m_wasParseSuccessful(true) |
33 | { |
34 | } |
35 | |
36 | JsonValue::JsonValue(const Aws::String& value) : m_wasParseSuccessful(true) |
37 | { |
38 | const char* return_parse_end; |
39 | m_value = cJSON_ParseWithOpts(value.c_str(), &return_parse_end, 1/*require_null_terminated*/); |
40 | |
41 | if (!m_value || cJSON_IsInvalid(m_value)) |
42 | { |
43 | m_wasParseSuccessful = false; |
44 | m_errorMessage = "Failed to parse JSON at: " ; |
45 | m_errorMessage += return_parse_end; |
46 | } |
47 | } |
48 | |
49 | JsonValue::JsonValue(Aws::IStream& istream) : m_wasParseSuccessful(true) |
50 | { |
51 | Aws::StringStream memoryStream; |
52 | std::copy(std::istreambuf_iterator<char>(istream), std::istreambuf_iterator<char>(), std::ostreambuf_iterator<char>(memoryStream)); |
53 | const char* return_parse_end; |
54 | const auto input = memoryStream.str(); |
55 | m_value = cJSON_ParseWithOpts(input.c_str(), &return_parse_end, 1/*require_null_terminated*/); |
56 | |
57 | if (!m_value || cJSON_IsInvalid(m_value)) |
58 | { |
59 | m_wasParseSuccessful = false; |
60 | m_errorMessage = "Failed to parse JSON. Invalid input at: " ; |
61 | m_errorMessage += return_parse_end; |
62 | } |
63 | } |
64 | |
65 | JsonValue::JsonValue(const JsonValue& value) : |
66 | m_value(cJSON_Duplicate(value.m_value, true/*recurse*/)), |
67 | m_wasParseSuccessful(value.m_wasParseSuccessful), |
68 | m_errorMessage(value.m_errorMessage) |
69 | { |
70 | } |
71 | |
72 | JsonValue::JsonValue(JsonValue&& value) : |
73 | m_value(value.m_value), |
74 | m_wasParseSuccessful(value.m_wasParseSuccessful), |
75 | m_errorMessage(std::move(value.m_errorMessage)) |
76 | { |
77 | value.m_value = nullptr; |
78 | } |
79 | |
80 | void JsonValue::Destroy() |
81 | { |
82 | cJSON_Delete(m_value); |
83 | } |
84 | |
85 | JsonValue::~JsonValue() |
86 | { |
87 | Destroy(); |
88 | } |
89 | |
90 | JsonValue& JsonValue::operator=(const JsonValue& other) |
91 | { |
92 | if (this == &other) |
93 | { |
94 | return *this; |
95 | } |
96 | |
97 | Destroy(); |
98 | m_value = cJSON_Duplicate(other.m_value, true /*recurse*/); |
99 | m_wasParseSuccessful = other.m_wasParseSuccessful; |
100 | m_errorMessage = other.m_errorMessage; |
101 | return *this; |
102 | } |
103 | |
104 | JsonValue& JsonValue::operator=(JsonValue&& other) |
105 | { |
106 | if (this == &other) |
107 | { |
108 | return *this; |
109 | } |
110 | |
111 | using std::swap; |
112 | swap(m_value, other.m_value); |
113 | swap(m_errorMessage, other.m_errorMessage); |
114 | m_wasParseSuccessful = other.m_wasParseSuccessful; |
115 | return *this; |
116 | } |
117 | |
118 | static void AddOrReplace(cJSON* root, const char* key, cJSON* value) |
119 | { |
120 | const auto existing = cJSON_GetObjectItemCaseSensitive(root, key); |
121 | if (existing) |
122 | { |
123 | cJSON_ReplaceItemInObjectCaseSensitive(root, key, value); |
124 | } |
125 | else |
126 | { |
127 | cJSON_AddItemToObject(root, key, value); |
128 | } |
129 | } |
130 | |
131 | JsonValue& JsonValue::WithString(const char* key, const Aws::String& value) |
132 | { |
133 | if (!m_value) |
134 | { |
135 | m_value = cJSON_CreateObject(); |
136 | } |
137 | |
138 | const auto val = cJSON_CreateString(value.c_str()); |
139 | AddOrReplace(m_value, key, val); |
140 | return *this; |
141 | } |
142 | |
143 | JsonValue& JsonValue::WithString(const Aws::String& key, const Aws::String& value) |
144 | { |
145 | return WithString(key.c_str(), value); |
146 | } |
147 | |
148 | JsonValue& JsonValue::AsString(const Aws::String& value) |
149 | { |
150 | Destroy(); |
151 | m_value = cJSON_CreateString(value.c_str()); |
152 | return *this; |
153 | } |
154 | |
155 | JsonValue& JsonValue::WithBool(const char* key, bool value) |
156 | { |
157 | if (!m_value) |
158 | { |
159 | m_value = cJSON_CreateObject(); |
160 | } |
161 | |
162 | const auto val = cJSON_CreateBool(value); |
163 | AddOrReplace(m_value, key, val); |
164 | return *this; |
165 | } |
166 | |
167 | JsonValue& JsonValue::WithBool(const Aws::String& key, bool value) |
168 | { |
169 | return WithBool(key.c_str(), value); |
170 | } |
171 | |
172 | JsonValue& JsonValue::AsBool(bool value) |
173 | { |
174 | Destroy(); |
175 | m_value = cJSON_CreateBool(value); |
176 | return *this; |
177 | } |
178 | |
179 | JsonValue& JsonValue::WithInteger(const char* key, int value) |
180 | { |
181 | return WithDouble(key, static_cast<double>(value)); |
182 | } |
183 | |
184 | JsonValue& JsonValue::WithInteger(const Aws::String& key, int value) |
185 | { |
186 | return WithDouble(key.c_str(), static_cast<double>(value)); |
187 | } |
188 | |
189 | JsonValue& JsonValue::AsInteger(int value) |
190 | { |
191 | Destroy(); |
192 | m_value = cJSON_CreateNumber(static_cast<double>(value)); |
193 | return *this; |
194 | } |
195 | |
196 | JsonValue& JsonValue::WithInt64(const char* key, long long value) |
197 | { |
198 | return WithDouble(key, static_cast<double>(value)); |
199 | } |
200 | |
201 | JsonValue& JsonValue::WithInt64(const Aws::String& key, long long value) |
202 | { |
203 | return WithDouble(key.c_str(), static_cast<double>(value)); |
204 | } |
205 | |
206 | JsonValue& JsonValue::AsInt64(long long value) |
207 | { |
208 | return AsDouble(static_cast<double>(value)); |
209 | } |
210 | |
211 | JsonValue& JsonValue::WithDouble(const char* key, double value) |
212 | { |
213 | if (!m_value) |
214 | { |
215 | m_value = cJSON_CreateObject(); |
216 | } |
217 | |
218 | const auto val = cJSON_CreateNumber(value); |
219 | AddOrReplace(m_value, key, val); |
220 | return *this; |
221 | } |
222 | |
223 | JsonValue& JsonValue::WithDouble(const Aws::String& key, double value) |
224 | { |
225 | return WithDouble(key.c_str(), value); |
226 | } |
227 | |
228 | JsonValue& JsonValue::AsDouble(double value) |
229 | { |
230 | Destroy(); |
231 | m_value = cJSON_CreateNumber(value); |
232 | return *this; |
233 | } |
234 | |
235 | JsonValue& JsonValue::WithArray(const char* key, const Array<Aws::String>& array) |
236 | { |
237 | if (!m_value) |
238 | { |
239 | m_value = cJSON_CreateObject(); |
240 | } |
241 | |
242 | auto arrayValue = cJSON_CreateArray(); |
243 | for (unsigned i = 0; i < array.GetLength(); ++i) |
244 | { |
245 | cJSON_AddItemToArray(arrayValue, cJSON_CreateString(array[i].c_str())); |
246 | } |
247 | |
248 | AddOrReplace(m_value, key, arrayValue); |
249 | return *this; |
250 | } |
251 | |
252 | JsonValue& JsonValue::WithArray(const Aws::String& key, const Array<Aws::String>& array) |
253 | { |
254 | return WithArray(key.c_str(), array); |
255 | } |
256 | |
257 | JsonValue& JsonValue::WithArray(const Aws::String& key, const Array<JsonValue>& array) |
258 | { |
259 | if (!m_value) |
260 | { |
261 | m_value = cJSON_CreateObject(); |
262 | } |
263 | |
264 | auto arrayValue = cJSON_CreateArray(); |
265 | for (unsigned i = 0; i < array.GetLength(); ++i) |
266 | { |
267 | cJSON_AddItemToArray(arrayValue, cJSON_Duplicate(array[i].m_value, true /*recurse*/)); |
268 | } |
269 | |
270 | AddOrReplace(m_value, key.c_str(), arrayValue); |
271 | return *this; |
272 | } |
273 | |
274 | JsonValue& JsonValue::WithArray(const Aws::String& key, Array<JsonValue>&& array) |
275 | { |
276 | if (!m_value) |
277 | { |
278 | m_value = cJSON_CreateObject(); |
279 | } |
280 | |
281 | auto arrayValue = cJSON_CreateArray(); |
282 | for (unsigned i = 0; i < array.GetLength(); ++i) |
283 | { |
284 | cJSON_AddItemToArray(arrayValue, array[i].m_value); |
285 | array[i].m_value = nullptr; |
286 | } |
287 | |
288 | AddOrReplace(m_value, key.c_str(), arrayValue); |
289 | return *this; |
290 | } |
291 | |
292 | JsonValue& JsonValue::AsArray(const Array<JsonValue>& array) |
293 | { |
294 | auto arrayValue = cJSON_CreateArray(); |
295 | for (unsigned i = 0; i < array.GetLength(); ++i) |
296 | { |
297 | cJSON_AddItemToArray(arrayValue, cJSON_Duplicate(array[i].m_value, true /*recurse*/)); |
298 | } |
299 | |
300 | Destroy(); |
301 | m_value = arrayValue; |
302 | return *this; |
303 | } |
304 | |
305 | JsonValue& JsonValue::AsArray(Array<JsonValue>&& array) |
306 | { |
307 | auto arrayValue = cJSON_CreateArray(); |
308 | for (unsigned i = 0; i < array.GetLength(); ++i) |
309 | { |
310 | cJSON_AddItemToArray(arrayValue, array[i].m_value); |
311 | array[i].m_value = nullptr; |
312 | } |
313 | |
314 | Destroy(); |
315 | m_value = arrayValue; |
316 | return *this; |
317 | } |
318 | |
319 | JsonValue& JsonValue::WithObject(const char* key, const JsonValue& value) |
320 | { |
321 | if (!m_value) |
322 | { |
323 | m_value = cJSON_CreateObject(); |
324 | } |
325 | |
326 | const auto copy = value.m_value == nullptr ? cJSON_CreateObject() : cJSON_Duplicate(value.m_value, true /*recurse*/); |
327 | AddOrReplace(m_value, key, copy); |
328 | return *this; |
329 | } |
330 | |
331 | JsonValue& JsonValue::WithObject(const Aws::String& key, const JsonValue& value) |
332 | { |
333 | return WithObject(key.c_str(), value); |
334 | } |
335 | |
336 | JsonValue& JsonValue::WithObject(const char* key, JsonValue&& value) |
337 | { |
338 | if (!m_value) |
339 | { |
340 | m_value = cJSON_CreateObject(); |
341 | } |
342 | |
343 | AddOrReplace(m_value, key, value.m_value == nullptr ? cJSON_CreateObject() : value.m_value); |
344 | value.m_value = nullptr; |
345 | return *this; |
346 | } |
347 | |
348 | JsonValue& JsonValue::WithObject(const Aws::String& key, JsonValue&& value) |
349 | { |
350 | return WithObject(key.c_str(), std::move(value)); |
351 | } |
352 | |
353 | JsonValue& JsonValue::AsObject(const JsonValue& value) |
354 | { |
355 | *this = value; |
356 | return *this; |
357 | } |
358 | |
359 | JsonValue& JsonValue::AsObject(JsonValue && value) |
360 | { |
361 | *this = std::move(value); |
362 | return *this; |
363 | } |
364 | |
365 | bool JsonValue::operator==(const JsonValue& other) const |
366 | { |
367 | return cJSON_Compare(m_value, other.m_value, true /*case-sensitive*/) != 0; |
368 | } |
369 | |
370 | bool JsonValue::operator!=(const JsonValue& other) const |
371 | { |
372 | return !(*this == other); |
373 | } |
374 | |
375 | JsonView JsonValue::View() const |
376 | { |
377 | return *this; |
378 | } |
379 | |
380 | JsonView::JsonView() : m_value(nullptr) |
381 | { |
382 | } |
383 | |
384 | JsonView::JsonView(const JsonValue& val) : m_value(val.m_value) |
385 | { |
386 | } |
387 | |
388 | JsonView::JsonView(cJSON* val) : m_value(val) |
389 | { |
390 | } |
391 | |
392 | JsonView& JsonView::operator=(const JsonValue& v) |
393 | { |
394 | m_value = v.m_value; |
395 | return *this; |
396 | } |
397 | |
398 | JsonView& JsonView::operator=(cJSON* val) |
399 | { |
400 | m_value = val; |
401 | return *this; |
402 | } |
403 | |
404 | Aws::String JsonView::GetString(const Aws::String& key) const |
405 | { |
406 | assert(m_value); |
407 | auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
408 | auto str = cJSON_GetStringValue(item); |
409 | return str ? str : "" ; |
410 | } |
411 | |
412 | Aws::String JsonView::AsString() const |
413 | { |
414 | const char* str = cJSON_GetStringValue(m_value); |
415 | if (str == nullptr) |
416 | { |
417 | return {}; |
418 | } |
419 | return str; |
420 | } |
421 | |
422 | bool JsonView::GetBool(const Aws::String& key) const |
423 | { |
424 | assert(m_value); |
425 | auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
426 | assert(item); |
427 | return item->valueint != 0; |
428 | } |
429 | |
430 | bool JsonView::AsBool() const |
431 | { |
432 | assert(cJSON_IsBool(m_value)); |
433 | return cJSON_IsTrue(m_value) != 0; |
434 | } |
435 | |
436 | int JsonView::GetInteger(const Aws::String& key) const |
437 | { |
438 | assert(m_value); |
439 | auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
440 | assert(item); |
441 | return item->valueint; |
442 | } |
443 | |
444 | int JsonView::AsInteger() const |
445 | { |
446 | assert(cJSON_IsNumber(m_value)); // can be double or value larger than int_max, but at least not UB |
447 | return m_value->valueint; |
448 | } |
449 | |
450 | int64_t JsonView::GetInt64(const Aws::String& key) const |
451 | { |
452 | return static_cast<long long>(GetDouble(key)); |
453 | } |
454 | |
455 | int64_t JsonView::AsInt64() const |
456 | { |
457 | assert(cJSON_IsNumber(m_value)); |
458 | return static_cast<long long>(m_value->valuedouble); |
459 | } |
460 | |
461 | double JsonView::GetDouble(const Aws::String& key) const |
462 | { |
463 | assert(m_value); |
464 | auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
465 | assert(item); |
466 | return item->valuedouble; |
467 | } |
468 | |
469 | double JsonView::AsDouble() const |
470 | { |
471 | assert(cJSON_IsNumber(m_value)); |
472 | return m_value->valuedouble; |
473 | } |
474 | |
475 | JsonView JsonView::GetObject(const Aws::String& key) const |
476 | { |
477 | assert(m_value); |
478 | auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
479 | return item; |
480 | } |
481 | |
482 | JsonView JsonView::AsObject() const |
483 | { |
484 | assert(cJSON_IsObject(m_value)); |
485 | return m_value; |
486 | } |
487 | |
488 | Array<JsonView> JsonView::GetArray(const Aws::String& key) const |
489 | { |
490 | assert(m_value); |
491 | auto array = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
492 | assert(cJSON_IsArray(array)); |
493 | Array<JsonView> returnArray(cJSON_GetArraySize(array)); |
494 | |
495 | auto element = array->child; |
496 | for (unsigned i = 0; element && i < returnArray.GetLength(); ++i, element = element->next) |
497 | { |
498 | returnArray[i] = element; |
499 | } |
500 | |
501 | return returnArray; |
502 | } |
503 | |
504 | Array<JsonView> JsonView::AsArray() const |
505 | { |
506 | assert(cJSON_IsArray(m_value)); |
507 | Array<JsonView> returnArray(cJSON_GetArraySize(m_value)); |
508 | |
509 | auto element = m_value->child; |
510 | |
511 | for (unsigned i = 0; element && i < returnArray.GetLength(); ++i, element = element->next) |
512 | { |
513 | returnArray[i] = element; |
514 | } |
515 | |
516 | return returnArray; |
517 | } |
518 | |
519 | Aws::Map<Aws::String, JsonView> JsonView::GetAllObjects() const |
520 | { |
521 | Aws::Map<Aws::String, JsonView> valueMap; |
522 | if (!m_value) |
523 | { |
524 | return valueMap; |
525 | } |
526 | |
527 | for (auto iter = m_value->child; iter; iter = iter->next) |
528 | { |
529 | valueMap.emplace(std::make_pair(Aws::String(iter->string), JsonView(iter))); |
530 | } |
531 | |
532 | return valueMap; |
533 | } |
534 | |
535 | bool JsonView::ValueExists(const Aws::String& key) const |
536 | { |
537 | if (!cJSON_IsObject(m_value)) |
538 | { |
539 | return false; |
540 | } |
541 | |
542 | auto item = cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()); |
543 | return !(item == nullptr || cJSON_IsNull(item)); |
544 | } |
545 | |
546 | bool JsonView::KeyExists(const Aws::String& key) const |
547 | { |
548 | if (!cJSON_IsObject(m_value)) |
549 | { |
550 | return false; |
551 | } |
552 | |
553 | return cJSON_GetObjectItemCaseSensitive(m_value, key.c_str()) != nullptr;; |
554 | } |
555 | |
556 | bool JsonView::IsObject() const |
557 | { |
558 | return cJSON_IsObject(m_value) != 0; |
559 | } |
560 | |
561 | bool JsonView::IsBool() const |
562 | { |
563 | return cJSON_IsBool(m_value) != 0; |
564 | } |
565 | |
566 | bool JsonView::IsString() const |
567 | { |
568 | return cJSON_IsString(m_value) != 0; |
569 | } |
570 | |
571 | bool JsonView::IsIntegerType() const |
572 | { |
573 | if (!cJSON_IsNumber(m_value)) |
574 | { |
575 | return false; |
576 | } |
577 | |
578 | return m_value->valuedouble == static_cast<long long>(m_value->valuedouble); |
579 | } |
580 | |
581 | bool JsonView::IsFloatingPointType() const |
582 | { |
583 | if (!cJSON_IsNumber(m_value)) |
584 | { |
585 | return false; |
586 | } |
587 | |
588 | return m_value->valuedouble != static_cast<long long>(m_value->valuedouble); |
589 | } |
590 | |
591 | bool JsonView::IsListType() const |
592 | { |
593 | return cJSON_IsArray(m_value) != 0; |
594 | } |
595 | |
596 | bool JsonView::IsNull() const |
597 | { |
598 | return cJSON_IsNull(m_value) != 0; |
599 | } |
600 | |
601 | Aws::String JsonView::WriteCompact(bool treatAsObject) const |
602 | { |
603 | if (!m_value) |
604 | { |
605 | if (treatAsObject) |
606 | { |
607 | return "{}" ; |
608 | } |
609 | return {}; |
610 | } |
611 | |
612 | auto temp = cJSON_PrintUnformatted(m_value); |
613 | Aws::String out(temp); |
614 | cJSON_free(temp); |
615 | return out; |
616 | } |
617 | |
618 | Aws::String JsonView::WriteReadable(bool treatAsObject) const |
619 | { |
620 | if (!m_value) |
621 | { |
622 | if (treatAsObject) |
623 | { |
624 | return "{\n}\n" ; |
625 | } |
626 | return {}; |
627 | } |
628 | |
629 | auto temp = cJSON_Print(m_value); |
630 | Aws::String out(temp); |
631 | cJSON_free(temp); |
632 | return out; |
633 | } |
634 | |
635 | JsonValue JsonView::Materialize() const |
636 | { |
637 | return m_value; |
638 | } |
639 | |