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
22using namespace Aws::Utils;
23using namespace Aws::Utils::Json;
24
25JsonValue::JsonValue() : m_wasParseSuccessful(true)
26{
27 m_value = nullptr;
28}
29
30JsonValue::JsonValue(cJSON* value) :
31 m_value(cJSON_Duplicate(value, true /* recurse */)),
32 m_wasParseSuccessful(true)
33{
34}
35
36JsonValue::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
49JsonValue::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
65JsonValue::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
72JsonValue::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
80void JsonValue::Destroy()
81{
82 cJSON_Delete(m_value);
83}
84
85JsonValue::~JsonValue()
86{
87 Destroy();
88}
89
90JsonValue& 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
104JsonValue& 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
118static 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
131JsonValue& 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
143JsonValue& JsonValue::WithString(const Aws::String& key, const Aws::String& value)
144{
145 return WithString(key.c_str(), value);
146}
147
148JsonValue& JsonValue::AsString(const Aws::String& value)
149{
150 Destroy();
151 m_value = cJSON_CreateString(value.c_str());
152 return *this;
153}
154
155JsonValue& 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
167JsonValue& JsonValue::WithBool(const Aws::String& key, bool value)
168{
169 return WithBool(key.c_str(), value);
170}
171
172JsonValue& JsonValue::AsBool(bool value)
173{
174 Destroy();
175 m_value = cJSON_CreateBool(value);
176 return *this;
177}
178
179JsonValue& JsonValue::WithInteger(const char* key, int value)
180{
181 return WithDouble(key, static_cast<double>(value));
182}
183
184JsonValue& JsonValue::WithInteger(const Aws::String& key, int value)
185{
186 return WithDouble(key.c_str(), static_cast<double>(value));
187}
188
189JsonValue& JsonValue::AsInteger(int value)
190{
191 Destroy();
192 m_value = cJSON_CreateNumber(static_cast<double>(value));
193 return *this;
194}
195
196JsonValue& JsonValue::WithInt64(const char* key, long long value)
197{
198 return WithDouble(key, static_cast<double>(value));
199}
200
201JsonValue& JsonValue::WithInt64(const Aws::String& key, long long value)
202{
203 return WithDouble(key.c_str(), static_cast<double>(value));
204}
205
206JsonValue& JsonValue::AsInt64(long long value)
207{
208 return AsDouble(static_cast<double>(value));
209}
210
211JsonValue& 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
223JsonValue& JsonValue::WithDouble(const Aws::String& key, double value)
224{
225 return WithDouble(key.c_str(), value);
226}
227
228JsonValue& JsonValue::AsDouble(double value)
229{
230 Destroy();
231 m_value = cJSON_CreateNumber(value);
232 return *this;
233}
234
235JsonValue& 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
252JsonValue& JsonValue::WithArray(const Aws::String& key, const Array<Aws::String>& array)
253{
254 return WithArray(key.c_str(), array);
255}
256
257JsonValue& 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
274JsonValue& 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
292JsonValue& 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
305JsonValue& 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
319JsonValue& 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
331JsonValue& JsonValue::WithObject(const Aws::String& key, const JsonValue& value)
332{
333 return WithObject(key.c_str(), value);
334}
335
336JsonValue& 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
348JsonValue& JsonValue::WithObject(const Aws::String& key, JsonValue&& value)
349{
350 return WithObject(key.c_str(), std::move(value));
351}
352
353JsonValue& JsonValue::AsObject(const JsonValue& value)
354{
355 *this = value;
356 return *this;
357}
358
359JsonValue& JsonValue::AsObject(JsonValue && value)
360{
361 *this = std::move(value);
362 return *this;
363}
364
365bool JsonValue::operator==(const JsonValue& other) const
366{
367 return cJSON_Compare(m_value, other.m_value, true /*case-sensitive*/) != 0;
368}
369
370bool JsonValue::operator!=(const JsonValue& other) const
371{
372 return !(*this == other);
373}
374
375JsonView JsonValue::View() const
376{
377 return *this;
378}
379
380JsonView::JsonView() : m_value(nullptr)
381{
382}
383
384JsonView::JsonView(const JsonValue& val) : m_value(val.m_value)
385{
386}
387
388JsonView::JsonView(cJSON* val) : m_value(val)
389{
390}
391
392JsonView& JsonView::operator=(const JsonValue& v)
393{
394 m_value = v.m_value;
395 return *this;
396}
397
398JsonView& JsonView::operator=(cJSON* val)
399{
400 m_value = val;
401 return *this;
402}
403
404Aws::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
412Aws::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
422bool 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
430bool JsonView::AsBool() const
431{
432 assert(cJSON_IsBool(m_value));
433 return cJSON_IsTrue(m_value) != 0;
434}
435
436int 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
444int 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
450int64_t JsonView::GetInt64(const Aws::String& key) const
451{
452 return static_cast<long long>(GetDouble(key));
453}
454
455int64_t JsonView::AsInt64() const
456{
457 assert(cJSON_IsNumber(m_value));
458 return static_cast<long long>(m_value->valuedouble);
459}
460
461double 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
469double JsonView::AsDouble() const
470{
471 assert(cJSON_IsNumber(m_value));
472 return m_value->valuedouble;
473}
474
475JsonView 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
482JsonView JsonView::AsObject() const
483{
484 assert(cJSON_IsObject(m_value));
485 return m_value;
486}
487
488Array<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
504Array<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
519Aws::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
535bool 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
546bool 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
556bool JsonView::IsObject() const
557{
558 return cJSON_IsObject(m_value) != 0;
559}
560
561bool JsonView::IsBool() const
562{
563 return cJSON_IsBool(m_value) != 0;
564}
565
566bool JsonView::IsString() const
567{
568 return cJSON_IsString(m_value) != 0;
569}
570
571bool 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
581bool 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
591bool JsonView::IsListType() const
592{
593 return cJSON_IsArray(m_value) != 0;
594}
595
596bool JsonView::IsNull() const
597{
598 return cJSON_IsNull(m_value) != 0;
599}
600
601Aws::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
618Aws::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
635JsonValue JsonView::Materialize() const
636{
637 return m_value;
638}
639