1 /*
2 * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3 */
4 #include "linkkit/infra/infra_config.h"
5
6 #ifdef INFRA_CJSON
7
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <limits.h>
12
13 #include <math.h>
14 #include <float.h>
15 #include <ctype.h>
16
17 #include "linkkit/infra/infra_cjson.h"
18 #include "linkkit/infra/infra_types.h"
19
20 typedef struct {
21 const unsigned char *content;
22 int length;
23 int offset;
24 int depth; /* How deeply nested (in arrays/objects) is the input at the
25 current offset. */
26 } parse_buffer;
27
28 /* check if the given size is left to read in a given parse buffer (starting
29 * with 1) */
30 #define can_read(buffer, size) \
31 ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
32 /* check if the buffer can be accessed at the given index (starting with 0) */
33 #define can_access_at_index(buffer, index) \
34 ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
35 #define cannot_access_at_index(buffer, index) \
36 (!can_access_at_index(buffer, index))
37 /* get a pointer to the buffer at the position */
38 #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
39
40 /* Predeclare these prototypes. */
41 static int parse_value(lite_cjson_t *const item,
42 parse_buffer * const input_buffer);
43 static int parse_string(lite_cjson_t *const item,
44 parse_buffer * const input_buffer);
45 static int parse_array(lite_cjson_t *const item,
46 parse_buffer * const input_buffer);
47 static int parse_object(lite_cjson_t *const item,
48 parse_buffer * const input_buffer);
49
50 /* Utility to jump whitespace and cr/lf */
buffer_skip_whitespace(parse_buffer * const buffer)51 static parse_buffer *buffer_skip_whitespace(parse_buffer *const buffer)
52 {
53 if ((buffer == NULL) || (buffer->content == NULL)) {
54 return NULL;
55 }
56
57 while (can_access_at_index(buffer, 0) &&
58 (buffer_at_offset(buffer)[0] <= 32)) {
59 buffer->offset++;
60 }
61
62 if (buffer->offset == buffer->length) {
63 buffer->offset--;
64 }
65
66 return buffer;
67 }
68
69 /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
skip_utf8_bom(parse_buffer * const buffer)70 static parse_buffer *skip_utf8_bom(parse_buffer *const buffer)
71 {
72 if ((buffer == NULL) || (buffer->content == NULL) ||
73 (buffer->offset != 0)) {
74 return NULL;
75 }
76
77 if (can_access_at_index(buffer, 4) &&
78 (strncmp((const char *)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) ==
79 0)) {
80 buffer->offset += 3;
81 }
82
83 return buffer;
84 }
85
86 /* Parse the input text to generate a number, and populate the result into item.
87 */
parse_number(lite_cjson_t * const item,parse_buffer * const input_buffer)88 static int parse_number(lite_cjson_t *const item,
89 parse_buffer *const input_buffer)
90 {
91 double number = 0;
92 unsigned char *after_end = NULL;
93 unsigned char number_c_string[64];
94 unsigned char decimal_point = '.';
95 int i = 0;
96
97 if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
98 return -1;
99 }
100
101 /* copy the number into a temporary buffer and replace '.' with the decimal
102 * point of the current locale (for strtod)
103 * This also takes care of '\0' not necessarily being available for marking
104 * the end of the input */
105 for (i = 0; (i < (sizeof(number_c_string) - 1)) &&
106 can_access_at_index(input_buffer, i);
107 i++) {
108 switch (buffer_at_offset(input_buffer)[i]) {
109 case '0':
110 case '1':
111 case '2':
112 case '3':
113 case '4':
114 case '5':
115 case '6':
116 case '7':
117 case '8':
118 case '9':
119 case '+':
120 case '-':
121 case 'e':
122 case 'E':
123 number_c_string[i] = buffer_at_offset(input_buffer)[i];
124 break;
125 case '.':
126 number_c_string[i] = decimal_point;
127 break;
128
129 default:
130 goto loop_end;
131 }
132 }
133 loop_end:
134 number_c_string[i] = '\0';
135 number = strtod((const char *)number_c_string, (char **)&after_end);
136 if (number_c_string == after_end) {
137 return -1;
138 }
139
140 item->type = cJSON_Number;
141 item->value = (char *)buffer_at_offset(input_buffer);
142 item->value_length = (int)(after_end - number_c_string);
143 item->value_double = number;
144
145 /* use saturation in case of overflow */
146 if (number >= INT_MAX) {
147 item->value_int = INT_MAX;
148 } else if (number <= INT_MIN) {
149 item->value_int = INT_MIN;
150 } else {
151 item->value_int = (int)number;
152 }
153
154 input_buffer->offset += (int)(after_end - number_c_string);
155 return 0;
156 }
157
158 /* Build an array from input text. */
parse_array(lite_cjson_t * const item,parse_buffer * const input_buffer)159 static int parse_array(lite_cjson_t *const item,
160 parse_buffer *const input_buffer)
161 {
162 lite_cjson_t current_item;
163 int start_pos = input_buffer->offset;
164 item->size = 0;
165
166 if (input_buffer->depth >= LITE_CJSON_NESTING_LIMIT) {
167 return -1; /* to deeply nested */
168 }
169 input_buffer->depth++;
170
171 if (buffer_at_offset(input_buffer)[0] != '[') {
172 /* not an array */
173 goto fail;
174 }
175
176 input_buffer->offset++;
177 buffer_skip_whitespace(input_buffer);
178 if (can_access_at_index(input_buffer, 0) &&
179 (buffer_at_offset(input_buffer)[0] == ']')) {
180 /* empty array */
181 goto success;
182 }
183
184 /* check if we skipped to the end of the buffer */
185 if (cannot_access_at_index(input_buffer, 0)) {
186 input_buffer->offset--;
187 goto fail;
188 }
189
190 /* step back to character in front of the first element */
191 input_buffer->offset--;
192 /* loop through the comma separated array elements */
193 do {
194 memset(¤t_item, 0, sizeof(lite_cjson_t));
195
196 /* parse next value */
197 input_buffer->offset++;
198 buffer_skip_whitespace(input_buffer);
199 if (parse_value(¤t_item, input_buffer) != 0) {
200 goto fail; /* failed to parse value */
201 }
202 buffer_skip_whitespace(input_buffer);
203
204 /* printf("current item index: %d, type: %d, length: %d, value: %.*s\n",
205 */
206 /* item->size+1, current_item.type, current_item.value_length,
207 * current_item.value_length, current_item.value); */
208
209 item->size++;
210 } while (can_access_at_index(input_buffer, 0) &&
211 (buffer_at_offset(input_buffer)[0] == ','));
212
213 if (cannot_access_at_index(input_buffer, 0) ||
214 buffer_at_offset(input_buffer)[0] != ']') {
215 goto fail; /* expected end of array */
216 }
217
218 success:
219 input_buffer->depth--;
220
221 item->type = cJSON_Array;
222 item->value = (char *)(input_buffer->content + start_pos);
223 item->value_length = input_buffer->offset - start_pos + 1;
224
225 input_buffer->offset++;
226
227 return 0;
228
229 fail:
230
231 return -1;
232 }
233
234 /* Build an object from the text. */
parse_object(lite_cjson_t * const item,parse_buffer * const input_buffer)235 static int parse_object(lite_cjson_t *const item,
236 parse_buffer *const input_buffer)
237 {
238 lite_cjson_t current_item_key;
239 lite_cjson_t current_item_value;
240 int start_pos = input_buffer->offset;
241 item->size = 0;
242
243 if (input_buffer->depth >= LITE_CJSON_NESTING_LIMIT) {
244 return -1; /* to deeply nested */
245 }
246 input_buffer->depth++;
247
248 if (cannot_access_at_index(input_buffer, 0) ||
249 (buffer_at_offset(input_buffer)[0] != '{')) {
250 goto fail; /* not an object */
251 }
252
253 input_buffer->offset++;
254 buffer_skip_whitespace(input_buffer);
255 if (can_access_at_index(input_buffer, 0) &&
256 (buffer_at_offset(input_buffer)[0] == '}')) {
257 goto success; /* empty object */
258 }
259
260 /* check if we skipped to the end of the buffer */
261 if (cannot_access_at_index(input_buffer, 0)) {
262 input_buffer->offset--;
263 goto fail;
264 }
265
266 /* step back to character in front of the first element */
267 input_buffer->offset--;
268 /* loop through the comma separated array elements */
269 do {
270 memset(¤t_item_key, 0, sizeof(lite_cjson_t));
271 memset(¤t_item_value, 0, sizeof(lite_cjson_t));
272
273 /* parse the name of the child */
274 input_buffer->offset++;
275 buffer_skip_whitespace(input_buffer);
276 if (parse_string(¤t_item_key, input_buffer) != 0) {
277 goto fail; /* faile to parse name */
278 }
279 buffer_skip_whitespace(input_buffer);
280
281 if (cannot_access_at_index(input_buffer, 0) ||
282 (buffer_at_offset(input_buffer)[0] != ':')) {
283 goto fail; /* invalid object */
284 }
285
286 /* parse the value */
287 input_buffer->offset++;
288 buffer_skip_whitespace(input_buffer);
289 if (parse_value(¤t_item_value, input_buffer) != 0) {
290 goto fail; /* failed to parse value */
291 }
292 buffer_skip_whitespace(input_buffer);
293
294 /* printf("Current Object [Index: %d], [Key Length: %d, Key Value:
295 * %.*s], [Value Length: %d, Value: %.*s]\n", */
296 /* item->size+1,current_item_key.value_length,current_item_key.value_length,current_item_key.value,
297 */
298 /* current_item_value.value_length,current_item_value.value_length,current_item_value.value);
299 */
300
301 item->size++;
302 } while (can_access_at_index(input_buffer, 0) &&
303 (buffer_at_offset(input_buffer)[0] == ','));
304
305 if (cannot_access_at_index(input_buffer, 0) ||
306 (buffer_at_offset(input_buffer)[0] != '}')) {
307 goto fail; /* expected end of object */
308 }
309
310 success:
311 input_buffer->depth--;
312
313 item->type = cJSON_Object;
314 item->value = (char *)(input_buffer->content + start_pos);
315 item->value_length = input_buffer->offset - start_pos + 1;
316
317 input_buffer->offset++;
318
319 return 0;
320
321 fail:
322
323 return -1;
324 }
325
326 /* Parse the input text into an unescaped cinput, and populate item. */
parse_string(lite_cjson_t * const item,parse_buffer * const input_buffer)327 static int parse_string(lite_cjson_t *const item,
328 parse_buffer *const input_buffer)
329 {
330 const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
331 const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
332 /* unsigned char *output_pointer = NULL; */
333 /* unsigned char *output = NULL; */
334
335 /* not a string */
336 if (buffer_at_offset(input_buffer)[0] != '\"') {
337 /* printf("not a string"); */
338 goto fail;
339 }
340
341 {
342 /* calculate approximate size of the output (overestimate) */
343 /* int allocation_length = 0; */
344 int skipped_bytes = 0;
345 while (
346 ((int)(input_end - input_buffer->content) < input_buffer->length) &&
347 (*input_end != '\"')) {
348 /* is escape sequence */
349 if (input_end[0] == '\\') {
350 if ((int)(input_end + 1 - input_buffer->content) >=
351 input_buffer->length) {
352 /* prevent buffer overflow when last input character is a
353 * backslash */
354 goto fail;
355 }
356 skipped_bytes++;
357 input_end++;
358 }
359 input_end++;
360 }
361 if (((int)(input_end - input_buffer->content) >=
362 input_buffer->length) ||
363 (*input_end != '\"')) {
364 /* printf("end error\n"); */
365 goto fail; /* string ended unexpectedly */
366 }
367 }
368
369 item->type = cJSON_String;
370 item->value = (char *)input_pointer;
371 item->value_length = input_end - input_pointer;
372
373 input_buffer->offset = (int)(input_end - input_buffer->content);
374 input_buffer->offset++;
375
376 return 0;
377
378 fail:
379 if (input_pointer != NULL) {
380 input_buffer->offset = (int)(input_pointer - input_buffer->content);
381 }
382
383 return -1;
384 }
385
386 /* Parser core - when encountering text, process appropriately. */
parse_value(lite_cjson_t * const lite,parse_buffer * const input_buffer)387 static int parse_value(lite_cjson_t *const lite,
388 parse_buffer *const input_buffer)
389 {
390 if ((input_buffer == NULL) || (input_buffer->content == NULL)) {
391 return -1; /* no input */
392 }
393
394 /* parse the different types of values */
395 /* null */
396 if (can_read(input_buffer, 4) &&
397 (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) ==
398 0)) {
399 lite->type = cJSON_NULL;
400 lite->value = (char *)buffer_at_offset(input_buffer);
401 lite->value_length = 4;
402
403 input_buffer->offset += 4;
404 return 0;
405 }
406 /* false */
407 if (can_read(input_buffer, 5) &&
408 (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) ==
409 0)) {
410 lite->type = cJSON_False;
411 lite->value = (char *)buffer_at_offset(input_buffer);
412 lite->value_length = 5;
413
414 input_buffer->offset += 5;
415 return 0;
416 }
417 /* true */
418 if (can_read(input_buffer, 4) &&
419 (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) ==
420 0)) {
421 lite->type = cJSON_True;
422 lite->value = (char *)buffer_at_offset(input_buffer);
423 lite->value_length = 4;
424
425 input_buffer->offset += 4;
426 return 0;
427 }
428 /* string */
429 if (can_access_at_index(input_buffer, 0) &&
430 (buffer_at_offset(input_buffer)[0] == '\"')) {
431 /* printf("parse string\n"); */
432 return parse_string(lite, input_buffer);
433 }
434
435 /* number */
436 if (can_access_at_index(input_buffer, 0) &&
437 ((buffer_at_offset(input_buffer)[0] == '-') ||
438 ((buffer_at_offset(input_buffer)[0] >= '0') &&
439 (buffer_at_offset(input_buffer)[0] <= '9')))) {
440 /* printf("parse number\n"); */
441 return parse_number(lite, input_buffer);
442 }
443
444 /* array */
445 if (can_access_at_index(input_buffer, 0) &&
446 (buffer_at_offset(input_buffer)[0] == '[')) {
447 /* printf("parse array\n"); */
448 return parse_array(lite, input_buffer);
449 }
450
451 /* object */
452 if (can_access_at_index(input_buffer, 0) &&
453 (buffer_at_offset(input_buffer)[0] == '{')) {
454 return parse_object(lite, input_buffer);
455 }
456
457 return -1;
458 }
459
lite_cjson_parse(const char * src,int src_len,lite_cjson_t * lite)460 int lite_cjson_parse(const char *src, int src_len, lite_cjson_t *lite)
461 {
462 parse_buffer buffer;
463
464 if (!lite || !src || !lite || src_len <= 0) {
465 return -1;
466 }
467
468 memset(&buffer, 0, sizeof(parse_buffer));
469 buffer.content = (const unsigned char *)src;
470 buffer.length = src_len;
471 buffer.offset = 0;
472
473 if (parse_value(lite, buffer_skip_whitespace(skip_utf8_bom(&buffer))) !=
474 0) {
475 lite->type = cJSON_Invalid;
476 lite->value = NULL;
477 lite->value_length = 0;
478 return -1;
479 }
480
481 return 0;
482 }
483
lite_cjson_is_number(lite_cjson_t * lite)484 int lite_cjson_is_number(lite_cjson_t *lite)
485 {
486 if (!lite) {
487 return -1;
488 }
489
490 return (lite->type & 0xFF) == cJSON_Number;
491 }
492
lite_cjson_is_string(lite_cjson_t * lite)493 int lite_cjson_is_string(lite_cjson_t *lite)
494 {
495 if (!lite) {
496 return -1;
497 }
498
499 return (lite->type & 0xFF) == cJSON_String;
500 }
501
lite_cjson_is_array(lite_cjson_t * lite)502 int lite_cjson_is_array(lite_cjson_t *lite)
503 {
504 if (!lite) {
505 return -1;
506 }
507
508 return (lite->type & 0xFF) == cJSON_Array;
509 }
510
lite_cjson_is_object(lite_cjson_t * lite)511 int lite_cjson_is_object(lite_cjson_t *lite)
512 {
513 if (!lite) {
514 return -1;
515 }
516
517 return (lite->type & 0xFF) == cJSON_Object;
518 }
519
lite_cjson_array_item(lite_cjson_t * lite,int index,lite_cjson_t * lite_item)520 int lite_cjson_array_item(lite_cjson_t *lite, int index,
521 lite_cjson_t *lite_item)
522 {
523 parse_buffer buffer;
524 parse_buffer *p_buffer = &buffer;
525 lite_cjson_t current_item;
526 int iter_index = 0;
527
528 if (!lite || lite->type != cJSON_Array || !lite->value || index < 0 ||
529 index >= lite->size || !lite_item) {
530 return -1;
531 }
532
533 memset(&buffer, 0, sizeof(parse_buffer));
534 buffer.content = (const unsigned char *)lite->value;
535 buffer.length = lite->value_length;
536 buffer.offset = 0;
537
538 /* int start_pos = p_buffer->offset; */
539
540 if (buffer_at_offset(p_buffer)[0] != '[') {
541 /* not an array */
542 return -1;
543 }
544
545 p_buffer->offset++;
546 buffer_skip_whitespace(p_buffer);
547 if (can_access_at_index(p_buffer, 0) &&
548 (buffer_at_offset(p_buffer)[0] == ']')) {
549 /* empty array */
550 return -1;
551 }
552
553 /* check if we skipped to the end of the buffer */
554 if (cannot_access_at_index(p_buffer, 0)) {
555 p_buffer->offset--;
556 return -1;
557 }
558
559 /* step back to character in front of the first element */
560 p_buffer->offset--;
561 /* loop through the comma separated array elements */
562 do {
563 memset(¤t_item, 0, sizeof(lite_cjson_t));
564
565 /* parse next value */
566 p_buffer->offset++;
567 buffer_skip_whitespace(p_buffer);
568 if (parse_value(¤t_item, p_buffer) != 0) {
569 return -1; /* failed to parse value */
570 }
571 buffer_skip_whitespace(p_buffer);
572
573 /* printf("current item index: %d, type: %d, length: %d, value: %.*s\n",
574 */
575 /* iter_index+1, current_item.type, current_item.value_length,
576 * current_item.value_length, current_item.value); */
577
578 if (iter_index == index) {
579 memcpy(lite_item, ¤t_item, sizeof(lite_cjson_t));
580 return 0;
581 }
582
583 iter_index++;
584 } while (can_access_at_index(p_buffer, 0) &&
585 (buffer_at_offset(p_buffer)[0] == ','));
586
587 return -1;
588 }
589
_lite_cjson_object_item(lite_cjson_t * lite,const char * key,int key_len,lite_cjson_t * lite_item)590 static int _lite_cjson_object_item(lite_cjson_t *lite, const char *key,
591 int key_len, lite_cjson_t *lite_item)
592 {
593 parse_buffer buffer;
594 parse_buffer *p_buffer = &buffer;
595 lite_cjson_t current_item_key;
596 lite_cjson_t current_item_value;
597 int index = 0;
598
599 if (!lite || lite->type != cJSON_Object || !lite->value ||
600 lite->size == 0 || !key || key_len <= 0 || !lite_item) {
601 return -1;
602 };
603
604 memset(&buffer, 0, sizeof(parse_buffer));
605 buffer.content = (const unsigned char *)lite->value;
606 buffer.length = lite->value_length;
607 buffer.offset = 0;
608
609 /* int start_pos = p_buffer->offset; */
610
611 if (cannot_access_at_index(p_buffer, 0) ||
612 (buffer_at_offset(p_buffer)[0] != '{')) {
613 return -1; /* not an object */
614 }
615
616 p_buffer->offset++;
617 buffer_skip_whitespace(p_buffer);
618 if (can_access_at_index(p_buffer, 0) &&
619 (buffer_at_offset(p_buffer)[0] == '}')) {
620 return -1; /* empty object */
621 }
622
623 /* check if we skipped to the end of the buffer */
624 if (cannot_access_at_index(p_buffer, 0)) {
625 p_buffer->offset--;
626 return -1;
627 }
628
629 /* step back to character in front of the first element */
630 p_buffer->offset--;
631 /* loop through the comma separated array elements */
632 do {
633 memset(¤t_item_key, 0, sizeof(lite_cjson_t));
634 memset(¤t_item_value, 0, sizeof(lite_cjson_t));
635
636 /* parse the name of the child */
637 p_buffer->offset++;
638 buffer_skip_whitespace(p_buffer);
639 if (parse_string(¤t_item_key, p_buffer) != 0) {
640 return -1; /* faile to parse name */
641 }
642 buffer_skip_whitespace(p_buffer);
643
644 if (cannot_access_at_index(p_buffer, 0) ||
645 (buffer_at_offset(p_buffer)[0] != ':')) {
646 return -1; /* invalid object */
647 }
648
649 /* parse the value */
650 p_buffer->offset++;
651 buffer_skip_whitespace(p_buffer);
652 if (parse_value(¤t_item_value, p_buffer) != 0) {
653 return -1; /* failed to parse value */
654 }
655 buffer_skip_whitespace(p_buffer);
656
657 /* printf("Current Object [Index: %d], [Key Length: %d, Key Value:
658 * %.*s], [Value Length: %d, Value: %.*s]\n", */
659 /* index + 1,
660 * current_item_key.value_length,current_item_key.value_length,current_item_key.value,
661 */
662 /* current_item_value.value_length,current_item_value.value_length,current_item_value.value);
663 */
664 index++;
665
666 /* printf("key: %s, ken_len: %d\n",key,key_len); */
667 if ((current_item_key.value_length == key_len) &&
668 memcmp(current_item_key.value, key, key_len) == 0) {
669 memcpy(lite_item, ¤t_item_value, sizeof(lite_cjson_t));
670 return 0;
671 }
672 } while (can_access_at_index(p_buffer, 0) &&
673 (buffer_at_offset(p_buffer)[0] == ','));
674
675 return -1;
676 }
677
_lite_cjson_key_array_index(const char * key,int key_len,int * partial_key_len,int * array_key_len,int * array_index)678 static int _lite_cjson_key_array_index(const char *key, int key_len,
679 int *partial_key_len, int *array_key_len,
680 int *array_index)
681 {
682 char *bracket_pre = NULL;
683 char *bracket_suf = NULL;
684 int index = 0;
685 int deep = 0;
686 char array_index_str[11] = { 0 };
687
688 if (!key || !partial_key_len || !array_key_len || !array_index) {
689 return -1;
690 }
691
692 for (index = 0; index < key_len; index++) {
693 switch (key[index]) {
694 case '[':
695 {
696 if (deep != 0) {
697 return -1;
698 }
699 deep++;
700 if (!bracket_pre) {
701 bracket_pre = (char *)&key[index];
702 }
703 }
704 break;
705 case ']':
706 {
707 if (deep != 1) {
708 return -1;
709 }
710 deep--;
711 if (key[index - 1] == '[') {
712 return -1;
713 }
714 if (!bracket_suf) {
715 bracket_suf = (char *)&key[index];
716 }
717 }
718 break;
719 default:
720 break;
721 }
722 }
723
724 if (bracket_pre && bracket_suf && ((bracket_suf - key + 1) == key_len)) {
725 *partial_key_len = bracket_pre - key;
726 *array_key_len = bracket_suf - key + 1;
727
728 /* Get Index */
729 if (bracket_suf - bracket_pre - 1 > 10) {
730 return -1;
731 }
732 memcpy(array_index_str, bracket_pre + 1, bracket_suf - bracket_pre - 1);
733 *array_index = atoi(array_index_str);
734 return 0;
735 }
736
737 return -1;
738 }
739
lite_cjson_object_item(lite_cjson_t * lite,const char * key,int key_len,lite_cjson_t * lite_item)740 int lite_cjson_object_item(lite_cjson_t *lite, const char *key, int key_len,
741 lite_cjson_t *lite_item)
742 {
743 int res = 0;
744 char *delim = NULL;
745 lite_cjson_t lite_prev;
746 lite_cjson_t lite_next;
747 lite_cjson_t lite_iter;
748 char *key_iter = (char *)key;
749 int key_iter_len = 0;
750 int partial_key_len = 0;
751 int array_key_len = 0;
752 int array_index = 0;
753
754 if (!lite || lite->type != cJSON_Object || !lite->value ||
755 lite->size == 0 || !key || key_len <= 0 || !lite_item) {
756 return -1;
757 };
758
759 memcpy(&lite_iter, lite, sizeof(lite_cjson_t));
760 memset(&lite_prev, 0, sizeof(lite_cjson_t));
761
762 do {
763 delim = strchr(key_iter, '.');
764 if (delim != NULL) {
765 /* printf("delim exist,delim : %s\n",delim); */
766 memset(&lite_next, 0, sizeof(lite_cjson_t));
767 partial_key_len = array_key_len = array_index = 0;
768 key_iter_len = (int)(delim - key_iter);
769 } else {
770 key_iter_len = key_len - (key_iter - key);
771 /* printf("key: %s, last key: %s, key len: %d, last key len:
772 * %d\n",key, key_iter, key_len, key_iter_len); */
773 }
774
775 if (_lite_cjson_key_array_index(key_iter, key_iter_len,
776 &partial_key_len, &array_key_len,
777 &array_index) == 0) {
778 /* printf("partial_key_len: %d, array_key_len: %d, array_index:
779 * %d\n", partial_key_len, array_key_len, array_index); */
780
781 res = _lite_cjson_object_item(&lite_iter, key_iter, partial_key_len,
782 &lite_prev);
783 if (res || lite_prev.type != cJSON_Array) {
784 return -1;
785 }
786 /* printf("current array:
787 * %.*s\n",lite_prev.value_length,lite_prev.value); */
788
789 res = lite_cjson_array_item(&lite_prev, array_index, &lite_next);
790 if (res) {
791 return -1;
792 }
793 /* printf("current array item:
794 * %.*s\n",lite_next.value_length,lite_next.value); */
795
796 memcpy(&lite_iter, &lite_next, sizeof(lite_cjson_t));
797 key_iter += array_key_len + 1;
798 /* printf("key_iter: %s\n",key_iter); */
799 } else {
800 res = _lite_cjson_object_item(&lite_iter, key_iter, key_iter_len,
801 &lite_prev);
802 if (res) {
803 return -1;
804 }
805 /* printf("current object:
806 * %.*s\n",lite_prev.value_length,lite_prev.value); */
807
808 memcpy(&lite_iter, &lite_prev, sizeof(lite_cjson_t));
809 key_iter = delim + 1;
810 }
811 } while (delim);
812
813 /* printf("final lite cjson value:
814 * %.*s\n",lite_iter.value_length,lite_iter.value); */
815 memcpy(lite_item, &lite_iter, sizeof(lite_cjson_t));
816
817 return 0;
818 }
819
lite_cjson_object_item_by_index(lite_cjson_t * lite,int index,lite_cjson_t * lite_item_key,lite_cjson_t * lite_item_value)820 int lite_cjson_object_item_by_index(lite_cjson_t *lite, int index,
821 lite_cjson_t *lite_item_key,
822 lite_cjson_t *lite_item_value)
823 {
824 parse_buffer buffer;
825 parse_buffer *p_buffer = &buffer;
826 lite_cjson_t current_item_key;
827 lite_cjson_t current_item_value;
828 /* int start_pos = p_buffer->offset; */
829 int item_index = 0;
830
831 if (!lite || lite->type != cJSON_Object || !lite->value ||
832 lite->size == 0 || index < 0 || index >= lite->size) {
833 return -1;
834 };
835
836 memset(&buffer, 0, sizeof(parse_buffer));
837 buffer.content = (const unsigned char *)lite->value;
838 buffer.length = lite->value_length;
839 buffer.offset = 0;
840
841 if (cannot_access_at_index(p_buffer, 0) ||
842 (buffer_at_offset(p_buffer)[0] != '{')) {
843 return -1; /* not an object */
844 }
845
846 p_buffer->offset++;
847 buffer_skip_whitespace(p_buffer);
848 if (can_access_at_index(p_buffer, 0) &&
849 (buffer_at_offset(p_buffer)[0] == '}')) {
850 return -1; /* empty object */
851 }
852
853 /* check if we skipped to the end of the buffer */
854 if (cannot_access_at_index(p_buffer, 0)) {
855 p_buffer->offset--;
856 return -1;
857 }
858
859 /* step back to character in front of the first element */
860 p_buffer->offset--;
861 /* loop through the comma separated array elements */
862 do {
863 memset(¤t_item_key, 0, sizeof(lite_cjson_t));
864 memset(¤t_item_value, 0, sizeof(lite_cjson_t));
865
866 /* parse the name of the child */
867 p_buffer->offset++;
868 buffer_skip_whitespace(p_buffer);
869 if (parse_string(¤t_item_key, p_buffer) != 0) {
870 return -1; /* faile to parse name */
871 }
872 buffer_skip_whitespace(p_buffer);
873
874 if (cannot_access_at_index(p_buffer, 0) ||
875 (buffer_at_offset(p_buffer)[0] != ':')) {
876 return -1; /* invalid object */
877 }
878
879 /* parse the value */
880 p_buffer->offset++;
881 buffer_skip_whitespace(p_buffer);
882 if (parse_value(¤t_item_value, p_buffer) != 0) {
883 return -1; /* failed to parse value */
884 }
885 buffer_skip_whitespace(p_buffer);
886
887 /* printf("Current Object [Index: %d], [Key Length: %d, Key Value:
888 * %.*s], [Value Length: %d, Value: %.*s]\n", */
889 /* index + 1,
890 * current_item_key.value_length,current_item_key.value_length,current_item_key.value,
891 */
892 /* current_item_value.value_length,current_item_value.value_length,current_item_value.value);
893 */
894
895 /* printf("index:%d, key: %.*s, value: %.*s\n",index, */
896 /* current_item_key.value_length,current_item_key.value, */
897 /* current_item_value.value_length,current_item_value.value); */
898
899 if (item_index == index) {
900 if (lite_item_key) {
901 memcpy(lite_item_key, ¤t_item_key, sizeof(lite_cjson_t));
902 }
903 if (lite_item_value) {
904 memcpy(lite_item_value, ¤t_item_value,
905 sizeof(lite_cjson_t));
906 }
907 return 0;
908 }
909
910 item_index++;
911 } while (can_access_at_index(p_buffer, 0) &&
912 (buffer_at_offset(p_buffer)[0] == ','));
913
914 return -1;
915 }
916
917 /*** cjson create, add and print ***/
918 #if defined(DEVICE_MODEL_GATEWAY) || defined(ALCS_ENABLED) || \
919 defined(DEPRECATED_LINKKIT)
920 #define true ((cJSON_bool)1)
921 #define false ((cJSON_bool)0)
922 #define cjson_min(a, b) ((a < b) ? a : b)
923
924 typedef struct internal_hooks {
925 void *(*allocate)(uint32_t size);
926 void (*deallocate)(void *pointer);
927 void *(*reallocate)(void *pointer, size_t size);
928 } internal_hooks;
929
930 typedef struct {
931 unsigned char *buffer;
932 size_t length;
933 size_t offset;
934 size_t depth; /* current nesting depth (for formatted printing) */
935 cJSON_bool noalloc;
936 cJSON_bool format; /* is this print a formatted print */
937 internal_hooks hooks;
938 } printbuffer;
939
940 void *HAL_Malloc(uint32_t size);
941 void HAL_Free(void *ptr);
942
internal_malloc(uint32_t size)943 static void *internal_malloc(uint32_t size)
944 {
945 return HAL_Malloc(size);
946 }
947
internal_free(void * ptr)948 static void internal_free(void *ptr)
949 {
950 HAL_Free(ptr);
951 }
952
953 static internal_hooks global_hooks = { internal_malloc, internal_free, NULL };
954 static cJSON_bool print_value(const lite_cjson_item_t *const item,
955 printbuffer * const output_buffer);
956
lite_cjson_init_hooks(lite_cjson_hooks * hooks)957 void lite_cjson_init_hooks(lite_cjson_hooks *hooks)
958 {
959 if (hooks == NULL || hooks->malloc_fn == NULL || hooks->free_fn == NULL) {
960 return;
961 }
962
963 global_hooks.allocate = hooks->malloc_fn;
964 global_hooks.deallocate = hooks->free_fn;
965 }
966
ensure(printbuffer * const p,size_t needed)967 static unsigned char *ensure(printbuffer * const p, size_t needed)
968 {
969 unsigned char *newbuffer = NULL;
970 size_t newsize = 0;
971
972 if ((p == NULL) || (p->buffer == NULL)) {
973 return NULL;
974 }
975
976 if ((p->length > 0) && (p->offset >= p->length)) {
977 /* make sure that offset is valid */
978 return NULL;
979 }
980
981 if (needed > INT_MAX) {
982 /* sizes bigger than INT_MAX are currently not supported */
983 return NULL;
984 }
985
986 needed += p->offset + 1;
987 if (needed <= p->length) {
988 return p->buffer + p->offset;
989 }
990
991 if (p->noalloc) {
992 return NULL;
993 }
994
995 /* calculate new buffer size */
996 if (needed > (INT_MAX / 2)) {
997 /* overflow of int, use INT_MAX if possible */
998 if (needed <= INT_MAX) {
999 newsize = INT_MAX;
1000 } else {
1001 return NULL;
1002 }
1003 } else {
1004 newsize = needed * 2;
1005 }
1006
1007 if (p->hooks.reallocate != NULL) {
1008 /* reallocate with realloc if available */
1009 newbuffer = (unsigned char *)p->hooks.reallocate(p->buffer, newsize);
1010 if (newbuffer == NULL) {
1011 p->hooks.deallocate(p->buffer);
1012 p->length = 0;
1013 p->buffer = NULL;
1014
1015 return NULL;
1016 }
1017 } else {
1018 /* otherwise reallocate manually */
1019 newbuffer = (unsigned char *)p->hooks.allocate(newsize);
1020 if (!newbuffer) {
1021 p->hooks.deallocate(p->buffer);
1022 p->length = 0;
1023 p->buffer = NULL;
1024
1025 return NULL;
1026 }
1027 if (newbuffer) {
1028 memcpy(newbuffer, p->buffer, p->offset + 1);
1029 }
1030 p->hooks.deallocate(p->buffer);
1031 }
1032 p->length = newsize;
1033 p->buffer = newbuffer;
1034
1035 return newbuffer + p->offset;
1036 }
1037
1038 /* get the decimal point character of the current locale */
get_decimal_point(void)1039 static unsigned char get_decimal_point(void)
1040 {
1041 #ifdef ENABLE_LOCALES
1042 struct lconv *lconv = localeconv();
1043 return (unsigned char)lconv->decimal_point[0];
1044 #else
1045 return '.';
1046 #endif
1047 }
1048
remove_zero(unsigned char buffer[26],int length)1049 static int remove_zero(unsigned char buffer[26], int length)
1050 {
1051 int idx = 0, found = 0;
1052
1053 for (idx = 0; idx < 26; idx++) {
1054 if (buffer[idx] == '.') {
1055 found = 1;
1056 continue;
1057 }
1058 if (buffer[idx] == '\0') {
1059 break;
1060 }
1061 }
1062
1063 if (found == 0) {
1064 return length;
1065 }
1066
1067 for (; idx > 0; idx--) {
1068 if (buffer[idx - 1] == '0') {
1069 buffer[idx - 1] = '\0';
1070 length--;
1071 } else {
1072 if (buffer[idx - 1] == '.') {
1073 buffer[idx - 1] = '\0';
1074 length--;
1075 }
1076 break;
1077 }
1078 }
1079
1080 return length;
1081 }
1082
1083 /* Render the number nicely from the given item into a string. */
print_number(const lite_cjson_item_t * const item,printbuffer * const output_buffer)1084 static cJSON_bool print_number(const lite_cjson_item_t *const item,
1085 printbuffer * const output_buffer)
1086 {
1087 unsigned char *output_pointer = NULL;
1088 double d = item->valuedouble;
1089 int length = 0;
1090 size_t i = 0;
1091 unsigned char
1092 number_buffer[26]; /* temporary buffer to print the number into */
1093 unsigned char decimal_point = get_decimal_point();
1094 float test_float;
1095 double test;
1096
1097 if (output_buffer == NULL) {
1098 return false;
1099 }
1100
1101 /* This checks for NaN and Infinity */
1102 if ((d * 0) != 0) {
1103 length = sprintf((char *)number_buffer, "null");
1104 } else {
1105 /* Try float data type */
1106 length = sprintf((char *)number_buffer, "%f", d);
1107
1108 if ((sscanf((char *)number_buffer, "%f", &test_float) != 1) ||
1109 ((double)test_float != d)) {
1110 /* Try 15 decimal places of precision to avoid nonsignificant
1111 * nonzero digits */
1112 length = sprintf((char *)number_buffer, "%1.15g", d);
1113
1114 /* Check whether the original double can be recovered */
1115 if ((sscanf((char *)number_buffer, "%lg", &test) != 1) ||
1116 ((double)test != d)) {
1117 /* If not, print with 17 decimal places of precision */
1118 length = sprintf((char *)number_buffer, "%1.17g", d);
1119 }
1120 } else {
1121 length = remove_zero(number_buffer, length);
1122 }
1123 }
1124
1125 /* sprintf failed or buffer overrun occured */
1126 if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) {
1127 return false;
1128 }
1129
1130 /* reserve appropriate space in the output */
1131 output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
1132 if (output_pointer == NULL) {
1133 return false;
1134 }
1135
1136 /* copy the printed number to the output and replace locale
1137 * dependent decimal point with '.' */
1138 for (i = 0; i < ((size_t)length); i++) {
1139 if (number_buffer[i] == decimal_point) {
1140 output_pointer[i] = '.';
1141 continue;
1142 }
1143
1144 output_pointer[i] = number_buffer[i];
1145 }
1146 output_pointer[i] = '\0';
1147
1148 output_buffer->offset += (size_t)length;
1149
1150 return true;
1151 }
1152
1153 /* Render the cstring provided to an escaped version that can be printed. */
print_string_ptr(const unsigned char * const input,printbuffer * const output_buffer)1154 static cJSON_bool print_string_ptr(const unsigned char *const input,
1155 printbuffer * const output_buffer)
1156 {
1157 const unsigned char *input_pointer = NULL;
1158 unsigned char *output = NULL;
1159 unsigned char *output_pointer = NULL;
1160 size_t output_length = 0;
1161 /* numbers of additional characters needed for escaping */
1162 size_t escape_characters = 0;
1163
1164 if (output_buffer == NULL) {
1165 return false;
1166 }
1167
1168 /* empty string */
1169 if (input == NULL) {
1170 output = ensure(output_buffer, sizeof("\"\""));
1171 if (output == NULL) {
1172 return false;
1173 }
1174 strcpy((char *)output, "\"\"");
1175
1176 return true;
1177 }
1178
1179 /* set "flag" to 1 if something needs to be escaped */
1180 for (input_pointer = input; *input_pointer; input_pointer++) {
1181 switch (*input_pointer) {
1182 case '\"':
1183 case '\\':
1184 case '\b':
1185 case '\f':
1186 case '\n':
1187 case '\r':
1188 case '\t':
1189 /* one character escape sequence */
1190 escape_characters++;
1191 break;
1192 default:
1193 if (*input_pointer < 32) {
1194 /* UTF-16 escape sequence uXXXX */
1195 escape_characters += 5;
1196 }
1197 break;
1198 }
1199 }
1200 output_length = (size_t)(input_pointer - input) + escape_characters;
1201
1202 output = ensure(output_buffer, output_length + sizeof("\"\""));
1203 if (output == NULL) {
1204 return false;
1205 }
1206
1207 /* no characters have to be escaped */
1208 if (escape_characters == 0) {
1209 output[0] = '\"';
1210 memcpy(output + 1, input, output_length);
1211 output[output_length + 1] = '\"';
1212 output[output_length + 2] = '\0';
1213
1214 return true;
1215 }
1216
1217 output[0] = '\"';
1218 output_pointer = output + 1;
1219 /* copy the string */
1220 for (input_pointer = input; *input_pointer != '\0';
1221 (void)input_pointer++, output_pointer++) {
1222 if ((*input_pointer > 31) && (*input_pointer != '\"') &&
1223 (*input_pointer != '\\')) {
1224 /* normal character, copy */
1225 *output_pointer = *input_pointer;
1226 } else {
1227 /* character needs to be escaped */
1228 *output_pointer++ = '\\';
1229 switch (*input_pointer) {
1230 case '\\':
1231 *output_pointer = '\\';
1232 break;
1233 case '\"':
1234 *output_pointer = '\"';
1235 break;
1236 case '\b':
1237 *output_pointer = 'b';
1238 break;
1239 case '\f':
1240 *output_pointer = 'f';
1241 break;
1242 case '\n':
1243 *output_pointer = 'n';
1244 break;
1245 case '\r':
1246 *output_pointer = 'r';
1247 break;
1248 case '\t':
1249 *output_pointer = 't';
1250 break;
1251 default:
1252 /* escape and print as unicode codepoint */
1253 sprintf((char *)output_pointer, "u%04x", *input_pointer);
1254 output_pointer += 4;
1255 break;
1256 }
1257 }
1258 }
1259 output[output_length + 1] = '\"';
1260 output[output_length + 2] = '\0';
1261
1262 return true;
1263 }
1264
1265 /* Invoke print_string_ptr (which is useful) on an item. */
print_string(const lite_cjson_item_t * const item,printbuffer * const p)1266 static cJSON_bool print_string(const lite_cjson_item_t *const item,
1267 printbuffer * const p)
1268 {
1269 return print_string_ptr((unsigned char *)item->valuestring, p);
1270 }
1271
1272 /* calculate the new length of the string in a printbuffer and update the offset
1273 */
update_offset(printbuffer * const buffer)1274 static void update_offset(printbuffer * const buffer)
1275 {
1276 const unsigned char *buffer_pointer = NULL;
1277 if ((buffer == NULL) || (buffer->buffer == NULL)) {
1278 return;
1279 }
1280 buffer_pointer = buffer->buffer + buffer->offset;
1281
1282 buffer->offset += strlen((const char *)buffer_pointer);
1283 }
1284
1285 /* Render an array to text */
print_array(const lite_cjson_item_t * const item,printbuffer * const output_buffer)1286 static cJSON_bool print_array(const lite_cjson_item_t *const item,
1287 printbuffer * const output_buffer)
1288 {
1289 unsigned char *output_pointer = NULL;
1290 size_t length = 0;
1291 lite_cjson_item_t *current_element = item->child;
1292
1293 if (output_buffer == NULL) {
1294 return false;
1295 }
1296
1297 /* Compose the output array. */
1298 /* opening square bracket */
1299 output_pointer = ensure(output_buffer, 1);
1300 if (output_pointer == NULL) {
1301 return false;
1302 }
1303
1304 *output_pointer = '[';
1305 output_buffer->offset++;
1306 output_buffer->depth++;
1307
1308 while (current_element != NULL) {
1309 if (!print_value(current_element, output_buffer)) {
1310 return false;
1311 }
1312 update_offset(output_buffer);
1313 if (current_element->next) {
1314 length = (size_t)(output_buffer->format ? 2 : 1);
1315 output_pointer = ensure(output_buffer, length + 1);
1316 if (output_pointer == NULL) {
1317 return false;
1318 }
1319 *output_pointer++ = ',';
1320 if (output_buffer->format) {
1321 *output_pointer++ = ' ';
1322 }
1323 *output_pointer = '\0';
1324 output_buffer->offset += length;
1325 }
1326 current_element = current_element->next;
1327 }
1328
1329 output_pointer = ensure(output_buffer, 2);
1330 if (output_pointer == NULL) {
1331 return false;
1332 }
1333 *output_pointer++ = ']';
1334 *output_pointer = '\0';
1335 output_buffer->depth--;
1336
1337 return true;
1338 }
1339
1340 /* Render an object to text. */
print_object(const lite_cjson_item_t * const item,printbuffer * const output_buffer)1341 static cJSON_bool print_object(const lite_cjson_item_t *const item,
1342 printbuffer * const output_buffer)
1343 {
1344 unsigned char *output_pointer = NULL;
1345 size_t length = 0;
1346 lite_cjson_item_t *current_item = item->child;
1347
1348 if (output_buffer == NULL) {
1349 return false;
1350 }
1351
1352 /* Compose the output: */
1353 length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */
1354 output_pointer = ensure(output_buffer, length + 1);
1355 if (output_pointer == NULL) {
1356 return false;
1357 }
1358
1359 *output_pointer++ = '{';
1360 output_buffer->depth++;
1361 if (output_buffer->format) {
1362 *output_pointer++ = '\n';
1363 }
1364 output_buffer->offset += length;
1365
1366 while (current_item) {
1367 if (output_buffer->format) {
1368 size_t i;
1369 output_pointer = ensure(output_buffer, output_buffer->depth);
1370 if (output_pointer == NULL) {
1371 return false;
1372 }
1373 for (i = 0; i < output_buffer->depth; i++) {
1374 *output_pointer++ = '\t';
1375 }
1376 output_buffer->offset += output_buffer->depth;
1377 }
1378
1379 /* print key */
1380 if (!print_string_ptr((unsigned char *)current_item->string,
1381 output_buffer)) {
1382 return false;
1383 }
1384 update_offset(output_buffer);
1385
1386 length = (size_t)(output_buffer->format ? 2 : 1);
1387 output_pointer = ensure(output_buffer, length);
1388 if (output_pointer == NULL) {
1389 return false;
1390 }
1391 *output_pointer++ = ':';
1392 if (output_buffer->format) {
1393 *output_pointer++ = '\t';
1394 }
1395 output_buffer->offset += length;
1396
1397 /* print value */
1398 if (!print_value(current_item, output_buffer)) {
1399 return false;
1400 }
1401 update_offset(output_buffer);
1402
1403 /* print comma if not last */
1404 length = (size_t)((output_buffer->format ? 1 : 0) +
1405 (current_item->next ? 1 : 0));
1406 output_pointer = ensure(output_buffer, length + 1);
1407 if (output_pointer == NULL) {
1408 return false;
1409 }
1410 if (current_item->next) {
1411 *output_pointer++ = ',';
1412 }
1413
1414 if (output_buffer->format) {
1415 *output_pointer++ = '\n';
1416 }
1417 *output_pointer = '\0';
1418 output_buffer->offset += length;
1419
1420 current_item = current_item->next;
1421 }
1422
1423 output_pointer = ensure(
1424 output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
1425 if (output_pointer == NULL) {
1426 return false;
1427 }
1428 if (output_buffer->format) {
1429 size_t i;
1430 for (i = 0; i < (output_buffer->depth - 1); i++) {
1431 *output_pointer++ = '\t';
1432 }
1433 }
1434 *output_pointer++ = '}';
1435 *output_pointer = '\0';
1436 output_buffer->depth--;
1437
1438 return true;
1439 }
1440
1441 /* Render a value to text. */
print_value(const lite_cjson_item_t * const item,printbuffer * const output_buffer)1442 static cJSON_bool print_value(const lite_cjson_item_t *const item,
1443 printbuffer * const output_buffer)
1444 {
1445 unsigned char *output = NULL;
1446
1447 if ((item == NULL) || (output_buffer == NULL)) {
1448 return false;
1449 }
1450
1451 switch ((item->type) & 0xFF) {
1452 case cJSON_NULL:
1453 output = ensure(output_buffer, 5);
1454 if (output == NULL) {
1455 return false;
1456 }
1457 strcpy((char *)output, "null");
1458 return true;
1459
1460 case cJSON_False:
1461 output = ensure(output_buffer, 6);
1462 if (output == NULL) {
1463 return false;
1464 }
1465 strcpy((char *)output, "false");
1466 return true;
1467
1468 case cJSON_True:
1469 output = ensure(output_buffer, 5);
1470 if (output == NULL) {
1471 return false;
1472 }
1473 strcpy((char *)output, "true");
1474 return true;
1475
1476 case cJSON_Number:
1477 return print_number(item, output_buffer);
1478
1479 case cJSON_Raw:
1480 {
1481 size_t raw_length = 0;
1482 if (item->valuestring == NULL) {
1483 return false;
1484 }
1485
1486 raw_length = strlen(item->valuestring) + sizeof("");
1487 output = ensure(output_buffer, raw_length);
1488 if (output == NULL) {
1489 return false;
1490 }
1491 memcpy(output, item->valuestring, raw_length);
1492 return true;
1493 }
1494
1495 case cJSON_String:
1496 return print_string(item, output_buffer);
1497
1498 case cJSON_Array:
1499 return print_array(item, output_buffer);
1500
1501 case cJSON_Object:
1502 return print_object(item, output_buffer);
1503
1504 default:
1505 return false;
1506 }
1507 }
1508
print(const lite_cjson_item_t * const item,cJSON_bool format,const internal_hooks * const hooks)1509 static unsigned char *print(const lite_cjson_item_t *const item,
1510 cJSON_bool format,
1511 const internal_hooks *const hooks)
1512 {
1513 static const size_t default_buffer_size = 256;
1514 printbuffer buffer[1];
1515 unsigned char *printed = NULL;
1516
1517 memset(buffer, 0, sizeof(buffer));
1518
1519 /* create buffer */
1520 buffer->buffer = (unsigned char *)hooks->allocate(default_buffer_size);
1521 buffer->length = default_buffer_size;
1522 buffer->format = format;
1523 buffer->hooks = *hooks;
1524 if (buffer->buffer == NULL) {
1525 goto fail;
1526 }
1527
1528 /* print the value */
1529 if (!print_value(item, buffer)) {
1530 goto fail;
1531 }
1532 update_offset(buffer);
1533
1534 /* check if reallocate is available */
1535 if (hooks->reallocate != NULL) {
1536 printed = (unsigned char *)hooks->reallocate(buffer->buffer,
1537 buffer->offset + 1);
1538 if (printed == NULL) {
1539 goto fail;
1540 }
1541 buffer->buffer = NULL;
1542 } else { /* otherwise copy the JSON over to a new buffer */
1543 printed = (unsigned char *)hooks->allocate(buffer->offset + 1);
1544 if (printed == NULL) {
1545 goto fail;
1546 }
1547 memcpy(printed, buffer->buffer,
1548 cjson_min(buffer->length, buffer->offset + 1));
1549 printed[buffer->offset] = '\0'; /* just to be sure */
1550
1551 /* free the buffer */
1552 hooks->deallocate(buffer->buffer);
1553 }
1554
1555 return printed;
1556
1557 fail:
1558 if (buffer->buffer != NULL) {
1559 hooks->deallocate(buffer->buffer);
1560 }
1561
1562 return NULL;
1563 }
1564
lite_cjson_print(lite_cjson_item_t * item)1565 char *lite_cjson_print(lite_cjson_item_t *item)
1566 {
1567 return (char *)print(item, true, &global_hooks);
1568 }
1569
lite_cjson_print_unformatted(lite_cjson_item_t * item)1570 char *lite_cjson_print_unformatted(lite_cjson_item_t *item)
1571 {
1572 return (char *)print(item, false, &global_hooks);
1573 }
1574
1575 /* Delete a cJSON structure. */
lite_cjson_delete(lite_cjson_item_t * item)1576 void lite_cjson_delete(lite_cjson_item_t *item)
1577 {
1578 lite_cjson_item_t *next = NULL;
1579 while (item != NULL) {
1580 next = item->next;
1581 if (!(item->type & cJSON_IsReference) && (item->child != NULL)) {
1582 lite_cjson_delete(item->child);
1583 }
1584 if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) {
1585 global_hooks.deallocate(item->valuestring);
1586 }
1587 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
1588 global_hooks.deallocate(item->string);
1589 }
1590 global_hooks.deallocate(item);
1591 item = next;
1592 }
1593 }
1594
suffix_object(lite_cjson_item_t * prev,lite_cjson_item_t * item)1595 static void suffix_object(lite_cjson_item_t *prev, lite_cjson_item_t *item)
1596 {
1597 prev->next = item;
1598 item->prev = prev;
1599 }
1600
add_item_to_array(lite_cjson_item_t * array,lite_cjson_item_t * item)1601 static cJSON_bool add_item_to_array(lite_cjson_item_t *array,
1602 lite_cjson_item_t *item)
1603 {
1604 lite_cjson_item_t *child = NULL;
1605
1606 if ((item == NULL) || (array == NULL)) {
1607 return false;
1608 }
1609
1610 child = array->child;
1611
1612 if (child == NULL) {
1613 /* list is empty, start new one */
1614 array->child = item;
1615 } else {
1616 /* append to the end */
1617 while (child->next) {
1618 child = child->next;
1619 }
1620 suffix_object(child, item);
1621 }
1622
1623 return true;
1624 }
1625
lite_cjson_add_item_to_array(lite_cjson_item_t * array,lite_cjson_item_t * item)1626 void lite_cjson_add_item_to_array(lite_cjson_item_t *array,
1627 lite_cjson_item_t *item)
1628 {
1629 add_item_to_array(array, item);
1630 }
1631
cast_away_const(const void * string)1632 static void *cast_away_const(const void *string)
1633 {
1634 return (void *)string;
1635 }
1636
cJSON_strdup(const unsigned char * string,const internal_hooks * const hooks)1637 static unsigned char *cJSON_strdup(const unsigned char *string,
1638 const internal_hooks *const hooks)
1639 {
1640 size_t length = 0;
1641 unsigned char *copy = NULL;
1642
1643 if (string == NULL) {
1644 return NULL;
1645 }
1646
1647 length = strlen((const char *)string) + sizeof("");
1648 copy = (unsigned char *)hooks->allocate(length);
1649 if (copy == NULL) {
1650 return NULL;
1651 }
1652 memcpy(copy, string, length);
1653
1654 return copy;
1655 }
1656
add_item_to_object(lite_cjson_item_t * const object,const char * const string,lite_cjson_item_t * const item,const internal_hooks * const hooks,const cJSON_bool constant_key)1657 static cJSON_bool add_item_to_object(lite_cjson_item_t *const object,
1658 const char *const string,
1659 lite_cjson_item_t *const item,
1660 const internal_hooks *const hooks,
1661 const cJSON_bool constant_key)
1662 {
1663 char *new_key = NULL;
1664 int new_type = cJSON_Invalid;
1665
1666 if ((object == NULL) || (string == NULL) || (item == NULL)) {
1667 return false;
1668 }
1669
1670 if (constant_key) {
1671 new_key = (char *)cast_away_const(string);
1672 new_type = item->type | cJSON_StringIsConst;
1673 } else {
1674 new_key = (char *)cJSON_strdup((const unsigned char *)string, hooks);
1675 if (new_key == NULL) {
1676 return false;
1677 }
1678
1679 new_type = item->type & ~cJSON_StringIsConst;
1680 }
1681
1682 if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) {
1683 hooks->deallocate(item->string);
1684 }
1685
1686 item->string = new_key;
1687 item->type = new_type;
1688
1689 return add_item_to_array(object, item);
1690 }
1691
lite_cjson_add_item_to_object(lite_cjson_item_t * object,const char * string,lite_cjson_item_t * item)1692 void lite_cjson_add_item_to_object(lite_cjson_item_t *object,
1693 const char *string, lite_cjson_item_t *item)
1694 {
1695 add_item_to_object(object, string, item, &global_hooks, false);
1696 }
1697
cJSON_New_Item(const internal_hooks * const hooks)1698 static lite_cjson_item_t *cJSON_New_Item(const internal_hooks *const hooks)
1699 {
1700 lite_cjson_item_t *node =
1701 (lite_cjson_item_t *)hooks->allocate(sizeof(lite_cjson_item_t));
1702 if (node) {
1703 memset(node, '\0', sizeof(lite_cjson_item_t));
1704 }
1705
1706 return node;
1707 }
1708
lite_cjson_create_null(void)1709 lite_cjson_item_t *lite_cjson_create_null(void)
1710 {
1711 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1712 if (item) {
1713 item->type = cJSON_NULL;
1714 }
1715
1716 return item;
1717 }
1718
lite_cjson_create_true(void)1719 lite_cjson_item_t *lite_cjson_create_true(void)
1720 {
1721 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1722 if (item) {
1723 item->type = cJSON_True;
1724 }
1725
1726 return item;
1727 }
1728
lite_cjson_create_false(void)1729 lite_cjson_item_t *lite_cjson_create_false(void)
1730 {
1731 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1732 if (item) {
1733 item->type = cJSON_False;
1734 }
1735
1736 return item;
1737 }
1738
lite_cjson_create_bool(cJSON_bool b)1739 lite_cjson_item_t *lite_cjson_create_bool(cJSON_bool b)
1740 {
1741 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1742 if (item) {
1743 item->type = b ? cJSON_True : cJSON_False;
1744 }
1745
1746 return item;
1747 }
1748
lite_cjson_create_number(double num)1749 lite_cjson_item_t *lite_cjson_create_number(double num)
1750 {
1751 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1752 if (item) {
1753 item->type = cJSON_Number;
1754 item->valuedouble = num;
1755
1756 /* use saturation in case of overflow */
1757 if (num >= INT_MAX) {
1758 item->valueint = INT_MAX;
1759 } else if (num <= INT_MIN) {
1760 item->valueint = INT_MIN;
1761 } else {
1762 item->valueint = (int)num;
1763 }
1764 }
1765
1766 return item;
1767 }
lite_cjson_create_string(const char * string)1768 lite_cjson_item_t *lite_cjson_create_string(const char *string)
1769 {
1770 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1771 if (item) {
1772 item->type = cJSON_String;
1773 item->valuestring =
1774 (char *)cJSON_strdup((const unsigned char *)string, &global_hooks);
1775 if (!item->valuestring) {
1776 lite_cjson_delete(item);
1777 return NULL;
1778 }
1779 }
1780
1781 return item;
1782 }
1783
lite_cjson_create_array(void)1784 lite_cjson_item_t *lite_cjson_create_array(void)
1785 {
1786 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1787 if (item) {
1788 item->type = cJSON_Array;
1789 }
1790
1791 return item;
1792 }
1793
lite_cjson_create_object(void)1794 lite_cjson_item_t *lite_cjson_create_object(void)
1795 {
1796 lite_cjson_item_t *item = cJSON_New_Item(&global_hooks);
1797 if (item) {
1798 item->type = cJSON_Object;
1799 }
1800
1801 return item;
1802 }
1803
lite_cjson_create_intArray(const int * numbers,int count)1804 lite_cjson_item_t *lite_cjson_create_intArray(const int *numbers, int count)
1805 {
1806 size_t i = 0;
1807 lite_cjson_item_t *n = NULL;
1808 lite_cjson_item_t *p = NULL;
1809 lite_cjson_item_t *a = NULL;
1810
1811 if ((count < 0) || (numbers == NULL)) {
1812 return NULL;
1813 }
1814
1815 a = lite_cjson_create_array();
1816 for (i = 0; a && (i < (size_t)count); i++) {
1817 n = lite_cjson_create_number(numbers[i]);
1818 if (!n) {
1819 lite_cjson_delete(a);
1820 return NULL;
1821 }
1822 if (!i) {
1823 a->child = n;
1824 } else {
1825 suffix_object(p, n);
1826 }
1827 p = n;
1828 }
1829
1830 return a;
1831 }
1832
lite_cjson_create_floatArray(const float * numbers,int count)1833 lite_cjson_item_t *lite_cjson_create_floatArray(const float *numbers, int count)
1834 {
1835 size_t i = 0;
1836 lite_cjson_item_t *n = NULL;
1837 lite_cjson_item_t *p = NULL;
1838 lite_cjson_item_t *a = NULL;
1839
1840 if ((count < 0) || (numbers == NULL)) {
1841 return NULL;
1842 }
1843
1844 a = lite_cjson_create_array();
1845
1846 for (i = 0; a && (i < (size_t)count); i++) {
1847 n = lite_cjson_create_number((double)numbers[i]);
1848 if (!n) {
1849 lite_cjson_delete(a);
1850 return NULL;
1851 }
1852 if (!i) {
1853 a->child = n;
1854 } else {
1855 suffix_object(p, n);
1856 }
1857 p = n;
1858 }
1859
1860 return a;
1861 }
1862
lite_cjson_create_doubleArray(const double * numbers,int count)1863 lite_cjson_item_t *lite_cjson_create_doubleArray(const double *numbers,
1864 int count)
1865 {
1866 size_t i = 0;
1867 lite_cjson_item_t *n = NULL;
1868 lite_cjson_item_t *p = NULL;
1869 lite_cjson_item_t *a = NULL;
1870
1871 if ((count < 0) || (numbers == NULL)) {
1872 return NULL;
1873 }
1874
1875 a = lite_cjson_create_array();
1876
1877 for (i = 0; a && (i < (size_t)count); i++) {
1878 n = lite_cjson_create_number(numbers[i]);
1879 if (!n) {
1880 lite_cjson_delete(a);
1881 return NULL;
1882 }
1883 if (!i) {
1884 a->child = n;
1885 } else {
1886 suffix_object(p, n);
1887 }
1888 p = n;
1889 }
1890
1891 return a;
1892 }
1893
lite_cjson_create_stringArray(const char ** strings,int count)1894 lite_cjson_item_t *lite_cjson_create_stringArray(const char **strings,
1895 int count)
1896 {
1897 size_t i = 0;
1898 lite_cjson_item_t *n = NULL;
1899 lite_cjson_item_t *p = NULL;
1900 lite_cjson_item_t *a = NULL;
1901
1902 if ((count < 0) || (strings == NULL)) {
1903 return NULL;
1904 }
1905
1906 a = lite_cjson_create_array();
1907
1908 for (i = 0; a && (i < (size_t)count); i++) {
1909 n = lite_cjson_create_string(strings[i]);
1910 if (!n) {
1911 lite_cjson_delete(a);
1912 return NULL;
1913 }
1914 if (!i) {
1915 a->child = n;
1916 } else {
1917 suffix_object(p, n);
1918 }
1919 p = n;
1920 }
1921
1922 return a;
1923 }
1924 #endif
1925 #endif
1926