blob: 0ece3253cd514255581e2772bf4b2de005de3ec9 [file] [log] [blame]
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -08001/*
2 * Copyright (C) 2013 The Android Open Source Project
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 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "JSONObject"
19#include <utils/Log.h>
20
21#include <media/stagefright/foundation/JSONObject.h>
22
23#include <ctype.h>
24#include <media/stagefright/Utils.h>
25#include <media/stagefright/foundation/ADebug.h>
26#include <media/stagefright/MediaErrors.h>
27
28namespace android {
Jorge E. Moreira392833b2019-12-03 16:53:29 -080029namespace {
30 const char kIndent[] = " ";
31}
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -080032
33// static
34ssize_t JSONValue::Parse(const char *data, size_t size, JSONValue *out) {
35 size_t offset = 0;
36 while (offset < size && isspace(data[offset])) {
37 ++offset;
38 }
39
40 if (offset == size) {
41 return ERROR_MALFORMED;
42 }
43
44 if (data[offset] == '[') {
Jorge E. Moreira392833b2019-12-03 16:53:29 -080045 std::shared_ptr<JSONArray> array(new JSONArray);
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -080046 ++offset;
47
48 for (;;) {
49 while (offset < size && isspace(data[offset])) {
50 ++offset;
51 }
52
53 if (offset == size) {
54 return ERROR_MALFORMED;
55 }
56
57 if (data[offset] == ']') {
58 ++offset;
59 break;
60 }
61
62 JSONValue val;
63 ssize_t n = Parse(&data[offset], size - offset, &val);
64
65 if (n < 0) {
66 return n;
67 }
68
69 array->addValue(val);
70
71 offset += n;
72
73 while (offset < size && isspace(data[offset])) {
74 ++offset;
75 }
76
77 if (offset == size) {
78 return ERROR_MALFORMED;
79 }
80
81 if (data[offset] == ',') {
82 ++offset;
83 } else if (data[offset] != ']') {
84 return ERROR_MALFORMED;
85 }
86 };
87
88 out->setArray(array);
89
90 return offset;
91 } else if (data[offset] == '{') {
Jorge E. Moreira392833b2019-12-03 16:53:29 -080092 std::shared_ptr<JSONObject> obj(new JSONObject);
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -080093 ++offset;
94
95 for (;;) {
96 while (offset < size && isspace(data[offset])) {
97 ++offset;
98 }
99
100 if (offset == size) {
101 return ERROR_MALFORMED;
102 }
103
104 if (data[offset] == '}') {
105 ++offset;
106 break;
107 }
108
109 JSONValue key;
110 ssize_t n = Parse(&data[offset], size - offset, &key);
111
112 if (n < 0) {
113 return n;
114 }
115
116 if (key.type() != TYPE_STRING) {
117 return ERROR_MALFORMED;
118 }
119
120 offset += n;
121
122 while (offset < size && isspace(data[offset])) {
123 ++offset;
124 }
125
126 if (offset == size || data[offset] != ':') {
127 return ERROR_MALFORMED;
128 }
129
130 ++offset;
131
132 JSONValue val;
133 n = Parse(&data[offset], size - offset, &val);
134
135 if (n < 0) {
136 return n;
137 }
138
139 std::string keyVal;
140 CHECK(key.getString(&keyVal));
141
142 obj->setValue(keyVal.c_str(), val);
143
144 offset += n;
145
146 while (offset < size && isspace(data[offset])) {
147 ++offset;
148 }
149
150 if (offset == size) {
151 return ERROR_MALFORMED;
152 }
153
154 if (data[offset] == ',') {
155 ++offset;
156 } else if (data[offset] != '}') {
157 return ERROR_MALFORMED;
158 }
159 };
160
161 out->setObject(obj);
162
163 return offset;
164 } else if (data[offset] == '"') {
165 ++offset;
166
167 std::string s;
168 bool escaped = false;
169 while (offset < size) {
170 if (escaped) {
171 char c;
172 switch (data[offset]) {
173 case '\"':
174 case '\\':
175 case '/':
176 c = data[offset];
177 break;
178 case 'b':
179 c = '\x08';
180 break;
181 case 'f':
182 c = '\x0c';
183 break;
184 case 'n':
185 c = '\x0a';
186 break;
187 case 'r':
188 c = '\x0d';
189 break;
190 case 't':
191 c = '\x09';
192 break;
193 default:
194 return ERROR_MALFORMED;
195 }
196
197 s.append(1, c);
198 ++offset;
199
200 escaped = false;
201 continue;
202 } else if (data[offset] == '\\') {
203 escaped = true;
204 ++offset;
205 continue;
206 } else if (data[offset] == '"') {
207 break;
208 }
209
210 s.append(1, data[offset++]);
211 }
212
213 if (offset == size) {
214 return ERROR_MALFORMED;
215 }
216
217 ++offset;
218 out->setString(s);
219
220 return offset;
221 } else if (isdigit(data[offset]) || data[offset] == '-') {
222 bool negate = false;
223 if (data[offset] == '-') {
224 negate = true;
225 ++offset;
226
227 if (offset == size) {
228 return ERROR_MALFORMED;
229 }
230 }
231
232 size_t firstDigitOffset = offset;
233 while (offset < size && isdigit(data[offset])) {
234 ++offset;
235 }
236
237 size_t numDigits = offset - firstDigitOffset;
238 if (numDigits > 1 && data[firstDigitOffset] == '0') {
239 // No leading zeros.
240 return ERROR_MALFORMED;
241 }
242
243 size_t firstFracDigitOffset = 0;
244 size_t numFracDigits = 0;
245
246 if (offset < size && data[offset] == '.') {
247 ++offset;
248
249 firstFracDigitOffset = offset;
250 while (offset < size && isdigit(data[offset])) {
251 ++offset;
252 }
253
254 numFracDigits = offset - firstFracDigitOffset;
255 if (numFracDigits == 0) {
256 return ERROR_MALFORMED;
257 }
258 }
259
260 bool negateExponent = false;
261 size_t firstExpDigitOffset = 0;
262 size_t numExpDigits = 0;
263
264 if (offset < size && (data[offset] == 'e' || data[offset] == 'E')) {
265 ++offset;
266
267 if (offset == size) {
268 return ERROR_MALFORMED;
269 }
270
271 if (data[offset] == '+' || data[offset] == '-') {
272 if (data[offset] == '-') {
273 negateExponent = true;
274 }
275
276 ++offset;
277 }
278
279 firstExpDigitOffset = offset;
280 while (offset < size && isdigit(data[offset])) {
281 ++offset;
282 }
283
284 numExpDigits = offset - firstExpDigitOffset;
285 if (numExpDigits == 0) {
286 return ERROR_MALFORMED;
287 }
288 }
289
290 CHECK_EQ(numFracDigits, 0u);
291 CHECK_EQ(numExpDigits, 0u);
292
293 int32_t x = 0;
294 for (size_t i = 0; i < numDigits; ++i) {
295 x *= 10;
296 x += data[firstDigitOffset + i] - '0';
297
298 CHECK_GE(x, 0);
299 }
300
301 if (negate) {
302 x = -x;
303 }
304
305 out->setInt32(x);
306
307 return offset;
308 } else if (offset + 4 <= size && !strncmp("null", &data[offset], 4)) {
309 out->unset();
310 return offset + 4;
311 } else if (offset + 4 <= size && !strncmp("true", &data[offset], 4)) {
312 out->setBoolean(true);
313 return offset + 4;
314 } else if (offset + 5 <= size && !strncmp("false", &data[offset], 5)) {
315 out->setBoolean(false);
316 return offset + 5;
317 }
318
319 return ERROR_MALFORMED;
320}
321
322JSONValue::JSONValue()
323 : mType(TYPE_NULL) {
324}
325
326JSONValue::JSONValue(const JSONValue &other)
327 : mType(TYPE_NULL) {
328 *this = other;
329}
330
331JSONValue &JSONValue::operator=(const JSONValue &other) {
332 if (&other != this) {
333 unset();
334 mType = other.mType;
335 mValue = other.mValue;
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800336 mObjectOrArray = other.mObjectOrArray;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800337
338 switch (mType) {
339 case TYPE_STRING:
340 mValue.mString = new std::string(*other.mValue.mString);
341 break;
342 case TYPE_OBJECT:
343 case TYPE_ARRAY:
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800344 default:
345 break;
346 }
347 }
348
349 return *this;
350}
351
352JSONValue::~JSONValue() {
353 unset();
354}
355
356JSONValue::FieldType JSONValue::type() const {
357 return mType;
358}
359
360bool JSONValue::getInt32(int32_t *value) const {
361 if (mType != TYPE_NUMBER) {
362 return false;
363 }
364
365 *value = mValue.mInt32;
366 return true;
367}
368
369bool JSONValue::getString(std::string *value) const {
370 if (mType != TYPE_STRING) {
371 return false;
372 }
373
374 *value = *mValue.mString;
375 return true;
376}
377
378bool JSONValue::getBoolean(bool *value) const {
379 if (mType != TYPE_BOOLEAN) {
380 return false;
381 }
382
383 *value = mValue.mBoolean;
384 return true;
385}
386
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800387bool JSONValue::getObject(std::shared_ptr<JSONObject> *value) const {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800388 if (mType != TYPE_OBJECT) {
389 return false;
390 }
391
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800392 *value = std::static_pointer_cast<JSONObject>(mObjectOrArray);
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800393 return true;
394}
395
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800396bool JSONValue::getArray(std::shared_ptr<JSONArray> *value) const {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800397 if (mType != TYPE_ARRAY) {
398 return false;
399 }
400
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800401 *value = std::static_pointer_cast<JSONArray>(mObjectOrArray);
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800402 return true;
403}
404
405void JSONValue::setInt32(int32_t value) {
406 unset();
407
408 mValue.mInt32 = value;
409 mType = TYPE_NUMBER;
410}
411
412void JSONValue::setString(std::string_view value) {
413 unset();
414
415 mValue.mString = new std::string(value);
416 mType = TYPE_STRING;
417}
418
419void JSONValue::setBoolean(bool value) {
420 unset();
421
422 mValue.mBoolean = value;
423 mType = TYPE_BOOLEAN;
424}
425
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800426void JSONValue::setObject(std::shared_ptr<JSONObject> obj) {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800427 unset();
428
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800429 mObjectOrArray = obj;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800430
431 mType = TYPE_OBJECT;
432}
433
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800434void JSONValue::setArray(std::shared_ptr<JSONArray> array) {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800435 unset();
436
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800437 mObjectOrArray = array;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800438
439 mType = TYPE_ARRAY;
440}
441
442void JSONValue::unset() {
443 switch (mType) {
444 case TYPE_STRING:
445 delete mValue.mString;
446 break;
447 case TYPE_OBJECT:
448 case TYPE_ARRAY:
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800449 mObjectOrArray.reset();
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800450 break;
451
452 default:
453 break;
454 }
455
456 mType = TYPE_NULL;
457}
458
459static void EscapeString(const char *in, size_t inSize, std::string *out) {
460 CHECK(in != out->c_str());
461 out->clear();
462
463 for (size_t i = 0; i < inSize; ++i) {
464 char c = in[i];
465 switch (c) {
466 case '\"':
467 out->append("\\\"");
468 break;
469 case '\\':
470 out->append("\\\\");
471 break;
472 case '/':
473 out->append("\\/");
474 break;
475 case '\x08':
476 out->append("\\b");
477 break;
478 case '\x0c':
479 out->append("\\f");
480 break;
481 case '\x0a':
482 out->append("\\n");
483 break;
484 case '\x0d':
485 out->append("\\r");
486 break;
487 case '\x09':
488 out->append("\\t");
489 break;
490 default:
491 out->append(1, c);
492 break;
493 }
494 }
495}
496
497std::string JSONValue::toString(size_t depth, bool indentFirstLine) const {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800498
499 std::string out;
500
501 switch (mType) {
502 case TYPE_STRING:
503 {
504 std::string escaped;
505 EscapeString(
506 mValue.mString->c_str(), mValue.mString->size(), &escaped);
507
508 out.append("\"");
509 out.append(escaped);
510 out.append("\"");
511 break;
512 }
513
514 case TYPE_NUMBER:
515 {
516 out = StringPrintf("%d", mValue.mInt32);
517 break;
518 }
519
520 case TYPE_BOOLEAN:
521 {
522 out = mValue.mBoolean ? "true" : "false";
523 break;
524 }
525
526 case TYPE_NULL:
527 {
528 out = "null";
529 break;
530 }
531
532 case TYPE_OBJECT:
533 case TYPE_ARRAY:
534 {
535 out = (mType == TYPE_OBJECT) ? "{\n" : "[\n";
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800536 out.append(mObjectOrArray->internalToString(depth + 1, true));
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800537 out.append("\n");
538 out.append(kIndent, 2 * depth);
539 out.append(mType == TYPE_OBJECT ? "}" : "]");
540 break;
541 }
542
543 default:
544 TRESPASS();
545 }
546
547 if (indentFirstLine) {
548 out.insert(0, kIndent, 2 * depth);
549 }
550
551 return out;
552}
553
554////////////////////////////////////////////////////////////////////////////////
555
556// static
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800557std::shared_ptr<JSONCompound> JSONCompound::Parse(const char *data, size_t size) {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800558 JSONValue value;
559 ssize_t result = JSONValue::Parse(data, size, &value);
560
561 if (result < 0) {
562 return NULL;
563 }
564
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800565 std::shared_ptr<JSONObject> obj;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800566 if (value.getObject(&obj)) {
567 return obj;
568 }
569
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800570 std::shared_ptr<JSONArray> array;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800571 if (value.getArray(&array)) {
572 return array;
573 }
574
575 return NULL;
576}
577
578std::string JSONCompound::toString(size_t depth, bool indentFirstLine) const {
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800579 std::string out;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800580
Jorge E. Moreira392833b2019-12-03 16:53:29 -0800581 if (indentFirstLine) {
582 out.insert(0, kIndent, 2 * depth);
583 }
584
585 out = isObject() ? "{\n" : "[\n";
586 out.append(internalToString(depth + 1, true));
587 out.append("\n");
588 out.append(kIndent, 2 * depth);
589 out.append(isObject() ? "}" : "]");
590
591 return out;
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800592}
593
594////////////////////////////////////////////////////////////////////////////////
595
596JSONObject::JSONObject() {}
597JSONObject::~JSONObject() {}
598
599bool JSONObject::isObject() const {
600 return true;
601}
602
603bool JSONObject::getValue(const char *key, JSONValue *value) const {
604 auto it = mValues.find(key);
605
606 if (it == mValues.end()) {
607 return false;
608 }
609
610 *value = it->second;
611
612 return true;
613}
614
615void JSONObject::setValue(const char *key, const JSONValue &value) {
616 mValues[std::string(key)] = value;
617}
618
619void JSONObject::remove(const char *key) {
620 mValues.erase(key);
621}
622
623std::string JSONObject::internalToString(
624 size_t depth, bool /* indentFirstLine */) const {
Jorge E. Moreiraa18ff1a2019-12-17 18:20:56 -0800625 std::string out;
626 for (auto it = mValues.begin(); it != mValues.end();) {
627 const std::string &key = it->first;
628 std::string escapedKey;
629 EscapeString(key.c_str(), key.size(), &escapedKey);
630
631 out.append(kIndent, 2 * depth);
632 out.append("\"");
633 out.append(escapedKey);
634 out.append("\": ");
635
636 out.append(it->second.toString(depth + 1, false));
637
638 ++it;
639 if (it != mValues.end()) {
640 out.append(",\n");
641 }
642 }
643
644 return out;
645}
646
647////////////////////////////////////////////////////////////////////////////////
648
649JSONArray::JSONArray() {}
650
651JSONArray::~JSONArray() {}
652
653bool JSONArray::isObject() const {
654 return false;
655}
656
657size_t JSONArray::size() const {
658 return mValues.size();
659}
660
661bool JSONArray::getValue(size_t key, JSONValue *value) const {
662 if (key >= mValues.size()) {
663 return false;
664 }
665
666 *value = mValues[key];
667
668 return true;
669}
670
671void JSONArray::addValue(const JSONValue &value) {
672 mValues.push_back(value);
673}
674
675std::string JSONArray::internalToString(
676 size_t depth, bool /* indentFirstLine */) const {
677 std::string out;
678 for (size_t i = 0; i < mValues.size(); ++i) {
679 out.append(mValues[i].toString(depth));
680
681 if (i + 1 < mValues.size()) {
682 out.append(",\n");
683 }
684 }
685
686 return out;
687}
688
689////////////////////////////////////////////////////////////////////////////////
690
691} // namespace android
692