Annotation of embedaddon/iperf/src/cjson.c, revision 1.1.1.2

1.1       misho       1: /*
1.1.1.2 ! misho       2:   Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
1.1       misho       3: 
                      4:   Permission is hereby granted, free of charge, to any person obtaining a copy
                      5:   of this software and associated documentation files (the "Software"), to deal
                      6:   in the Software without restriction, including without limitation the rights
                      7:   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                      8:   copies of the Software, and to permit persons to whom the Software is
                      9:   furnished to do so, subject to the following conditions:
                     10: 
                     11:   The above copyright notice and this permission notice shall be included in
                     12:   all copies or substantial portions of the Software.
                     13: 
                     14:   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     15:   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     16:   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                     17:   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     18:   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     19:   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     20:   THE SOFTWARE.
                     21: */
                     22: 
                     23: /* cJSON */
                     24: /* JSON parser in C. */
                     25: 
1.1.1.2 ! misho      26: /* disable warnings about old C89 functions in MSVC */
        !            27: #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
        !            28: #define _CRT_SECURE_NO_DEPRECATE
        !            29: #endif
        !            30: 
        !            31: #ifdef __GNUC__
        !            32: #pragma GCC visibility push(default)
        !            33: #endif
        !            34: #if defined(_MSC_VER)
        !            35: #pragma warning (push)
        !            36: /* disable warning about single line comments in system headers */
        !            37: #pragma warning (disable : 4001)
        !            38: #endif
        !            39: 
1.1       misho      40: #include <string.h>
                     41: #include <stdio.h>
                     42: #include <math.h>
                     43: #include <stdlib.h>
                     44: #include <limits.h>
                     45: #include <ctype.h>
1.1.1.2 ! misho      46: #include <float.h>
1.1       misho      47: #ifdef HAVE_STDINT_H
1.1.1.2 ! misho      48: #include <stdint.h>
1.1       misho      49: #endif
                     50: #include <sys/types.h>
1.1.1.2 ! misho      51: 
        !            52: #ifdef ENABLE_LOCALES
        !            53: #include <locale.h>
        !            54: #endif
        !            55: 
        !            56: #if defined(_MSC_VER)
        !            57: #pragma warning (pop)
        !            58: #endif
        !            59: #ifdef __GNUC__
        !            60: #pragma GCC visibility pop
        !            61: #endif
        !            62: 
1.1       misho      63: #include "cjson.h"
                     64: 
1.1.1.2 ! misho      65: /* define our own boolean type */
        !            66: #ifdef true
        !            67: #undef true
        !            68: #endif
        !            69: #define true ((cJSON_bool)1)
        !            70: 
        !            71: #ifdef false
        !            72: #undef false
        !            73: #endif
        !            74: #define false ((cJSON_bool)0)
        !            75: 
        !            76: /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
        !            77: #ifndef isinf
        !            78: #define isinf(d) (isnan((d - d)) && !isnan(d))
        !            79: #endif
        !            80: #ifndef isnan
        !            81: #define isnan(d) (d != d)
        !            82: #endif
        !            83: 
        !            84: #ifndef NAN
        !            85: #define NAN 0.0/0.0
        !            86: #endif
        !            87: 
        !            88: typedef struct {
        !            89:     const unsigned char *json;
        !            90:     size_t position;
        !            91: } error;
        !            92: static error global_error = { NULL, 0 };
        !            93: 
1.1       misho      94: #ifndef LLONG_MAX
                     95: #define LLONG_MAX 9223372036854775807LL
                     96: #endif
                     97: #ifndef LLONG_MIN
                     98: #define LLONG_MIN (-LLONG_MAX - 1LL)
                     99: #endif
                    100: 
1.1.1.2 ! misho     101: CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
        !           102: {
        !           103:     return (const char*) (global_error.json + global_error.position);
        !           104: }
        !           105: 
        !           106: CJSON_PUBLIC(char *) cJSON_GetStringValue(cJSON *item) 
        !           107: {
        !           108:     if (!cJSON_IsString(item)) 
        !           109:     {
        !           110:         return NULL;
        !           111:     }
        !           112: 
        !           113:     return item->valuestring;
        !           114: }
        !           115: 
        !           116: CJSON_PUBLIC(double) cJSON_GetNumberValue(cJSON *item) 
        !           117: {
        !           118:     if (!cJSON_IsNumber(item)) 
        !           119:     {
        !           120:         return NAN;
        !           121:     }
        !           122: 
        !           123:     return item->valuedouble;
        !           124: }
        !           125: 
        !           126: /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
        !           127: #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 13)
        !           128:     #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
        !           129: #endif
        !           130: 
        !           131: CJSON_PUBLIC(const char*) cJSON_Version(void)
        !           132: {
        !           133:     static char version[15];
        !           134:     sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
        !           135: 
        !           136:     return version;
        !           137: }
        !           138: 
        !           139: /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
        !           140: static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
        !           141: {
        !           142:     if ((string1 == NULL) || (string2 == NULL))
        !           143:     {
        !           144:         return 1;
        !           145:     }
        !           146: 
        !           147:     if (string1 == string2)
        !           148:     {
        !           149:         return 0;
        !           150:     }
        !           151: 
        !           152:     for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
        !           153:     {
        !           154:         if (*string1 == '\0')
        !           155:         {
        !           156:             return 0;
        !           157:         }
        !           158:     }
        !           159: 
        !           160:     return tolower(*string1) - tolower(*string2);
        !           161: }
        !           162: 
        !           163: typedef struct internal_hooks
        !           164: {
        !           165:     void *(CJSON_CDECL *allocate)(size_t size);
        !           166:     void (CJSON_CDECL *deallocate)(void *pointer);
        !           167:     void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
        !           168: } internal_hooks;
1.1       misho     169: 
1.1.1.2 ! misho     170: #if defined(_MSC_VER)
        !           171: /* work around MSVC error C2322: '...' address of dllimport '...' is not static */
        !           172: static void * CJSON_CDECL internal_malloc(size_t size)
        !           173: {
        !           174:     return malloc(size);
        !           175: }
        !           176: static void CJSON_CDECL internal_free(void *pointer)
        !           177: {
        !           178:     free(pointer);
        !           179: }
        !           180: static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
1.1       misho     181: {
1.1.1.2 ! misho     182:     return realloc(pointer, size);
1.1       misho     183: }
1.1.1.2 ! misho     184: #else
        !           185: #define internal_malloc malloc
        !           186: #define internal_free free
        !           187: #define internal_realloc realloc
        !           188: #endif
        !           189: 
        !           190: /* strlen of character literals resolved at compile time */
        !           191: #define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
1.1       misho     192: 
1.1.1.2 ! misho     193: static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
1.1       misho     194: 
1.1.1.2 ! misho     195: static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
1.1       misho     196: {
1.1.1.2 ! misho     197:     size_t length = 0;
        !           198:     unsigned char *copy = NULL;
        !           199: 
        !           200:     if (string == NULL)
        !           201:     {
        !           202:         return NULL;
        !           203:     }
1.1       misho     204: 
1.1.1.2 ! misho     205:     length = strlen((const char*)string) + sizeof("");
        !           206:     copy = (unsigned char*)hooks->allocate(length);
        !           207:     if (copy == NULL)
        !           208:     {
        !           209:         return NULL;
        !           210:     }
        !           211:     memcpy(copy, string, length);
        !           212: 
        !           213:     return copy;
1.1       misho     214: }
                    215: 
1.1.1.2 ! misho     216: CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
1.1       misho     217: {
1.1.1.2 ! misho     218:     if (hooks == NULL)
        !           219:     {
        !           220:         /* Reset hooks */
        !           221:         global_hooks.allocate = malloc;
        !           222:         global_hooks.deallocate = free;
        !           223:         global_hooks.reallocate = realloc;
1.1       misho     224:         return;
                    225:     }
                    226: 
1.1.1.2 ! misho     227:     global_hooks.allocate = malloc;
        !           228:     if (hooks->malloc_fn != NULL)
        !           229:     {
        !           230:         global_hooks.allocate = hooks->malloc_fn;
        !           231:     }
        !           232: 
        !           233:     global_hooks.deallocate = free;
        !           234:     if (hooks->free_fn != NULL)
        !           235:     {
        !           236:         global_hooks.deallocate = hooks->free_fn;
        !           237:     }
        !           238: 
        !           239:     /* use realloc only if both free and malloc are used */
        !           240:     global_hooks.reallocate = NULL;
        !           241:     if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
        !           242:     {
        !           243:         global_hooks.reallocate = realloc;
        !           244:     }
1.1       misho     245: }
                    246: 
                    247: /* Internal constructor. */
1.1.1.2 ! misho     248: static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
1.1       misho     249: {
1.1.1.2 ! misho     250:     cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
        !           251:     if (node)
        !           252:     {
        !           253:         memset(node, '\0', sizeof(cJSON));
        !           254:     }
        !           255: 
        !           256:     return node;
1.1       misho     257: }
                    258: 
                    259: /* Delete a cJSON structure. */
1.1.1.2 ! misho     260: CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
        !           261: {
        !           262:     cJSON *next = NULL;
        !           263:     while (item != NULL)
        !           264:     {
        !           265:         next = item->next;
        !           266:         if (!(item->type & cJSON_IsReference) && (item->child != NULL))
        !           267:         {
        !           268:             cJSON_Delete(item->child);
        !           269:         }
        !           270:         if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
        !           271:         {
        !           272:             global_hooks.deallocate(item->valuestring);
        !           273:         }
        !           274:         if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
        !           275:         {
        !           276:             global_hooks.deallocate(item->string);
        !           277:         }
        !           278:         global_hooks.deallocate(item);
        !           279:         item = next;
        !           280:     }
        !           281: }
        !           282: 
        !           283: /* get the decimal point character of the current locale */
        !           284: static unsigned char get_decimal_point(void)
1.1       misho     285: {
1.1.1.2 ! misho     286: #ifdef ENABLE_LOCALES
        !           287:     struct lconv *lconv = localeconv();
        !           288:     return (unsigned char) lconv->decimal_point[0];
        !           289: #else
        !           290:     return '.';
        !           291: #endif
1.1       misho     292: }
                    293: 
1.1.1.2 ! misho     294: typedef struct
        !           295: {
        !           296:     const unsigned char *content;
        !           297:     size_t length;
        !           298:     size_t offset;
        !           299:     size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
        !           300:     internal_hooks hooks;
        !           301: } parse_buffer;
        !           302: 
        !           303: /* check if the given size is left to read in a given parse buffer (starting with 1) */
        !           304: #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
        !           305: /* check if the buffer can be accessed at the given index (starting with 0) */
        !           306: #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
        !           307: #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
        !           308: /* get a pointer to the buffer at the position */
        !           309: #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
        !           310: 
1.1       misho     311: /* Parse the input text to generate a number, and populate the result into item. */
1.1.1.2 ! misho     312: static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
1.1       misho     313: {
1.1.1.2 ! misho     314:     double number = 0;
        !           315:     unsigned char *after_end = NULL;
        !           316:     unsigned char number_c_string[64];
        !           317:     unsigned char decimal_point = get_decimal_point();
        !           318:     size_t i = 0;
        !           319: 
        !           320:     if ((input_buffer == NULL) || (input_buffer->content == NULL))
        !           321:     {
        !           322:         return false;
        !           323:     }
        !           324: 
        !           325:     /* copy the number into a temporary buffer and replace '.' with the decimal point
        !           326:      * of the current locale (for strtod)
        !           327:      * This also takes care of '\0' not necessarily being available for marking the end of the input */
        !           328:     for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
        !           329:     {
        !           330:         switch (buffer_at_offset(input_buffer)[i])
        !           331:         {
        !           332:             case '0':
        !           333:             case '1':
        !           334:             case '2':
        !           335:             case '3':
        !           336:             case '4':
        !           337:             case '5':
        !           338:             case '6':
        !           339:             case '7':
        !           340:             case '8':
        !           341:             case '9':
        !           342:             case '+':
        !           343:             case '-':
        !           344:             case 'e':
        !           345:             case 'E':
        !           346:                 number_c_string[i] = buffer_at_offset(input_buffer)[i];
        !           347:                 break;
        !           348: 
        !           349:             case '.':
        !           350:                 number_c_string[i] = decimal_point;
        !           351:                 break;
        !           352: 
        !           353:             default:
        !           354:                 goto loop_end;
        !           355:         }
        !           356:     }
        !           357: loop_end:
        !           358:     number_c_string[i] = '\0';
        !           359: 
        !           360:     number = strtod((const char*)number_c_string, (char**)&after_end);
        !           361:     if (number_c_string == after_end)
        !           362:     {
        !           363:         return false; /* parse_error */
        !           364:     }
        !           365: 
        !           366:     item->valuedouble = number;
        !           367: 
        !           368:     /* use saturation in case of overflow */
        !           369:     if (number >= LLONG_MAX)
        !           370:     {
        !           371:         item->valueint = LLONG_MAX;
        !           372:     }
        !           373:     else if (number <= (double)LLONG_MIN)
        !           374:     {
        !           375:         item->valueint = LLONG_MIN;
        !           376:     }
        !           377:     else
        !           378:     {
        !           379:         item->valueint = (int64_t)number;
        !           380:     }
1.1       misho     381: 
1.1.1.2 ! misho     382:     item->type = cJSON_Number;
        !           383: 
        !           384:     input_buffer->offset += (size_t)(after_end - number_c_string);
        !           385:     return true;
1.1       misho     386: }
                    387: 
1.1.1.2 ! misho     388: /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
        !           389: CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
1.1       misho     390: {
1.1.1.2 ! misho     391:     if (number >= LLONG_MAX)
        !           392:     {
        !           393:         object->valueint = LLONG_MAX;
        !           394:     }
        !           395:     else if (number <= (double)LLONG_MIN)
        !           396:     {
        !           397:         object->valueint = LLONG_MIN;
        !           398:     }
        !           399:     else
        !           400:     {
        !           401:         object->valueint = (int64_t)number;
        !           402:     }
        !           403: 
        !           404:     return object->valuedouble = number;
1.1       misho     405: }
                    406: 
1.1.1.2 ! misho     407: CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
1.1       misho     408: {
1.1.1.2 ! misho     409:     char *copy = NULL;
        !           410:     /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
        !           411:     if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
        !           412:     {
        !           413:         return NULL;
        !           414:     }
        !           415:     if (strlen(valuestring) <= strlen(object->valuestring))
        !           416:     {
        !           417:         strcpy(object->valuestring, valuestring);
        !           418:         return object->valuestring;
        !           419:     }
        !           420:     copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
        !           421:     if (copy == NULL)
        !           422:     {
        !           423:         return NULL;
        !           424:     }
        !           425:     if (object->valuestring != NULL)
        !           426:     {
        !           427:         cJSON_free(object->valuestring);
        !           428:     }
        !           429:     object->valuestring = copy;
1.1       misho     430: 
1.1.1.2 ! misho     431:     return copy;
1.1       misho     432: }
                    433: 
1.1.1.2 ! misho     434: typedef struct
        !           435: {
        !           436:     unsigned char *buffer;
        !           437:     size_t length;
        !           438:     size_t offset;
        !           439:     size_t depth; /* current nesting depth (for formatted printing) */
        !           440:     cJSON_bool noalloc;
        !           441:     cJSON_bool format; /* is this print a formatted print */
        !           442:     internal_hooks hooks;
        !           443: } printbuffer;
1.1       misho     444: 
1.1.1.2 ! misho     445: /* realloc printbuffer if necessary to have at least "needed" bytes more */
        !           446: static unsigned char* ensure(printbuffer * const p, size_t needed)
        !           447: {
        !           448:     unsigned char *newbuffer = NULL;
        !           449:     size_t newsize = 0;
1.1       misho     450: 
1.1.1.2 ! misho     451:     if ((p == NULL) || (p->buffer == NULL))
        !           452:     {
        !           453:         return NULL;
        !           454:     }
        !           455: 
        !           456:     if ((p->length > 0) && (p->offset >= p->length))
        !           457:     {
        !           458:         /* make sure that offset is valid */
        !           459:         return NULL;
        !           460:     }
        !           461: 
        !           462:     if (needed > SIZE_MAX)
        !           463:     {
        !           464:         /* sizes bigger than SIZE_MAX are currently not supported */
        !           465:         return NULL;
        !           466:     }
        !           467: 
        !           468:     needed += p->offset + 1;
        !           469:     if (needed <= p->length)
        !           470:     {
        !           471:         return p->buffer + p->offset;
        !           472:     }
        !           473: 
        !           474:     if (p->noalloc) {
        !           475:         return NULL;
        !           476:     }
        !           477: 
        !           478:     /* calculate new buffer size */
        !           479:     if (needed > (SIZE_MAX / 2))
        !           480:     {
        !           481:         /* overflow of int, use SIZE_MAX if possible */
        !           482:         if (needed <= SIZE_MAX)
        !           483:         {
        !           484:             newsize = SIZE_MAX;
        !           485:         }
        !           486:         else
        !           487:         {
        !           488:             return NULL;
        !           489:         }
        !           490:     }
        !           491:     else
        !           492:     {
        !           493:         newsize = needed * 2;
        !           494:     }
        !           495: 
        !           496:     if (p->hooks.reallocate != NULL)
        !           497:     {
        !           498:         /* reallocate with realloc if available */
        !           499:         newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
        !           500:         if (newbuffer == NULL)
        !           501:         {
        !           502:             p->hooks.deallocate(p->buffer);
        !           503:             p->length = 0;
        !           504:             p->buffer = NULL;
        !           505: 
        !           506:             return NULL;
        !           507:         }
        !           508:     }
        !           509:     else
        !           510:     {
        !           511:         /* otherwise reallocate manually */
        !           512:         newbuffer = (unsigned char*)p->hooks.allocate(newsize);
        !           513:         if (!newbuffer)
        !           514:         {
        !           515:             p->hooks.deallocate(p->buffer);
        !           516:             p->length = 0;
        !           517:             p->buffer = NULL;
        !           518: 
        !           519:             return NULL;
        !           520:         }
        !           521:         if (newbuffer)
        !           522:         {
        !           523:             memcpy(newbuffer, p->buffer, p->offset + 1);
        !           524:         }
        !           525:         p->hooks.deallocate(p->buffer);
        !           526:     }
        !           527:     p->length = newsize;
        !           528:     p->buffer = newbuffer;
        !           529: 
        !           530:     return newbuffer + p->offset;
        !           531: }
        !           532: 
        !           533: /* calculate the new length of the string in a printbuffer and update the offset */
        !           534: static void update_offset(printbuffer * const buffer)
1.1       misho     535: {
1.1.1.2 ! misho     536:     const unsigned char *buffer_pointer = NULL;
        !           537:     if ((buffer == NULL) || (buffer->buffer == NULL))
        !           538:     {
        !           539:         return;
        !           540:     }
        !           541:     buffer_pointer = buffer->buffer + buffer->offset;
        !           542: 
        !           543:     buffer->offset += strlen((const char*)buffer_pointer);
1.1       misho     544: }
                    545: 
1.1.1.2 ! misho     546: /* securely comparison of floating-point variables */
        !           547: static cJSON_bool compare_double(double a, double b)
        !           548: {
        !           549:     double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
        !           550:     return (fabs(a - b) <= maxVal * DBL_EPSILON);
        !           551: }
1.1       misho     552: 
1.1.1.2 ! misho     553: /* Render the number nicely from the given item into a string. */
        !           554: static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
1.1       misho     555: {
1.1.1.2 ! misho     556:     unsigned char *output_pointer = NULL;
        !           557:     double d = item->valuedouble;
        !           558:     int length = 0;
        !           559:     size_t i = 0;
        !           560:     unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
        !           561:     unsigned char decimal_point = get_decimal_point();
        !           562:     double test = 0.0;
        !           563: 
        !           564:     if (output_buffer == NULL)
        !           565:     {
        !           566:         return false;
        !           567:     }
        !           568: 
        !           569:     /* This checks for NaN and Infinity */
        !           570:     if (isnan(d) || isinf(d))
        !           571:     {
        !           572:         length = sprintf((char*)number_buffer, "null");
        !           573:     }
        !           574:     else
        !           575:     {
        !           576:         /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
        !           577:         length = sprintf((char*)number_buffer, "%1.15g", d);
        !           578: 
        !           579:         /* Check whether the original double can be recovered */
        !           580:         if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
        !           581:         {
        !           582:             /* If not, print with 17 decimal places of precision */
        !           583:             length = sprintf((char*)number_buffer, "%1.17g", d);
        !           584:         }
        !           585:     }
        !           586: 
        !           587:     /* sprintf failed or buffer overrun occurred */
        !           588:     if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
        !           589:     {
        !           590:         return false;
        !           591:     }
        !           592: 
        !           593:     /* reserve appropriate space in the output */
        !           594:     output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
        !           595:     if (output_pointer == NULL)
        !           596:     {
        !           597:         return false;
        !           598:     }
        !           599: 
        !           600:     /* copy the printed number to the output and replace locale
        !           601:      * dependent decimal point with '.' */
        !           602:     for (i = 0; i < ((size_t)length); i++)
        !           603:     {
        !           604:         if (number_buffer[i] == decimal_point)
        !           605:         {
        !           606:             output_pointer[i] = '.';
        !           607:             continue;
        !           608:         }
        !           609: 
        !           610:         output_pointer[i] = number_buffer[i];
        !           611:     }
        !           612:     output_pointer[i] = '\0';
        !           613: 
        !           614:     output_buffer->offset += (size_t)length;
        !           615: 
        !           616:     return true;
1.1       misho     617: }
                    618: 
1.1.1.2 ! misho     619: /* parse 4 digit hexadecimal number */
        !           620: static unsigned parse_hex4(const unsigned char * const input)
        !           621: {
        !           622:     unsigned int h = 0;
        !           623:     size_t i = 0;
        !           624: 
        !           625:     for (i = 0; i < 4; i++)
        !           626:     {
        !           627:         /* parse digit */
        !           628:         if ((input[i] >= '0') && (input[i] <= '9'))
        !           629:         {
        !           630:             h += (unsigned int) input[i] - '0';
        !           631:         }
        !           632:         else if ((input[i] >= 'A') && (input[i] <= 'F'))
        !           633:         {
        !           634:             h += (unsigned int) 10 + input[i] - 'A';
        !           635:         }
        !           636:         else if ((input[i] >= 'a') && (input[i] <= 'f'))
        !           637:         {
        !           638:             h += (unsigned int) 10 + input[i] - 'a';
        !           639:         }
        !           640:         else /* invalid */
        !           641:         {
        !           642:             return 0;
        !           643:         }
        !           644: 
        !           645:         if (i < 3)
        !           646:         {
        !           647:             /* shift left to make place for the next nibble */
        !           648:             h = h << 4;
        !           649:         }
        !           650:     }
1.1       misho     651: 
1.1.1.2 ! misho     652:     return h;
        !           653: }
        !           654: 
        !           655: /* converts a UTF-16 literal to UTF-8
        !           656:  * A literal can be one or two sequences of the form \uXXXX */
        !           657: static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
        !           658: {
        !           659:     long unsigned int codepoint = 0;
        !           660:     unsigned int first_code = 0;
        !           661:     const unsigned char *first_sequence = input_pointer;
        !           662:     unsigned char utf8_length = 0;
        !           663:     unsigned char utf8_position = 0;
        !           664:     unsigned char sequence_length = 0;
        !           665:     unsigned char first_byte_mark = 0;
        !           666: 
        !           667:     if ((input_end - first_sequence) < 6)
        !           668:     {
        !           669:         /* input ends unexpectedly */
        !           670:         goto fail;
        !           671:     }
        !           672: 
        !           673:     /* get the first utf16 sequence */
        !           674:     first_code = parse_hex4(first_sequence + 2);
        !           675: 
        !           676:     /* check that the code is valid */
        !           677:     if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
        !           678:     {
        !           679:         goto fail;
        !           680:     }
        !           681: 
        !           682:     /* UTF16 surrogate pair */
        !           683:     if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
        !           684:     {
        !           685:         const unsigned char *second_sequence = first_sequence + 6;
        !           686:         unsigned int second_code = 0;
        !           687:         sequence_length = 12; /* \uXXXX\uXXXX */
        !           688: 
        !           689:         if ((input_end - second_sequence) < 6)
        !           690:         {
        !           691:             /* input ends unexpectedly */
        !           692:             goto fail;
        !           693:         }
        !           694: 
        !           695:         if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
        !           696:         {
        !           697:             /* missing second half of the surrogate pair */
        !           698:             goto fail;
        !           699:         }
        !           700: 
        !           701:         /* get the second utf16 sequence */
        !           702:         second_code = parse_hex4(second_sequence + 2);
        !           703:         /* check that the code is valid */
        !           704:         if ((second_code < 0xDC00) || (second_code > 0xDFFF))
        !           705:         {
        !           706:             /* invalid second half of the surrogate pair */
        !           707:             goto fail;
        !           708:         }
        !           709: 
        !           710: 
        !           711:         /* calculate the unicode codepoint from the surrogate pair */
        !           712:         codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
        !           713:     }
        !           714:     else
        !           715:     {
        !           716:         sequence_length = 6; /* \uXXXX */
        !           717:         codepoint = first_code;
        !           718:     }
        !           719: 
        !           720:     /* encode as UTF-8
        !           721:      * takes at maximum 4 bytes to encode:
        !           722:      * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
        !           723:     if (codepoint < 0x80)
        !           724:     {
        !           725:         /* normal ascii, encoding 0xxxxxxx */
        !           726:         utf8_length = 1;
        !           727:     }
        !           728:     else if (codepoint < 0x800)
        !           729:     {
        !           730:         /* two bytes, encoding 110xxxxx 10xxxxxx */
        !           731:         utf8_length = 2;
        !           732:         first_byte_mark = 0xC0; /* 11000000 */
        !           733:     }
        !           734:     else if (codepoint < 0x10000)
        !           735:     {
        !           736:         /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
        !           737:         utf8_length = 3;
        !           738:         first_byte_mark = 0xE0; /* 11100000 */
        !           739:     }
        !           740:     else if (codepoint <= 0x10FFFF)
        !           741:     {
        !           742:         /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
        !           743:         utf8_length = 4;
        !           744:         first_byte_mark = 0xF0; /* 11110000 */
        !           745:     }
        !           746:     else
        !           747:     {
        !           748:         /* invalid unicode codepoint */
        !           749:         goto fail;
        !           750:     }
        !           751: 
        !           752:     /* encode as utf8 */
        !           753:     for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
        !           754:     {
        !           755:         /* 10xxxxxx */
        !           756:         (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
        !           757:         codepoint >>= 6;
        !           758:     }
        !           759:     /* encode first byte */
        !           760:     if (utf8_length > 1)
        !           761:     {
        !           762:         (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
        !           763:     }
        !           764:     else
        !           765:     {
        !           766:         (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
        !           767:     }
        !           768: 
        !           769:     *output_pointer += utf8_length;
        !           770: 
        !           771:     return sequence_length;
        !           772: 
        !           773: fail:
        !           774:     return 0;
        !           775: }
        !           776: 
        !           777: /* Parse the input text into an unescaped cinput, and populate item. */
        !           778: static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
1.1       misho     779: {
1.1.1.2 ! misho     780:     const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
        !           781:     const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
        !           782:     unsigned char *output_pointer = NULL;
        !           783:     unsigned char *output = NULL;
        !           784: 
        !           785:     /* not a string */
        !           786:     if (buffer_at_offset(input_buffer)[0] != '\"')
        !           787:     {
        !           788:         goto fail;
        !           789:     }
        !           790: 
        !           791:     {
        !           792:         /* calculate approximate size of the output (overestimate) */
        !           793:         size_t allocation_length = 0;
        !           794:         size_t skipped_bytes = 0;
        !           795:         while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
        !           796:         {
        !           797:             /* is escape sequence */
        !           798:             if (input_end[0] == '\\')
        !           799:             {
        !           800:                 if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
        !           801:                 {
        !           802:                     /* prevent buffer overflow when last input character is a backslash */
        !           803:                     goto fail;
        !           804:                 }
        !           805:                 skipped_bytes++;
        !           806:                 input_end++;
        !           807:             }
        !           808:             input_end++;
        !           809:         }
        !           810:         if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
        !           811:         {
        !           812:             goto fail; /* string ended unexpectedly */
        !           813:         }
        !           814: 
        !           815:         /* This is at most how much we need for the output */
        !           816:         allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
        !           817:         output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
        !           818:         if (output == NULL)
        !           819:         {
        !           820:             goto fail; /* allocation failure */
        !           821:         }
        !           822:     }
        !           823: 
        !           824:     output_pointer = output;
        !           825:     /* loop through the string literal */
        !           826:     while (input_pointer < input_end)
        !           827:     {
        !           828:         if (*input_pointer != '\\')
        !           829:         {
        !           830:             *output_pointer++ = *input_pointer++;
        !           831:         }
        !           832:         /* escape sequence */
        !           833:         else
        !           834:         {
        !           835:             unsigned char sequence_length = 2;
        !           836:             if ((input_end - input_pointer) < 1)
        !           837:             {
        !           838:                 goto fail;
        !           839:             }
        !           840: 
        !           841:             switch (input_pointer[1])
        !           842:             {
        !           843:                 case 'b':
        !           844:                     *output_pointer++ = '\b';
        !           845:                     break;
        !           846:                 case 'f':
        !           847:                     *output_pointer++ = '\f';
        !           848:                     break;
        !           849:                 case 'n':
        !           850:                     *output_pointer++ = '\n';
        !           851:                     break;
        !           852:                 case 'r':
        !           853:                     *output_pointer++ = '\r';
        !           854:                     break;
        !           855:                 case 't':
        !           856:                     *output_pointer++ = '\t';
        !           857:                     break;
        !           858:                 case '\"':
        !           859:                 case '\\':
        !           860:                 case '/':
        !           861:                     *output_pointer++ = input_pointer[1];
        !           862:                     break;
        !           863: 
        !           864:                 /* UTF-16 literal */
        !           865:                 case 'u':
        !           866:                     sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
        !           867:                     if (sequence_length == 0)
        !           868:                     {
        !           869:                         /* failed to convert UTF16-literal to UTF-8 */
        !           870:                         goto fail;
        !           871:                     }
        !           872:                     break;
        !           873: 
        !           874:                 default:
        !           875:                     goto fail;
        !           876:             }
        !           877:             input_pointer += sequence_length;
        !           878:         }
        !           879:     }
1.1       misho     880: 
1.1.1.2 ! misho     881:     /* zero terminate the output */
        !           882:     *output_pointer = '\0';
        !           883: 
        !           884:     item->type = cJSON_String;
        !           885:     item->valuestring = (char*)output;
        !           886: 
        !           887:     input_buffer->offset = (size_t) (input_end - input_buffer->content);
        !           888:     input_buffer->offset++;
        !           889: 
        !           890:     return true;
        !           891: 
        !           892: fail:
        !           893:     if (output != NULL)
        !           894:     {
        !           895:         input_buffer->hooks.deallocate(output);
        !           896:     }
        !           897: 
        !           898:     if (input_pointer != NULL)
        !           899:     {
        !           900:         input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
        !           901:     }
        !           902: 
        !           903:     return false;
1.1       misho     904: }
                    905: 
1.1.1.2 ! misho     906: /* Render the cstring provided to an escaped version that can be printed. */
        !           907: static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
        !           908: {
        !           909:     const unsigned char *input_pointer = NULL;
        !           910:     unsigned char *output = NULL;
        !           911:     unsigned char *output_pointer = NULL;
        !           912:     size_t output_length = 0;
        !           913:     /* numbers of additional characters needed for escaping */
        !           914:     size_t escape_characters = 0;
        !           915: 
        !           916:     if (output_buffer == NULL)
        !           917:     {
        !           918:         return false;
        !           919:     }
        !           920: 
        !           921:     /* empty string */
        !           922:     if (input == NULL)
        !           923:     {
        !           924:         output = ensure(output_buffer, sizeof("\"\""));
        !           925:         if (output == NULL)
        !           926:         {
        !           927:             return false;
        !           928:         }
        !           929:         strcpy((char*)output, "\"\"");
        !           930: 
        !           931:         return true;
        !           932:     }
        !           933: 
        !           934:     /* set "flag" to 1 if something needs to be escaped */
        !           935:     for (input_pointer = input; *input_pointer; input_pointer++)
        !           936:     {
        !           937:         switch (*input_pointer)
        !           938:         {
        !           939:             case '\"':
        !           940:             case '\\':
        !           941:             case '\b':
        !           942:             case '\f':
        !           943:             case '\n':
        !           944:             case '\r':
        !           945:             case '\t':
        !           946:                 /* one character escape sequence */
        !           947:                 escape_characters++;
        !           948:                 break;
        !           949:             default:
        !           950:                 if (*input_pointer < 32)
        !           951:                 {
        !           952:                     /* UTF-16 escape sequence uXXXX */
        !           953:                     escape_characters += 5;
        !           954:                 }
        !           955:                 break;
        !           956:         }
        !           957:     }
        !           958:     output_length = (size_t)(input_pointer - input) + escape_characters;
        !           959: 
        !           960:     output = ensure(output_buffer, output_length + sizeof("\"\""));
        !           961:     if (output == NULL)
        !           962:     {
        !           963:         return false;
        !           964:     }
        !           965: 
        !           966:     /* no characters have to be escaped */
        !           967:     if (escape_characters == 0)
        !           968:     {
        !           969:         output[0] = '\"';
        !           970:         memcpy(output + 1, input, output_length);
        !           971:         output[output_length + 1] = '\"';
        !           972:         output[output_length + 2] = '\0';
        !           973: 
        !           974:         return true;
        !           975:     }
        !           976: 
        !           977:     output[0] = '\"';
        !           978:     output_pointer = output + 1;
        !           979:     /* copy the string */
        !           980:     for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
        !           981:     {
        !           982:         if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
        !           983:         {
        !           984:             /* normal character, copy */
        !           985:             *output_pointer = *input_pointer;
        !           986:         }
        !           987:         else
        !           988:         {
        !           989:             /* character needs to be escaped */
        !           990:             *output_pointer++ = '\\';
        !           991:             switch (*input_pointer)
        !           992:             {
        !           993:                 case '\\':
        !           994:                     *output_pointer = '\\';
        !           995:                     break;
        !           996:                 case '\"':
        !           997:                     *output_pointer = '\"';
        !           998:                     break;
        !           999:                 case '\b':
        !          1000:                     *output_pointer = 'b';
        !          1001:                     break;
        !          1002:                 case '\f':
        !          1003:                     *output_pointer = 'f';
        !          1004:                     break;
        !          1005:                 case '\n':
        !          1006:                     *output_pointer = 'n';
        !          1007:                     break;
        !          1008:                 case '\r':
        !          1009:                     *output_pointer = 'r';
        !          1010:                     break;
        !          1011:                 case '\t':
        !          1012:                     *output_pointer = 't';
        !          1013:                     break;
        !          1014:                 default:
        !          1015:                     /* escape and print as unicode codepoint */
        !          1016:                     sprintf((char*)output_pointer, "u%04x", *input_pointer);
        !          1017:                     output_pointer += 4;
        !          1018:                     break;
        !          1019:             }
        !          1020:         }
        !          1021:     }
        !          1022:     output[output_length + 1] = '\"';
        !          1023:     output[output_length + 2] = '\0';
        !          1024: 
        !          1025:     return true;
        !          1026: }
        !          1027: 
        !          1028: /* Invoke print_string_ptr (which is useful) on an item. */
        !          1029: static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
1.1       misho    1030: {
1.1.1.2 ! misho    1031:     return print_string_ptr((unsigned char*)item->valuestring, p);
1.1       misho    1032: }
                   1033: 
1.1.1.2 ! misho    1034: /* Predeclare these prototypes. */
        !          1035: static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
        !          1036: static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
        !          1037: static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
        !          1038: static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
        !          1039: static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
        !          1040: static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
        !          1041: 
        !          1042: /* Utility to jump whitespace and cr/lf */
        !          1043: static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
1.1       misho    1044: {
1.1.1.2 ! misho    1045:     if ((buffer == NULL) || (buffer->content == NULL))
        !          1046:     {
        !          1047:         return NULL;
        !          1048:     }
1.1       misho    1049: 
1.1.1.2 ! misho    1050:     if (cannot_access_at_index(buffer, 0))
        !          1051:     {
        !          1052:         return buffer;
        !          1053:     }
        !          1054: 
        !          1055:     while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
        !          1056:     {
        !          1057:        buffer->offset++;
        !          1058:     }
        !          1059: 
        !          1060:     if (buffer->offset == buffer->length)
        !          1061:     {
        !          1062:         buffer->offset--;
        !          1063:     }
1.1       misho    1064: 
1.1.1.2 ! misho    1065:     return buffer;
1.1       misho    1066: }
                   1067: 
1.1.1.2 ! misho    1068: /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
        !          1069: static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
1.1       misho    1070: {
1.1.1.2 ! misho    1071:     if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
        !          1072:     {
        !          1073:         return NULL;
        !          1074:     }
        !          1075: 
        !          1076:     if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
        !          1077:     {
        !          1078:         buffer->offset += 3;
        !          1079:     }
        !          1080: 
        !          1081:     return buffer;
1.1       misho    1082: }
                   1083: 
1.1.1.2 ! misho    1084: CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
1.1       misho    1085: {
1.1.1.2 ! misho    1086:     size_t buffer_length;
        !          1087: 
        !          1088:     if (NULL == value)
        !          1089:     {
        !          1090:         return NULL;
        !          1091:     }
        !          1092: 
        !          1093:     /* Adding null character size due to require_null_terminated. */
        !          1094:     buffer_length = strlen(value) + sizeof("");
        !          1095: 
        !          1096:     return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
1.1       misho    1097: }
                   1098: 
1.1.1.2 ! misho    1099: /* Parse an object - create a new root, and populate. */
        !          1100: CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
1.1       misho    1101: {
1.1.1.2 ! misho    1102:     parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
        !          1103:     cJSON *item = NULL;
        !          1104: 
        !          1105:     /* reset error position */
        !          1106:     global_error.json = NULL;
        !          1107:     global_error.position = 0;
        !          1108: 
        !          1109:     if (value == NULL || 0 == buffer_length)
        !          1110:     {
        !          1111:         goto fail;
        !          1112:     }
        !          1113: 
        !          1114:     buffer.content = (const unsigned char*)value;
        !          1115:     buffer.length = buffer_length; 
        !          1116:     buffer.offset = 0;
        !          1117:     buffer.hooks = global_hooks;
        !          1118: 
        !          1119:     item = cJSON_New_Item(&global_hooks);
        !          1120:     if (item == NULL) /* memory fail */
        !          1121:     {
        !          1122:         goto fail;
        !          1123:     }
        !          1124: 
        !          1125:     if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
        !          1126:     {
        !          1127:         /* parse failure. ep is set. */
        !          1128:         goto fail;
        !          1129:     }
        !          1130: 
        !          1131:     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
        !          1132:     if (require_null_terminated)
        !          1133:     {
        !          1134:         buffer_skip_whitespace(&buffer);
        !          1135:         if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
        !          1136:         {
        !          1137:             goto fail;
        !          1138:         }
        !          1139:     }
        !          1140:     if (return_parse_end)
        !          1141:     {
        !          1142:         *return_parse_end = (const char*)buffer_at_offset(&buffer);
        !          1143:     }
        !          1144: 
        !          1145:     return item;
        !          1146: 
        !          1147: fail:
        !          1148:     if (item != NULL)
        !          1149:     {
        !          1150:         cJSON_Delete(item);
        !          1151:     }
        !          1152: 
        !          1153:     if (value != NULL)
        !          1154:     {
        !          1155:         error local_error;
        !          1156:         local_error.json = (const unsigned char*)value;
        !          1157:         local_error.position = 0;
        !          1158: 
        !          1159:         if (buffer.offset < buffer.length)
        !          1160:         {
        !          1161:             local_error.position = buffer.offset;
        !          1162:         }
        !          1163:         else if (buffer.length > 0)
        !          1164:         {
        !          1165:             local_error.position = buffer.length - 1;
        !          1166:         }
        !          1167: 
        !          1168:         if (return_parse_end != NULL)
        !          1169:         {
        !          1170:             *return_parse_end = (const char*)local_error.json + local_error.position;
        !          1171:         }
        !          1172: 
        !          1173:         global_error = local_error;
        !          1174:     }
        !          1175: 
        !          1176:     return NULL;
1.1       misho    1177: }
                   1178: 
1.1.1.2 ! misho    1179: /* Default options for cJSON_Parse */
        !          1180: CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
        !          1181: {
        !          1182:     return cJSON_ParseWithOpts(value, 0, 0);
        !          1183: }
1.1       misho    1184: 
1.1.1.2 ! misho    1185: CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
        !          1186: {
        !          1187:     return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
        !          1188: }
1.1       misho    1189: 
1.1.1.2 ! misho    1190: #define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
1.1       misho    1191: 
1.1.1.2 ! misho    1192: static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
        !          1193: {
        !          1194:     static const size_t default_buffer_size = 256;
        !          1195:     printbuffer buffer[1];
        !          1196:     unsigned char *printed = NULL;
1.1       misho    1197: 
1.1.1.2 ! misho    1198:     memset(buffer, 0, sizeof(buffer));
1.1       misho    1199: 
1.1.1.2 ! misho    1200:     /* create buffer */
        !          1201:     buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
        !          1202:     buffer->length = default_buffer_size;
        !          1203:     buffer->format = format;
        !          1204:     buffer->hooks = *hooks;
        !          1205:     if (buffer->buffer == NULL)
        !          1206:     {
        !          1207:         goto fail;
        !          1208:     }
1.1       misho    1209: 
1.1.1.2 ! misho    1210:     /* print the value */
        !          1211:     if (!print_value(item, buffer))
        !          1212:     {
        !          1213:         goto fail;
        !          1214:     }
        !          1215:     update_offset(buffer);
        !          1216: 
        !          1217:     /* check if reallocate is available */
        !          1218:     if (hooks->reallocate != NULL)
        !          1219:     {
        !          1220:         printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
        !          1221:         if (printed == NULL) {
        !          1222:             goto fail;
        !          1223:         }
        !          1224:         buffer->buffer = NULL;
        !          1225:     }
        !          1226:     else /* otherwise copy the JSON over to a new buffer */
        !          1227:     {
        !          1228:         printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
        !          1229:         if (printed == NULL)
        !          1230:         {
        !          1231:             goto fail;
        !          1232:         }
        !          1233:         memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
        !          1234:         printed[buffer->offset] = '\0'; /* just to be sure */
        !          1235: 
        !          1236:         /* free the buffer */
        !          1237:         hooks->deallocate(buffer->buffer);
        !          1238:     }
        !          1239: 
        !          1240:     return printed;
        !          1241: 
        !          1242: fail:
        !          1243:     if (buffer->buffer != NULL)
        !          1244:     {
        !          1245:         hooks->deallocate(buffer->buffer);
        !          1246:     }
        !          1247: 
        !          1248:     if (printed != NULL)
        !          1249:     {
        !          1250:         hooks->deallocate(printed);
        !          1251:     }
        !          1252: 
        !          1253:     return NULL;
        !          1254: }
        !          1255: 
        !          1256: /* Render a cJSON item/entity/structure to text. */
        !          1257: CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
        !          1258: {
        !          1259:     return (char*)print(item, true, &global_hooks);
        !          1260: }
        !          1261: 
        !          1262: CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
        !          1263: {
        !          1264:     return (char*)print(item, false, &global_hooks);
        !          1265: }
        !          1266: 
        !          1267: CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
        !          1268: {
        !          1269:     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
        !          1270: 
        !          1271:     if (prebuffer < 0)
        !          1272:     {
        !          1273:         return NULL;
        !          1274:     }
        !          1275: 
        !          1276:     p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
        !          1277:     if (!p.buffer)
        !          1278:     {
        !          1279:         return NULL;
        !          1280:     }
        !          1281: 
        !          1282:     p.length = (size_t)prebuffer;
        !          1283:     p.offset = 0;
        !          1284:     p.noalloc = false;
        !          1285:     p.format = fmt;
        !          1286:     p.hooks = global_hooks;
        !          1287: 
        !          1288:     if (!print_value(item, &p))
        !          1289:     {
        !          1290:         global_hooks.deallocate(p.buffer);
        !          1291:         return NULL;
        !          1292:     }
        !          1293: 
        !          1294:     return (char*)p.buffer;
        !          1295: }
        !          1296: 
        !          1297: CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
        !          1298: {
        !          1299:     printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
        !          1300: 
        !          1301:     if ((length < 0) || (buffer == NULL))
        !          1302:     {
        !          1303:         return false;
        !          1304:     }
        !          1305: 
        !          1306:     p.buffer = (unsigned char*)buffer;
        !          1307:     p.length = (size_t)length;
        !          1308:     p.offset = 0;
        !          1309:     p.noalloc = true;
        !          1310:     p.format = format;
        !          1311:     p.hooks = global_hooks;
        !          1312: 
        !          1313:     return print_value(item, &p);
        !          1314: }
        !          1315: 
        !          1316: /* Parser core - when encountering text, process appropriately. */
        !          1317: static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
        !          1318: {
        !          1319:     if ((input_buffer == NULL) || (input_buffer->content == NULL))
        !          1320:     {
        !          1321:         return false; /* no input */
        !          1322:     }
        !          1323: 
        !          1324:     /* parse the different types of values */
        !          1325:     /* null */
        !          1326:     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
        !          1327:     {
        !          1328:         item->type = cJSON_NULL;
        !          1329:         input_buffer->offset += 4;
        !          1330:         return true;
        !          1331:     }
        !          1332:     /* false */
        !          1333:     if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
        !          1334:     {
        !          1335:         item->type = cJSON_False;
        !          1336:         input_buffer->offset += 5;
        !          1337:         return true;
        !          1338:     }
        !          1339:     /* true */
        !          1340:     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
        !          1341:     {
        !          1342:         item->type = cJSON_True;
        !          1343:         item->valueint = 1;
        !          1344:         input_buffer->offset += 4;
        !          1345:         return true;
        !          1346:     }
        !          1347:     /* string */
        !          1348:     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
        !          1349:     {
        !          1350:         return parse_string(item, input_buffer);
        !          1351:     }
        !          1352:     /* number */
        !          1353:     if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9'))))
        !          1354:     {
        !          1355:         return parse_number(item, input_buffer);
        !          1356:     }
        !          1357:     /* array */
        !          1358:     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
        !          1359:     {
        !          1360:         return parse_array(item, input_buffer);
        !          1361:     }
        !          1362:     /* object */
        !          1363:     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
        !          1364:     {
        !          1365:         return parse_object(item, input_buffer);
        !          1366:     }
        !          1367: 
        !          1368:     return false;
        !          1369: }
        !          1370: 
        !          1371: /* Render a value to text. */
        !          1372: static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
        !          1373: {
        !          1374:     unsigned char *output = NULL;
        !          1375: 
        !          1376:     if ((item == NULL) || (output_buffer == NULL))
        !          1377:     {
        !          1378:         return false;
        !          1379:     }
        !          1380: 
        !          1381:     switch ((item->type) & 0xFF)
        !          1382:     {
        !          1383:         case cJSON_NULL:
        !          1384:             output = ensure(output_buffer, 5);
        !          1385:             if (output == NULL)
        !          1386:             {
        !          1387:                 return false;
        !          1388:             }
        !          1389:             strcpy((char*)output, "null");
        !          1390:             return true;
        !          1391: 
        !          1392:         case cJSON_False:
        !          1393:             output = ensure(output_buffer, 6);
        !          1394:             if (output == NULL)
        !          1395:             {
        !          1396:                 return false;
        !          1397:             }
        !          1398:             strcpy((char*)output, "false");
        !          1399:             return true;
        !          1400: 
        !          1401:         case cJSON_True:
        !          1402:             output = ensure(output_buffer, 5);
        !          1403:             if (output == NULL)
        !          1404:             {
        !          1405:                 return false;
        !          1406:             }
        !          1407:             strcpy((char*)output, "true");
        !          1408:             return true;
        !          1409: 
        !          1410:         case cJSON_Number:
        !          1411:             return print_number(item, output_buffer);
        !          1412: 
        !          1413:         case cJSON_Raw:
        !          1414:         {
        !          1415:             size_t raw_length = 0;
        !          1416:             if (item->valuestring == NULL)
        !          1417:             {
        !          1418:                 return false;
        !          1419:             }
        !          1420: 
        !          1421:             raw_length = strlen(item->valuestring) + sizeof("");
        !          1422:             output = ensure(output_buffer, raw_length);
        !          1423:             if (output == NULL)
        !          1424:             {
        !          1425:                 return false;
        !          1426:             }
        !          1427:             memcpy(output, item->valuestring, raw_length);
        !          1428:             return true;
        !          1429:         }
        !          1430: 
        !          1431:         case cJSON_String:
        !          1432:             return print_string(item, output_buffer);
        !          1433: 
        !          1434:         case cJSON_Array:
        !          1435:             return print_array(item, output_buffer);
        !          1436: 
        !          1437:         case cJSON_Object:
        !          1438:             return print_object(item, output_buffer);
        !          1439: 
        !          1440:         default:
        !          1441:             return false;
        !          1442:     }
        !          1443: }
        !          1444: 
        !          1445: /* Build an array from input text. */
        !          1446: static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
        !          1447: {
        !          1448:     cJSON *head = NULL; /* head of the linked list */
        !          1449:     cJSON *current_item = NULL;
        !          1450: 
        !          1451:     if (input_buffer->depth >= CJSON_NESTING_LIMIT)
        !          1452:     {
        !          1453:         return false; /* to deeply nested */
        !          1454:     }
        !          1455:     input_buffer->depth++;
        !          1456: 
        !          1457:     if (buffer_at_offset(input_buffer)[0] != '[')
        !          1458:     {
        !          1459:         /* not an array */
        !          1460:         goto fail;
        !          1461:     }
        !          1462: 
        !          1463:     input_buffer->offset++;
        !          1464:     buffer_skip_whitespace(input_buffer);
        !          1465:     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
        !          1466:     {
        !          1467:         /* empty array */
        !          1468:         goto success;
        !          1469:     }
        !          1470: 
        !          1471:     /* check if we skipped to the end of the buffer */
        !          1472:     if (cannot_access_at_index(input_buffer, 0))
        !          1473:     {
        !          1474:         input_buffer->offset--;
        !          1475:         goto fail;
        !          1476:     }
        !          1477: 
        !          1478:     /* step back to character in front of the first element */
        !          1479:     input_buffer->offset--;
        !          1480:     /* loop through the comma separated array elements */
        !          1481:     do
        !          1482:     {
        !          1483:         /* allocate next item */
        !          1484:         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
        !          1485:         if (new_item == NULL)
        !          1486:         {
        !          1487:             goto fail; /* allocation failure */
        !          1488:         }
        !          1489: 
        !          1490:         /* attach next item to list */
        !          1491:         if (head == NULL)
        !          1492:         {
        !          1493:             /* start the linked list */
        !          1494:             current_item = head = new_item;
        !          1495:         }
        !          1496:         else
        !          1497:         {
        !          1498:             /* add to the end and advance */
        !          1499:             current_item->next = new_item;
        !          1500:             new_item->prev = current_item;
        !          1501:             current_item = new_item;
        !          1502:         }
        !          1503: 
        !          1504:         /* parse next value */
        !          1505:         input_buffer->offset++;
        !          1506:         buffer_skip_whitespace(input_buffer);
        !          1507:         if (!parse_value(current_item, input_buffer))
        !          1508:         {
        !          1509:             goto fail; /* failed to parse value */
        !          1510:         }
        !          1511:         buffer_skip_whitespace(input_buffer);
        !          1512:     }
        !          1513:     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
        !          1514: 
        !          1515:     if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
        !          1516:     {
        !          1517:         goto fail; /* expected end of array */
        !          1518:     }
        !          1519: 
        !          1520: success:
        !          1521:     input_buffer->depth--;
        !          1522: 
        !          1523:     item->type = cJSON_Array;
        !          1524:     item->child = head;
        !          1525: 
        !          1526:     input_buffer->offset++;
        !          1527: 
        !          1528:     return true;
        !          1529: 
        !          1530: fail:
        !          1531:     if (head != NULL)
        !          1532:     {
        !          1533:         cJSON_Delete(head);
        !          1534:     }
        !          1535: 
        !          1536:     return false;
        !          1537: }
        !          1538: 
        !          1539: /* Render an array to text */
        !          1540: static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
        !          1541: {
        !          1542:     unsigned char *output_pointer = NULL;
        !          1543:     size_t length = 0;
        !          1544:     cJSON *current_element = item->child;
        !          1545: 
        !          1546:     if (output_buffer == NULL)
        !          1547:     {
        !          1548:         return false;
        !          1549:     }
        !          1550: 
        !          1551:     /* Compose the output array. */
        !          1552:     /* opening square bracket */
        !          1553:     output_pointer = ensure(output_buffer, 1);
        !          1554:     if (output_pointer == NULL)
        !          1555:     {
        !          1556:         return false;
        !          1557:     }
        !          1558: 
        !          1559:     *output_pointer = '[';
        !          1560:     output_buffer->offset++;
        !          1561:     output_buffer->depth++;
        !          1562: 
        !          1563:     while (current_element != NULL)
        !          1564:     {
        !          1565:         if (!print_value(current_element, output_buffer))
        !          1566:         {
        !          1567:             return false;
        !          1568:         }
        !          1569:         update_offset(output_buffer);
        !          1570:         if (current_element->next)
        !          1571:         {
        !          1572:             length = (size_t) (output_buffer->format ? 2 : 1);
        !          1573:             output_pointer = ensure(output_buffer, length + 1);
        !          1574:             if (output_pointer == NULL)
        !          1575:             {
        !          1576:                 return false;
        !          1577:             }
        !          1578:             *output_pointer++ = ',';
        !          1579:             if(output_buffer->format)
        !          1580:             {
        !          1581:                 *output_pointer++ = ' ';
        !          1582:             }
        !          1583:             *output_pointer = '\0';
        !          1584:             output_buffer->offset += length;
        !          1585:         }
        !          1586:         current_element = current_element->next;
        !          1587:     }
        !          1588: 
        !          1589:     output_pointer = ensure(output_buffer, 2);
        !          1590:     if (output_pointer == NULL)
        !          1591:     {
        !          1592:         return false;
        !          1593:     }
        !          1594:     *output_pointer++ = ']';
        !          1595:     *output_pointer = '\0';
        !          1596:     output_buffer->depth--;
        !          1597: 
        !          1598:     return true;
        !          1599: }
        !          1600: 
        !          1601: /* Build an object from the text. */
        !          1602: static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
        !          1603: {
        !          1604:     cJSON *head = NULL; /* linked list head */
        !          1605:     cJSON *current_item = NULL;
        !          1606: 
        !          1607:     if (input_buffer->depth >= CJSON_NESTING_LIMIT)
        !          1608:     {
        !          1609:         return false; /* to deeply nested */
        !          1610:     }
        !          1611:     input_buffer->depth++;
        !          1612: 
        !          1613:     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
        !          1614:     {
        !          1615:         goto fail; /* not an object */
        !          1616:     }
        !          1617: 
        !          1618:     input_buffer->offset++;
        !          1619:     buffer_skip_whitespace(input_buffer);
        !          1620:     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
        !          1621:     {
        !          1622:         goto success; /* empty object */
        !          1623:     }
        !          1624: 
        !          1625:     /* check if we skipped to the end of the buffer */
        !          1626:     if (cannot_access_at_index(input_buffer, 0))
        !          1627:     {
        !          1628:         input_buffer->offset--;
        !          1629:         goto fail;
        !          1630:     }
        !          1631: 
        !          1632:     /* step back to character in front of the first element */
        !          1633:     input_buffer->offset--;
        !          1634:     /* loop through the comma separated array elements */
        !          1635:     do
        !          1636:     {
        !          1637:         /* allocate next item */
        !          1638:         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
        !          1639:         if (new_item == NULL)
        !          1640:         {
        !          1641:             goto fail; /* allocation failure */
        !          1642:         }
        !          1643: 
        !          1644:         /* attach next item to list */
        !          1645:         if (head == NULL)
        !          1646:         {
        !          1647:             /* start the linked list */
        !          1648:             current_item = head = new_item;
        !          1649:         }
        !          1650:         else
        !          1651:         {
        !          1652:             /* add to the end and advance */
        !          1653:             current_item->next = new_item;
        !          1654:             new_item->prev = current_item;
        !          1655:             current_item = new_item;
        !          1656:         }
        !          1657: 
        !          1658:         /* parse the name of the child */
        !          1659:         input_buffer->offset++;
        !          1660:         buffer_skip_whitespace(input_buffer);
        !          1661:         if (!parse_string(current_item, input_buffer))
        !          1662:         {
        !          1663:             goto fail; /* failed to parse name */
        !          1664:         }
        !          1665:         buffer_skip_whitespace(input_buffer);
        !          1666: 
        !          1667:         /* swap valuestring and string, because we parsed the name */
        !          1668:         current_item->string = current_item->valuestring;
        !          1669:         current_item->valuestring = NULL;
        !          1670: 
        !          1671:         if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
        !          1672:         {
        !          1673:             goto fail; /* invalid object */
        !          1674:         }
        !          1675: 
        !          1676:         /* parse the value */
        !          1677:         input_buffer->offset++;
        !          1678:         buffer_skip_whitespace(input_buffer);
        !          1679:         if (!parse_value(current_item, input_buffer))
        !          1680:         {
        !          1681:             goto fail; /* failed to parse value */
        !          1682:         }
        !          1683:         buffer_skip_whitespace(input_buffer);
        !          1684:     }
        !          1685:     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
        !          1686: 
        !          1687:     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
        !          1688:     {
        !          1689:         goto fail; /* expected end of object */
        !          1690:     }
        !          1691: 
        !          1692: success:
        !          1693:     input_buffer->depth--;
        !          1694: 
        !          1695:     item->type = cJSON_Object;
        !          1696:     item->child = head;
        !          1697: 
        !          1698:     input_buffer->offset++;
        !          1699:     return true;
        !          1700: 
        !          1701: fail:
        !          1702:     if (head != NULL)
        !          1703:     {
        !          1704:         cJSON_Delete(head);
        !          1705:     }
        !          1706: 
        !          1707:     return false;
        !          1708: }
        !          1709: 
        !          1710: /* Render an object to text. */
        !          1711: static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
        !          1712: {
        !          1713:     unsigned char *output_pointer = NULL;
        !          1714:     size_t length = 0;
        !          1715:     cJSON *current_item = item->child;
        !          1716: 
        !          1717:     if (output_buffer == NULL)
        !          1718:     {
        !          1719:         return false;
        !          1720:     }
        !          1721: 
        !          1722:     /* Compose the output: */
        !          1723:     length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
        !          1724:     output_pointer = ensure(output_buffer, length + 1);
        !          1725:     if (output_pointer == NULL)
        !          1726:     {
        !          1727:         return false;
        !          1728:     }
        !          1729: 
        !          1730:     *output_pointer++ = '{';
        !          1731:     output_buffer->depth++;
        !          1732:     if (output_buffer->format)
        !          1733:     {
        !          1734:         *output_pointer++ = '\n';
        !          1735:     }
        !          1736:     output_buffer->offset += length;
        !          1737: 
        !          1738:     while (current_item)
        !          1739:     {
        !          1740:         if (output_buffer->format)
        !          1741:         {
        !          1742:             size_t i;
        !          1743:             output_pointer = ensure(output_buffer, output_buffer->depth);
        !          1744:             if (output_pointer == NULL)
        !          1745:             {
        !          1746:                 return false;
        !          1747:             }
        !          1748:             for (i = 0; i < output_buffer->depth; i++)
        !          1749:             {
        !          1750:                 *output_pointer++ = '\t';
        !          1751:             }
        !          1752:             output_buffer->offset += output_buffer->depth;
        !          1753:         }
        !          1754: 
        !          1755:         /* print key */
        !          1756:         if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
        !          1757:         {
        !          1758:             return false;
        !          1759:         }
        !          1760:         update_offset(output_buffer);
        !          1761: 
        !          1762:         length = (size_t) (output_buffer->format ? 2 : 1);
        !          1763:         output_pointer = ensure(output_buffer, length);
        !          1764:         if (output_pointer == NULL)
        !          1765:         {
        !          1766:             return false;
        !          1767:         }
        !          1768:         *output_pointer++ = ':';
        !          1769:         if (output_buffer->format)
        !          1770:         {
        !          1771:             *output_pointer++ = '\t';
        !          1772:         }
        !          1773:         output_buffer->offset += length;
        !          1774: 
        !          1775:         /* print value */
        !          1776:         if (!print_value(current_item, output_buffer))
        !          1777:         {
        !          1778:             return false;
        !          1779:         }
        !          1780:         update_offset(output_buffer);
        !          1781: 
        !          1782:         /* print comma if not last */
        !          1783:         length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
        !          1784:         output_pointer = ensure(output_buffer, length + 1);
        !          1785:         if (output_pointer == NULL)
        !          1786:         {
        !          1787:             return false;
        !          1788:         }
        !          1789:         if (current_item->next)
        !          1790:         {
        !          1791:             *output_pointer++ = ',';
        !          1792:         }
        !          1793: 
        !          1794:         if (output_buffer->format)
        !          1795:         {
        !          1796:             *output_pointer++ = '\n';
        !          1797:         }
        !          1798:         *output_pointer = '\0';
        !          1799:         output_buffer->offset += length;
        !          1800: 
        !          1801:         current_item = current_item->next;
        !          1802:     }
        !          1803: 
        !          1804:     output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
        !          1805:     if (output_pointer == NULL)
        !          1806:     {
        !          1807:         return false;
        !          1808:     }
        !          1809:     if (output_buffer->format)
        !          1810:     {
        !          1811:         size_t i;
        !          1812:         for (i = 0; i < (output_buffer->depth - 1); i++)
        !          1813:         {
        !          1814:             *output_pointer++ = '\t';
        !          1815:         }
        !          1816:     }
        !          1817:     *output_pointer++ = '}';
        !          1818:     *output_pointer = '\0';
        !          1819:     output_buffer->depth--;
        !          1820: 
        !          1821:     return true;
        !          1822: }
        !          1823: 
        !          1824: /* Get Array size/item / object item. */
        !          1825: CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
        !          1826: {
        !          1827:     cJSON *child = NULL;
        !          1828:     size_t size = 0;
        !          1829: 
        !          1830:     if (array == NULL)
        !          1831:     {
        !          1832:         return 0;
        !          1833:     }
        !          1834: 
        !          1835:     child = array->child;
        !          1836: 
        !          1837:     while(child != NULL)
        !          1838:     {
        !          1839:         size++;
        !          1840:         child = child->next;
        !          1841:     }
        !          1842: 
        !          1843:     /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
        !          1844: 
        !          1845:     return (int)size;
        !          1846: }
        !          1847: 
        !          1848: static cJSON* get_array_item(const cJSON *array, size_t index)
        !          1849: {
        !          1850:     cJSON *current_child = NULL;
        !          1851: 
        !          1852:     if (array == NULL)
        !          1853:     {
        !          1854:         return NULL;
        !          1855:     }
        !          1856: 
        !          1857:     current_child = array->child;
        !          1858:     while ((current_child != NULL) && (index > 0))
        !          1859:     {
        !          1860:         index--;
        !          1861:         current_child = current_child->next;
        !          1862:     }
        !          1863: 
        !          1864:     return current_child;
        !          1865: }
        !          1866: 
        !          1867: CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
        !          1868: {
        !          1869:     if (index < 0)
        !          1870:     {
        !          1871:         return NULL;
        !          1872:     }
        !          1873: 
        !          1874:     return get_array_item(array, (size_t)index);
        !          1875: }
        !          1876: 
        !          1877: static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
        !          1878: {
        !          1879:     cJSON *current_element = NULL;
        !          1880: 
        !          1881:     if ((object == NULL) || (name == NULL))
        !          1882:     {
        !          1883:         return NULL;
        !          1884:     }
        !          1885: 
        !          1886:     current_element = object->child;
        !          1887:     if (case_sensitive)
        !          1888:     {
        !          1889:         while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
        !          1890:         {
        !          1891:             current_element = current_element->next;
        !          1892:         }
        !          1893:     }
        !          1894:     else
        !          1895:     {
        !          1896:         while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
        !          1897:         {
        !          1898:             current_element = current_element->next;
        !          1899:         }
        !          1900:     }
        !          1901: 
        !          1902:     if ((current_element == NULL) || (current_element->string == NULL)) {
        !          1903:         return NULL;
        !          1904:     }
        !          1905: 
        !          1906:     return current_element;
        !          1907: }
        !          1908: 
        !          1909: CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
        !          1910: {
        !          1911:     return get_object_item(object, string, false);
        !          1912: }
        !          1913: 
        !          1914: CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
        !          1915: {
        !          1916:     return get_object_item(object, string, true);
        !          1917: }
        !          1918: 
        !          1919: CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
        !          1920: {
        !          1921:     return cJSON_GetObjectItem(object, string) ? 1 : 0;
        !          1922: }
        !          1923: 
        !          1924: /* Utility for array list handling. */
        !          1925: static void suffix_object(cJSON *prev, cJSON *item)
        !          1926: {
        !          1927:     prev->next = item;
        !          1928:     item->prev = prev;
        !          1929: }
        !          1930: 
        !          1931: /* Utility for handling references. */
        !          1932: static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
        !          1933: {
        !          1934:     cJSON *reference = NULL;
        !          1935:     if (item == NULL)
        !          1936:     {
        !          1937:         return NULL;
        !          1938:     }
        !          1939: 
        !          1940:     reference = cJSON_New_Item(hooks);
        !          1941:     if (reference == NULL)
        !          1942:     {
        !          1943:         return NULL;
        !          1944:     }
        !          1945: 
        !          1946:     memcpy(reference, item, sizeof(cJSON));
        !          1947:     reference->string = NULL;
        !          1948:     reference->type |= cJSON_IsReference;
        !          1949:     reference->next = reference->prev = NULL;
        !          1950:     return reference;
        !          1951: }
        !          1952: 
        !          1953: static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
        !          1954: {
        !          1955:     cJSON *child = NULL;
        !          1956: 
        !          1957:     if ((item == NULL) || (array == NULL) || (array == item))
        !          1958:     {
        !          1959:         return false;
        !          1960:     }
        !          1961: 
        !          1962:     child = array->child;
        !          1963:     /*
        !          1964:      * To find the last item in array quickly, we use prev in array
        !          1965:      */
        !          1966:     if (child == NULL)
        !          1967:     {
        !          1968:         /* list is empty, start new one */
        !          1969:         array->child = item;
        !          1970:         item->prev = item;
        !          1971:         item->next = NULL;
        !          1972:     }
        !          1973:     else
        !          1974:     {
        !          1975:         /* append to the end */
        !          1976:         if (child->prev)
        !          1977:         {
        !          1978:             suffix_object(child->prev, item);
        !          1979:             array->child->prev = item;
        !          1980:         }
        !          1981:         else
        !          1982:         {
        !          1983:             while (child->next)
        !          1984:             {
        !          1985:                 child = child->next;
        !          1986:             }
        !          1987:             suffix_object(child, item);
        !          1988:             array->child->prev = item;
        !          1989:         }
        !          1990:     }
        !          1991: 
        !          1992:     return true;
        !          1993: }
        !          1994: 
        !          1995: /* Add item to array/object. */
        !          1996: CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
        !          1997: {
        !          1998:     return add_item_to_array(array, item);
        !          1999: }
        !          2000: 
        !          2001: #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
        !          2002:     #pragma GCC diagnostic push
        !          2003: #endif
        !          2004: #ifdef __GNUC__
        !          2005: #pragma GCC diagnostic ignored "-Wcast-qual"
        !          2006: #endif
        !          2007: /* helper function to cast away const */
        !          2008: static void* cast_away_const(const void* string)
        !          2009: {
        !          2010:     return (void*)string;
        !          2011: }
        !          2012: #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
        !          2013:     #pragma GCC diagnostic pop
        !          2014: #endif
        !          2015: 
        !          2016: 
        !          2017: static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
        !          2018: {
        !          2019:     char *new_key = NULL;
        !          2020:     int new_type = cJSON_Invalid;
        !          2021: 
        !          2022:     if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
        !          2023:     {
        !          2024:         return false;
        !          2025:     }
        !          2026: 
        !          2027:     if (constant_key)
        !          2028:     {
        !          2029:         new_key = (char*)cast_away_const(string);
        !          2030:         new_type = item->type | cJSON_StringIsConst;
        !          2031:     }
        !          2032:     else
        !          2033:     {
        !          2034:         new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
        !          2035:         if (new_key == NULL)
        !          2036:         {
        !          2037:             return false;
        !          2038:         }
        !          2039: 
        !          2040:         new_type = item->type & ~cJSON_StringIsConst;
        !          2041:     }
        !          2042: 
        !          2043:     if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
        !          2044:     {
        !          2045:         hooks->deallocate(item->string);
        !          2046:     }
        !          2047: 
        !          2048:     item->string = new_key;
        !          2049:     item->type = new_type;
        !          2050: 
        !          2051:     return add_item_to_array(object, item);
        !          2052: }
        !          2053: 
        !          2054: CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
        !          2055: {
        !          2056:     return add_item_to_object(object, string, item, &global_hooks, false);
        !          2057: }
        !          2058: 
        !          2059: /* Add an item to an object with constant string as key */
        !          2060: CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
        !          2061: {
        !          2062:     return add_item_to_object(object, string, item, &global_hooks, true);
        !          2063: }
        !          2064: 
        !          2065: CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
        !          2066: {
        !          2067:     if (array == NULL)
        !          2068:     {
        !          2069:         return false;
        !          2070:     }
        !          2071: 
        !          2072:     return add_item_to_array(array, create_reference(item, &global_hooks));
        !          2073: }
        !          2074: 
        !          2075: CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
        !          2076: {
        !          2077:     if ((object == NULL) || (string == NULL))
        !          2078:     {
        !          2079:         return false;
        !          2080:     }
        !          2081: 
        !          2082:     return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
        !          2083: }
        !          2084: 
        !          2085: CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
        !          2086: {
        !          2087:     cJSON *null = cJSON_CreateNull();
        !          2088:     if (add_item_to_object(object, name, null, &global_hooks, false))
        !          2089:     {
        !          2090:         return null;
        !          2091:     }
        !          2092: 
        !          2093:     cJSON_Delete(null);
        !          2094:     return NULL;
        !          2095: }
        !          2096: 
        !          2097: CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
        !          2098: {
        !          2099:     cJSON *true_item = cJSON_CreateTrue();
        !          2100:     if (add_item_to_object(object, name, true_item, &global_hooks, false))
        !          2101:     {
        !          2102:         return true_item;
        !          2103:     }
        !          2104: 
        !          2105:     cJSON_Delete(true_item);
        !          2106:     return NULL;
        !          2107: }
        !          2108: 
        !          2109: CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
        !          2110: {
        !          2111:     cJSON *false_item = cJSON_CreateFalse();
        !          2112:     if (add_item_to_object(object, name, false_item, &global_hooks, false))
        !          2113:     {
        !          2114:         return false_item;
        !          2115:     }
        !          2116: 
        !          2117:     cJSON_Delete(false_item);
        !          2118:     return NULL;
        !          2119: }
        !          2120: 
        !          2121: CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
        !          2122: {
        !          2123:     cJSON *bool_item = cJSON_CreateBool(boolean);
        !          2124:     if (add_item_to_object(object, name, bool_item, &global_hooks, false))
        !          2125:     {
        !          2126:         return bool_item;
        !          2127:     }
        !          2128: 
        !          2129:     cJSON_Delete(bool_item);
        !          2130:     return NULL;
        !          2131: }
        !          2132: 
        !          2133: CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
        !          2134: {
        !          2135:     cJSON *number_item = cJSON_CreateNumber(number);
        !          2136:     if (add_item_to_object(object, name, number_item, &global_hooks, false))
        !          2137:     {
        !          2138:         return number_item;
        !          2139:     }
        !          2140: 
        !          2141:     cJSON_Delete(number_item);
        !          2142:     return NULL;
        !          2143: }
        !          2144: 
        !          2145: CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
        !          2146: {
        !          2147:     cJSON *string_item = cJSON_CreateString(string);
        !          2148:     if (add_item_to_object(object, name, string_item, &global_hooks, false))
        !          2149:     {
        !          2150:         return string_item;
        !          2151:     }
        !          2152: 
        !          2153:     cJSON_Delete(string_item);
        !          2154:     return NULL;
        !          2155: }
        !          2156: 
        !          2157: CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
        !          2158: {
        !          2159:     cJSON *raw_item = cJSON_CreateRaw(raw);
        !          2160:     if (add_item_to_object(object, name, raw_item, &global_hooks, false))
        !          2161:     {
        !          2162:         return raw_item;
        !          2163:     }
        !          2164: 
        !          2165:     cJSON_Delete(raw_item);
        !          2166:     return NULL;
        !          2167: }
        !          2168: 
        !          2169: CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
        !          2170: {
        !          2171:     cJSON *object_item = cJSON_CreateObject();
        !          2172:     if (add_item_to_object(object, name, object_item, &global_hooks, false))
        !          2173:     {
        !          2174:         return object_item;
        !          2175:     }
        !          2176: 
        !          2177:     cJSON_Delete(object_item);
        !          2178:     return NULL;
        !          2179: }
        !          2180: 
        !          2181: CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
        !          2182: {
        !          2183:     cJSON *array = cJSON_CreateArray();
        !          2184:     if (add_item_to_object(object, name, array, &global_hooks, false))
        !          2185:     {
        !          2186:         return array;
        !          2187:     }
        !          2188: 
        !          2189:     cJSON_Delete(array);
        !          2190:     return NULL;
        !          2191: }
        !          2192: 
        !          2193: CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
        !          2194: {
        !          2195:     if ((parent == NULL) || (item == NULL))
        !          2196:     {
        !          2197:         return NULL;
        !          2198:     }
        !          2199: 
        !          2200:     if (item != parent->child)
        !          2201:     {
        !          2202:         /* not the first element */
        !          2203:         item->prev->next = item->next;
        !          2204:     }
        !          2205:     if (item->next != NULL)
        !          2206:     {
        !          2207:         /* not the last element */
        !          2208:         item->next->prev = item->prev;
        !          2209:     }
        !          2210: 
        !          2211:     if (item == parent->child)
        !          2212:     {
        !          2213:         /* first element */
        !          2214:         parent->child = item->next;
        !          2215:     }
        !          2216:     /* make sure the detached item doesn't point anywhere anymore */
        !          2217:     item->prev = NULL;
        !          2218:     item->next = NULL;
        !          2219: 
        !          2220:     return item;
        !          2221: }
        !          2222: 
        !          2223: CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
        !          2224: {
        !          2225:     if (which < 0)
        !          2226:     {
        !          2227:         return NULL;
        !          2228:     }
        !          2229: 
        !          2230:     return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
        !          2231: }
        !          2232: 
        !          2233: CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
        !          2234: {
        !          2235:     cJSON_Delete(cJSON_DetachItemFromArray(array, which));
        !          2236: }
        !          2237: 
        !          2238: CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
        !          2239: {
        !          2240:     cJSON *to_detach = cJSON_GetObjectItem(object, string);
        !          2241: 
        !          2242:     return cJSON_DetachItemViaPointer(object, to_detach);
        !          2243: }
        !          2244: 
        !          2245: CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
        !          2246: {
        !          2247:     cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
        !          2248: 
        !          2249:     return cJSON_DetachItemViaPointer(object, to_detach);
        !          2250: }
        !          2251: 
        !          2252: CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
        !          2253: {
        !          2254:     cJSON_Delete(cJSON_DetachItemFromObject(object, string));
        !          2255: }
        !          2256: 
        !          2257: CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
        !          2258: {
        !          2259:     cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
        !          2260: }
        !          2261: 
        !          2262: /* Replace array/object items with new ones. */
        !          2263: CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
        !          2264: {
        !          2265:     cJSON *after_inserted = NULL;
        !          2266: 
        !          2267:     if (which < 0)
        !          2268:     {
        !          2269:         return false;
        !          2270:     }
        !          2271: 
        !          2272:     after_inserted = get_array_item(array, (size_t)which);
        !          2273:     if (after_inserted == NULL)
        !          2274:     {
        !          2275:         return add_item_to_array(array, newitem);
        !          2276:     }
        !          2277: 
        !          2278:     newitem->next = after_inserted;
        !          2279:     newitem->prev = after_inserted->prev;
        !          2280:     after_inserted->prev = newitem;
        !          2281:     if (after_inserted == array->child)
        !          2282:     {
        !          2283:         array->child = newitem;
        !          2284:     }
        !          2285:     else
        !          2286:     {
        !          2287:         newitem->prev->next = newitem;
        !          2288:     }
        !          2289:     return true;
        !          2290: }
        !          2291: 
        !          2292: CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
        !          2293: {
        !          2294:     if ((parent == NULL) || (replacement == NULL) || (item == NULL))
        !          2295:     {
        !          2296:         return false;
        !          2297:     }
        !          2298: 
        !          2299:     if (replacement == item)
        !          2300:     {
        !          2301:         return true;
        !          2302:     }
        !          2303: 
        !          2304:     replacement->next = item->next;
        !          2305:     replacement->prev = item->prev;
        !          2306: 
        !          2307:     if (replacement->next != NULL)
        !          2308:     {
        !          2309:         replacement->next->prev = replacement;
        !          2310:     }
        !          2311:     if (parent->child == item)
        !          2312:     {
        !          2313:         parent->child = replacement;
        !          2314:     }
        !          2315:     else
        !          2316:     {   /*
        !          2317:          * To find the last item in array quickly, we use prev in array.
        !          2318:          * We can't modify the last item's next pointer where this item was the parent's child
        !          2319:          */
        !          2320:         if (replacement->prev != NULL)
        !          2321:         {
        !          2322:             replacement->prev->next = replacement;
        !          2323:         }
        !          2324:     }
        !          2325: 
        !          2326:     item->next = NULL;
        !          2327:     item->prev = NULL;
        !          2328:     cJSON_Delete(item);
        !          2329: 
        !          2330:     return true;
        !          2331: }
        !          2332: 
        !          2333: CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
        !          2334: {
        !          2335:     if (which < 0)
        !          2336:     {
        !          2337:         return false;
        !          2338:     }
        !          2339: 
        !          2340:     return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
        !          2341: }
        !          2342: 
        !          2343: static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
        !          2344: {
        !          2345:     if ((replacement == NULL) || (string == NULL))
        !          2346:     {
        !          2347:         return false;
        !          2348:     }
        !          2349: 
        !          2350:     /* replace the name in the replacement */
        !          2351:     if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
        !          2352:     {
        !          2353:         cJSON_free(replacement->string);
        !          2354:     }
        !          2355:     replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
        !          2356:     replacement->type &= ~cJSON_StringIsConst;
        !          2357: 
        !          2358:     return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
        !          2359: }
        !          2360: 
        !          2361: CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
        !          2362: {
        !          2363:     return replace_item_in_object(object, string, newitem, false);
        !          2364: }
        !          2365: 
        !          2366: CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
        !          2367: {
        !          2368:     return replace_item_in_object(object, string, newitem, true);
        !          2369: }
        !          2370: 
        !          2371: /* Create basic types: */
        !          2372: CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
        !          2373: {
        !          2374:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2375:     if(item)
        !          2376:     {
        !          2377:         item->type = cJSON_NULL;
        !          2378:     }
        !          2379: 
        !          2380:     return item;
        !          2381: }
        !          2382: 
        !          2383: CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
        !          2384: {
        !          2385:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2386:     if(item)
        !          2387:     {
        !          2388:         item->type = cJSON_True;
        !          2389:     }
        !          2390: 
        !          2391:     return item;
        !          2392: }
        !          2393: 
        !          2394: CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
        !          2395: {
        !          2396:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2397:     if(item)
        !          2398:     {
        !          2399:         item->type = cJSON_False;
        !          2400:     }
        !          2401: 
        !          2402:     return item;
        !          2403: }
        !          2404: 
        !          2405: CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
        !          2406: {
        !          2407:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2408:     if(item)
        !          2409:     {
        !          2410:         item->type = boolean ? cJSON_True : cJSON_False;
        !          2411:     }
        !          2412: 
        !          2413:     return item;
        !          2414: }
        !          2415: 
        !          2416: CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
        !          2417: {
        !          2418:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2419:     if(item)
        !          2420:     {
        !          2421:         item->type = cJSON_Number;
        !          2422:         item->valuedouble = num;
        !          2423: 
        !          2424:         /* use saturation in case of overflow */
        !          2425:         if (num >= LLONG_MAX)
        !          2426:         {
        !          2427:             item->valueint = LLONG_MAX;
        !          2428:         }
        !          2429:         else if (num <= (double)LLONG_MIN)
        !          2430:         {
        !          2431:             item->valueint = LLONG_MIN;
        !          2432:         }
        !          2433:         else
        !          2434:         {
        !          2435:             item->valueint = (int64_t)num;
        !          2436:         }
        !          2437:     }
        !          2438: 
        !          2439:     return item;
        !          2440: }
        !          2441: 
        !          2442: CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
        !          2443: {
        !          2444:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2445:     if(item)
        !          2446:     {
        !          2447:         item->type = cJSON_String;
        !          2448:         item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
        !          2449:         if(!item->valuestring)
        !          2450:         {
        !          2451:             cJSON_Delete(item);
        !          2452:             return NULL;
        !          2453:         }
        !          2454:     }
        !          2455: 
        !          2456:     return item;
        !          2457: }
        !          2458: 
        !          2459: CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
        !          2460: {
        !          2461:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2462:     if (item != NULL)
        !          2463:     {
        !          2464:         item->type = cJSON_String | cJSON_IsReference;
        !          2465:         item->valuestring = (char*)cast_away_const(string);
        !          2466:     }
        !          2467: 
        !          2468:     return item;
        !          2469: }
        !          2470: 
        !          2471: CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
        !          2472: {
        !          2473:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2474:     if (item != NULL) {
        !          2475:         item->type = cJSON_Object | cJSON_IsReference;
        !          2476:         item->child = (cJSON*)cast_away_const(child);
        !          2477:     }
        !          2478: 
        !          2479:     return item;
        !          2480: }
        !          2481: 
        !          2482: CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
        !          2483:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2484:     if (item != NULL) {
        !          2485:         item->type = cJSON_Array | cJSON_IsReference;
        !          2486:         item->child = (cJSON*)cast_away_const(child);
        !          2487:     }
        !          2488: 
        !          2489:     return item;
        !          2490: }
        !          2491: 
        !          2492: CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
        !          2493: {
        !          2494:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2495:     if(item)
        !          2496:     {
        !          2497:         item->type = cJSON_Raw;
        !          2498:         item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
        !          2499:         if(!item->valuestring)
        !          2500:         {
        !          2501:             cJSON_Delete(item);
        !          2502:             return NULL;
        !          2503:         }
        !          2504:     }
        !          2505: 
        !          2506:     return item;
        !          2507: }
        !          2508: 
        !          2509: CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
        !          2510: {
        !          2511:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2512:     if(item)
        !          2513:     {
        !          2514:         item->type=cJSON_Array;
        !          2515:     }
        !          2516: 
        !          2517:     return item;
        !          2518: }
        !          2519: 
        !          2520: CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
        !          2521: {
        !          2522:     cJSON *item = cJSON_New_Item(&global_hooks);
        !          2523:     if (item)
        !          2524:     {
        !          2525:         item->type = cJSON_Object;
        !          2526:     }
        !          2527: 
        !          2528:     return item;
        !          2529: }
        !          2530: 
        !          2531: /* Create Arrays: */
        !          2532: CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
        !          2533: {
        !          2534:     size_t i = 0;
        !          2535:     cJSON *n = NULL;
        !          2536:     cJSON *p = NULL;
        !          2537:     cJSON *a = NULL;
        !          2538: 
        !          2539:     if ((count < 0) || (numbers == NULL))
        !          2540:     {
        !          2541:         return NULL;
        !          2542:     }
        !          2543: 
        !          2544:     a = cJSON_CreateArray();
        !          2545:     for(i = 0; a && (i < (size_t)count); i++)
        !          2546:     {
        !          2547:         n = cJSON_CreateNumber(numbers[i]);
        !          2548:         if (!n)
        !          2549:         {
        !          2550:             cJSON_Delete(a);
        !          2551:             return NULL;
        !          2552:         }
        !          2553:         if(!i)
        !          2554:         {
        !          2555:             a->child = n;
        !          2556:         }
        !          2557:         else
        !          2558:         {
        !          2559:             suffix_object(p, n);
        !          2560:         }
        !          2561:         p = n;
        !          2562:     }
        !          2563: 
        !          2564:     return a;
        !          2565: }
        !          2566: 
        !          2567: CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
        !          2568: {
        !          2569:     size_t i = 0;
        !          2570:     cJSON *n = NULL;
        !          2571:     cJSON *p = NULL;
        !          2572:     cJSON *a = NULL;
        !          2573: 
        !          2574:     if ((count < 0) || (numbers == NULL))
        !          2575:     {
        !          2576:         return NULL;
        !          2577:     }
        !          2578: 
        !          2579:     a = cJSON_CreateArray();
        !          2580: 
        !          2581:     for(i = 0; a && (i < (size_t)count); i++)
        !          2582:     {
        !          2583:         n = cJSON_CreateNumber((double)numbers[i]);
        !          2584:         if(!n)
        !          2585:         {
        !          2586:             cJSON_Delete(a);
        !          2587:             return NULL;
        !          2588:         }
        !          2589:         if(!i)
        !          2590:         {
        !          2591:             a->child = n;
        !          2592:         }
        !          2593:         else
        !          2594:         {
        !          2595:             suffix_object(p, n);
        !          2596:         }
        !          2597:         p = n;
        !          2598:     }
        !          2599: 
        !          2600:     return a;
        !          2601: }
        !          2602: 
        !          2603: CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
        !          2604: {
        !          2605:     size_t i = 0;
        !          2606:     cJSON *n = NULL;
        !          2607:     cJSON *p = NULL;
        !          2608:     cJSON *a = NULL;
        !          2609: 
        !          2610:     if ((count < 0) || (numbers == NULL))
        !          2611:     {
        !          2612:         return NULL;
        !          2613:     }
        !          2614: 
        !          2615:     a = cJSON_CreateArray();
        !          2616: 
        !          2617:     for(i = 0;a && (i < (size_t)count); i++)
        !          2618:     {
        !          2619:         n = cJSON_CreateNumber(numbers[i]);
        !          2620:         if(!n)
        !          2621:         {
        !          2622:             cJSON_Delete(a);
        !          2623:             return NULL;
        !          2624:         }
        !          2625:         if(!i)
        !          2626:         {
        !          2627:             a->child = n;
        !          2628:         }
        !          2629:         else
        !          2630:         {
        !          2631:             suffix_object(p, n);
        !          2632:         }
        !          2633:         p = n;
        !          2634:     }
        !          2635: 
        !          2636:     return a;
        !          2637: }
        !          2638: 
        !          2639: CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
        !          2640: {
        !          2641:     size_t i = 0;
        !          2642:     cJSON *n = NULL;
        !          2643:     cJSON *p = NULL;
        !          2644:     cJSON *a = NULL;
        !          2645: 
        !          2646:     if ((count < 0) || (strings == NULL))
        !          2647:     {
        !          2648:         return NULL;
        !          2649:     }
        !          2650: 
        !          2651:     a = cJSON_CreateArray();
        !          2652: 
        !          2653:     for (i = 0; a && (i < (size_t)count); i++)
        !          2654:     {
        !          2655:         n = cJSON_CreateString(strings[i]);
        !          2656:         if(!n)
        !          2657:         {
        !          2658:             cJSON_Delete(a);
        !          2659:             return NULL;
        !          2660:         }
        !          2661:         if(!i)
        !          2662:         {
        !          2663:             a->child = n;
        !          2664:         }
        !          2665:         else
        !          2666:         {
        !          2667:             suffix_object(p,n);
        !          2668:         }
        !          2669:         p = n;
        !          2670:     }
        !          2671: 
        !          2672:     return a;
        !          2673: }
        !          2674: 
        !          2675: /* Duplication */
        !          2676: CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
        !          2677: {
        !          2678:     cJSON *newitem = NULL;
        !          2679:     cJSON *child = NULL;
        !          2680:     cJSON *next = NULL;
        !          2681:     cJSON *newchild = NULL;
        !          2682: 
        !          2683:     /* Bail on bad ptr */
        !          2684:     if (!item)
        !          2685:     {
        !          2686:         goto fail;
        !          2687:     }
        !          2688:     /* Create new item */
        !          2689:     newitem = cJSON_New_Item(&global_hooks);
        !          2690:     if (!newitem)
        !          2691:     {
        !          2692:         goto fail;
        !          2693:     }
        !          2694:     /* Copy over all vars */
        !          2695:     newitem->type = item->type & (~cJSON_IsReference);
        !          2696:     newitem->valueint = item->valueint;
        !          2697:     newitem->valuedouble = item->valuedouble;
        !          2698:     if (item->valuestring)
        !          2699:     {
        !          2700:         newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
        !          2701:         if (!newitem->valuestring)
        !          2702:         {
        !          2703:             goto fail;
        !          2704:         }
        !          2705:     }
        !          2706:     if (item->string)
        !          2707:     {
        !          2708:         newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
        !          2709:         if (!newitem->string)
        !          2710:         {
        !          2711:             goto fail;
        !          2712:         }
        !          2713:     }
        !          2714:     /* If non-recursive, then we're done! */
        !          2715:     if (!recurse)
        !          2716:     {
        !          2717:         return newitem;
        !          2718:     }
        !          2719:     /* Walk the ->next chain for the child. */
        !          2720:     child = item->child;
        !          2721:     while (child != NULL)
        !          2722:     {
        !          2723:         newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
        !          2724:         if (!newchild)
        !          2725:         {
        !          2726:             goto fail;
        !          2727:         }
        !          2728:         if (next != NULL)
        !          2729:         {
        !          2730:             /* If newitem->child already set, then crosswire ->prev and ->next and move on */
        !          2731:             next->next = newchild;
        !          2732:             newchild->prev = next;
        !          2733:             next = newchild;
        !          2734:         }
        !          2735:         else
        !          2736:         {
        !          2737:             /* Set newitem->child and move to it */
        !          2738:             newitem->child = newchild;
        !          2739:             next = newchild;
        !          2740:         }
        !          2741:         child = child->next;
        !          2742:     }
        !          2743: 
        !          2744:     return newitem;
        !          2745: 
        !          2746: fail:
        !          2747:     if (newitem != NULL)
        !          2748:     {
        !          2749:         cJSON_Delete(newitem);
        !          2750:     }
        !          2751: 
        !          2752:     return NULL;
        !          2753: }
        !          2754: 
        !          2755: static void skip_oneline_comment(char **input)
        !          2756: {
        !          2757:     *input += static_strlen("//");
        !          2758: 
        !          2759:     for (; (*input)[0] != '\0'; ++(*input))
        !          2760:     {
        !          2761:         if ((*input)[0] == '\n') {
        !          2762:             *input += static_strlen("\n");
        !          2763:             return;
        !          2764:         }
        !          2765:     }
        !          2766: }
        !          2767: 
        !          2768: static void skip_multiline_comment(char **input)
        !          2769: {
        !          2770:     *input += static_strlen("/*");
        !          2771: 
        !          2772:     for (; (*input)[0] != '\0'; ++(*input))
        !          2773:     {
        !          2774:         if (((*input)[0] == '*') && ((*input)[1] == '/'))
        !          2775:         {
        !          2776:             *input += static_strlen("*/");
        !          2777:             return;
        !          2778:         }
        !          2779:     }
        !          2780: }
        !          2781: 
        !          2782: static void minify_string(char **input, char **output) {
        !          2783:     (*output)[0] = (*input)[0];
        !          2784:     *input += static_strlen("\"");
        !          2785:     *output += static_strlen("\"");
        !          2786: 
        !          2787: 
        !          2788:     for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
        !          2789:         (*output)[0] = (*input)[0];
        !          2790: 
        !          2791:         if ((*input)[0] == '\"') {
        !          2792:             (*output)[0] = '\"';
        !          2793:             *input += static_strlen("\"");
        !          2794:             *output += static_strlen("\"");
        !          2795:             return;
        !          2796:         } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
        !          2797:             (*output)[1] = (*input)[1];
        !          2798:             *input += static_strlen("\"");
        !          2799:             *output += static_strlen("\"");
        !          2800:         }
        !          2801:     }
        !          2802: }
        !          2803: 
        !          2804: CJSON_PUBLIC(void) cJSON_Minify(char *json)
        !          2805: {
        !          2806:     char *into = json;
        !          2807: 
        !          2808:     if (json == NULL)
        !          2809:     {
        !          2810:         return;
        !          2811:     }
        !          2812: 
        !          2813:     while (json[0] != '\0')
        !          2814:     {
        !          2815:         switch (json[0])
        !          2816:         {
        !          2817:             case ' ':
        !          2818:             case '\t':
        !          2819:             case '\r':
        !          2820:             case '\n':
        !          2821:                 json++;
        !          2822:                 break;
        !          2823: 
        !          2824:             case '/':
        !          2825:                 if (json[1] == '/')
        !          2826:                 {
        !          2827:                     skip_oneline_comment(&json);
        !          2828:                 }
        !          2829:                 else if (json[1] == '*')
        !          2830:                 {
        !          2831:                     skip_multiline_comment(&json);
        !          2832:                 } else {
        !          2833:                     json++;
        !          2834:                 }
        !          2835:                 break;
        !          2836: 
        !          2837:             case '\"':
        !          2838:                 minify_string(&json, (char**)&into);
        !          2839:                 break;
        !          2840: 
        !          2841:             default:
        !          2842:                 into[0] = json[0];
        !          2843:                 json++;
        !          2844:                 into++;
        !          2845:         }
        !          2846:     }
        !          2847: 
        !          2848:     /* and null-terminate. */
        !          2849:     *into = '\0';
        !          2850: }
        !          2851: 
        !          2852: CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
        !          2853: {
        !          2854:     if (item == NULL)
        !          2855:     {
        !          2856:         return false;
        !          2857:     }
        !          2858: 
        !          2859:     return (item->type & 0xFF) == cJSON_Invalid;
        !          2860: }
        !          2861: 
        !          2862: CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
        !          2863: {
        !          2864:     if (item == NULL)
        !          2865:     {
        !          2866:         return false;
        !          2867:     }
        !          2868: 
        !          2869:     return (item->type & 0xFF) == cJSON_False;
        !          2870: }
        !          2871: 
        !          2872: CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
        !          2873: {
        !          2874:     if (item == NULL)
        !          2875:     {
        !          2876:         return false;
        !          2877:     }
        !          2878: 
        !          2879:     return (item->type & 0xff) == cJSON_True;
        !          2880: }
        !          2881: 
        !          2882: 
        !          2883: CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
        !          2884: {
        !          2885:     if (item == NULL)
        !          2886:     {
        !          2887:         return false;
        !          2888:     }
        !          2889: 
        !          2890:     return (item->type & (cJSON_True | cJSON_False)) != 0;
        !          2891: }
        !          2892: CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
        !          2893: {
        !          2894:     if (item == NULL)
        !          2895:     {
        !          2896:         return false;
        !          2897:     }
        !          2898: 
        !          2899:     return (item->type & 0xFF) == cJSON_NULL;
        !          2900: }
        !          2901: 
        !          2902: CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
        !          2903: {
        !          2904:     if (item == NULL)
        !          2905:     {
        !          2906:         return false;
        !          2907:     }
        !          2908: 
        !          2909:     return (item->type & 0xFF) == cJSON_Number;
        !          2910: }
        !          2911: 
        !          2912: CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
        !          2913: {
        !          2914:     if (item == NULL)
        !          2915:     {
        !          2916:         return false;
        !          2917:     }
        !          2918: 
        !          2919:     return (item->type & 0xFF) == cJSON_String;
        !          2920: }
        !          2921: 
        !          2922: CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
        !          2923: {
        !          2924:     if (item == NULL)
        !          2925:     {
        !          2926:         return false;
        !          2927:     }
        !          2928: 
        !          2929:     return (item->type & 0xFF) == cJSON_Array;
        !          2930: }
        !          2931: 
        !          2932: CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
        !          2933: {
        !          2934:     if (item == NULL)
        !          2935:     {
        !          2936:         return false;
        !          2937:     }
        !          2938: 
        !          2939:     return (item->type & 0xFF) == cJSON_Object;
        !          2940: }
        !          2941: 
        !          2942: CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
        !          2943: {
        !          2944:     if (item == NULL)
        !          2945:     {
        !          2946:         return false;
        !          2947:     }
        !          2948: 
        !          2949:     return (item->type & 0xFF) == cJSON_Raw;
        !          2950: }
        !          2951: 
        !          2952: CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
        !          2953: {
        !          2954:     if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a))
        !          2955:     {
        !          2956:         return false;
        !          2957:     }
        !          2958: 
        !          2959:     /* check if type is valid */
        !          2960:     switch (a->type & 0xFF)
        !          2961:     {
        !          2962:         case cJSON_False:
        !          2963:         case cJSON_True:
        !          2964:         case cJSON_NULL:
        !          2965:         case cJSON_Number:
        !          2966:         case cJSON_String:
        !          2967:         case cJSON_Raw:
        !          2968:         case cJSON_Array:
        !          2969:         case cJSON_Object:
        !          2970:             break;
        !          2971: 
        !          2972:         default:
        !          2973:             return false;
        !          2974:     }
        !          2975: 
        !          2976:     /* identical objects are equal */
        !          2977:     if (a == b)
        !          2978:     {
        !          2979:         return true;
        !          2980:     }
        !          2981: 
        !          2982:     switch (a->type & 0xFF)
        !          2983:     {
        !          2984:         /* in these cases and equal type is enough */
        !          2985:         case cJSON_False:
        !          2986:         case cJSON_True:
        !          2987:         case cJSON_NULL:
        !          2988:             return true;
        !          2989: 
        !          2990:         case cJSON_Number:
        !          2991:             if (compare_double(a->valuedouble, b->valuedouble))
        !          2992:             {
        !          2993:                 return true;
        !          2994:             }
        !          2995:             return false;
        !          2996: 
        !          2997:         case cJSON_String:
        !          2998:         case cJSON_Raw:
        !          2999:             if ((a->valuestring == NULL) || (b->valuestring == NULL))
        !          3000:             {
        !          3001:                 return false;
        !          3002:             }
        !          3003:             if (strcmp(a->valuestring, b->valuestring) == 0)
        !          3004:             {
        !          3005:                 return true;
        !          3006:             }
        !          3007: 
        !          3008:             return false;
        !          3009: 
        !          3010:         case cJSON_Array:
        !          3011:         {
        !          3012:             cJSON *a_element = a->child;
        !          3013:             cJSON *b_element = b->child;
        !          3014: 
        !          3015:             for (; (a_element != NULL) && (b_element != NULL);)
        !          3016:             {
        !          3017:                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
        !          3018:                 {
        !          3019:                     return false;
        !          3020:                 }
        !          3021: 
        !          3022:                 a_element = a_element->next;
        !          3023:                 b_element = b_element->next;
        !          3024:             }
        !          3025: 
        !          3026:             /* one of the arrays is longer than the other */
        !          3027:             if (a_element != b_element) {
        !          3028:                 return false;
        !          3029:             }
        !          3030: 
        !          3031:             return true;
        !          3032:         }
        !          3033: 
        !          3034:         case cJSON_Object:
        !          3035:         {
        !          3036:             cJSON *a_element = NULL;
        !          3037:             cJSON *b_element = NULL;
        !          3038:             cJSON_ArrayForEach(a_element, a)
        !          3039:             {
        !          3040:                 /* TODO This has O(n^2) runtime, which is horrible! */
        !          3041:                 b_element = get_object_item(b, a_element->string, case_sensitive);
        !          3042:                 if (b_element == NULL)
        !          3043:                 {
        !          3044:                     return false;
        !          3045:                 }
        !          3046: 
        !          3047:                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
        !          3048:                 {
        !          3049:                     return false;
        !          3050:                 }
        !          3051:             }
        !          3052: 
        !          3053:             /* doing this twice, once on a and b to prevent true comparison if a subset of b
        !          3054:              * TODO: Do this the proper way, this is just a fix for now */
        !          3055:             cJSON_ArrayForEach(b_element, b)
        !          3056:             {
        !          3057:                 a_element = get_object_item(a, b_element->string, case_sensitive);
        !          3058:                 if (a_element == NULL)
        !          3059:                 {
        !          3060:                     return false;
        !          3061:                 }
        !          3062: 
        !          3063:                 if (!cJSON_Compare(b_element, a_element, case_sensitive))
        !          3064:                 {
        !          3065:                     return false;
        !          3066:                 }
        !          3067:             }
        !          3068: 
        !          3069:             return true;
        !          3070:         }
        !          3071: 
        !          3072:         default:
        !          3073:             return false;
        !          3074:     }
        !          3075: }
        !          3076: 
        !          3077: CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
        !          3078: {
        !          3079:     return global_hooks.allocate(size);
        !          3080: }
        !          3081: 
        !          3082: CJSON_PUBLIC(void) cJSON_free(void *object)
1.1       misho    3083: {
1.1.1.2 ! misho    3084:     global_hooks.deallocate(object);
1.1       misho    3085: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>