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(&current_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(&current_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(&current_item_key, 0, sizeof(lite_cjson_t));
271         memset(&current_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(&current_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(&current_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(&current_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(&current_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, &current_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(&current_item_key, 0, sizeof(lite_cjson_t));
634         memset(&current_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(&current_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(&current_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, &current_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(&current_item_key, 0, sizeof(lite_cjson_t));
864         memset(&current_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(&current_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(&current_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, &current_item_key, sizeof(lite_cjson_t));
902             }
903             if (lite_item_value) {
904                 memcpy(lite_item_value, &current_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