Diff for /embedaddon/iperf/src/cjson.c between versions 1.1 and 1.1.1.3

version 1.1, 2016/10/18 13:28:18 version 1.1.1.3, 2023/09/27 11:14:54
Line 1 Line 1
 /*  /*
  Copyright (c) 2009 Dave Gamble  Copyright (c) 2009-2017 Dave Gamble and cJSON contributors
   
   Permission is hereby granted, free of charge, to any person obtaining a copy    Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to deal    of this software and associated documentation files (the "Software"), to deal
Line 23 Line 23
 /* cJSON */  /* cJSON */
 /* JSON parser in C. */  /* JSON parser in C. */
   
   /* disable warnings about old C89 functions in MSVC */
   #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER)
   #define _CRT_SECURE_NO_DEPRECATE
   #endif
   
   #ifdef __GNUC__
   #pragma GCC visibility push(default)
   #endif
   #if defined(_MSC_VER)
   #pragma warning (push)
   /* disable warning about single line comments in system headers */
   #pragma warning (disable : 4001)
   #endif
   
   #include "iperf_config.h"
 #include <string.h>  #include <string.h>
 #include <stdio.h>  #include <stdio.h>
 #include <math.h>  #include <math.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <float.h>  
 #include <limits.h>  #include <limits.h>
 #include <ctype.h>  #include <ctype.h>
   #include <float.h>
 #ifdef HAVE_STDINT_H  #ifdef HAVE_STDINT_H
#include <stdint.h> #include <stdint.h>
 #endif  #endif
 #include <sys/types.h>  #include <sys/types.h>
   
   #ifdef ENABLE_LOCALES
   #include <locale.h>
   #endif
   
   #if defined(_MSC_VER)
   #pragma warning (pop)
   #endif
   #ifdef __GNUC__
   #pragma GCC visibility pop
   #endif
   
 #include "cjson.h"  #include "cjson.h"
   
   /* define our own boolean type */
   #ifdef true
   #undef true
   #endif
   #define true ((cJSON_bool)1)
   
   #ifdef false
   #undef false
   #endif
   #define false ((cJSON_bool)0)
   
   /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */
   #ifndef isinf
   #define isinf(d) (isnan((d - d)) && !isnan(d))
   #endif
   #ifndef isnan
   #define isnan(d) (d != d)
   #endif
   
   #ifndef NAN
   #ifdef _WIN32
   #define NAN sqrt(-1.0)
   #else
   #define NAN 0.0/0.0
   #endif
   #endif
   
   #if defined(HAVE_INTTYPES_H)
   # include <inttypes.h>
   #else
   # ifndef PRIu64
   #  if sizeof(long) == 8
   #   define PRIu64               "lu"
   #  else
   #   define PRIu64               "llu"
   #  endif
   # ifndef PRId64
   #  if sizeof(long) == 8
   #   define PRId64               "ld"
   #  else
   #   define PRId64               "lld"
   #  endif
   # endif
   # endif
   #endif
   
   typedef struct {
       const unsigned char *json;
       size_t position;
   } error;
   static error global_error = { NULL, 0 };
   
 #ifndef LLONG_MAX  #ifndef LLONG_MAX
 #define LLONG_MAX 9223372036854775807LL  #define LLONG_MAX 9223372036854775807LL
 #endif  #endif
 #ifndef LLONG_MIN  #ifndef LLONG_MIN
 #define LLONG_MIN (-LLONG_MAX - 1LL)  #define LLONG_MIN (-LLONG_MAX - 1LL)
 #endif  #endif
 static const char *global_ep;  
   
const char *cJSON_GetErrorPtr(void) {return global_ep;}CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void)
 {
     return (const char*) (global_error.json + global_error.position);
 }
   
static int cJSON_strcasecmp(const char *s1,const char *s2)CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item)
 {  {
        if (!s1) return (s1==s2)?0:1;if (!s2) return 1;    if (!cJSON_IsString(item))
        for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0)    return 0;    {
        return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);        return NULL;
     }
 
     return item->valuestring;
 }  }
   
static void *(*cJSON_malloc)(size_t sz) = malloc;CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item)
static void (*cJSON_free)(void *ptr) = free;{
     if (!cJSON_IsNumber(item))
     {
         return (double) NAN;    // cppcheck-suppress invalidFunctionArg
     }
   
static char* cJSON_strdup(const char* str)    return item->valuedouble;
 }
 
 /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */
 #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 15)
     #error cJSON.h and cJSON.c have different versions. Make sure that both have the same.
 #endif
 
 CJSON_PUBLIC(const char*) cJSON_Version(void)
 {  {
      size_t len;    static char version[15];
      char* copy;    sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH);
   
      len = strlen(str) + 1;    return version;
      if (!(copy = (char*)cJSON_malloc(len))) return 0; 
      memcpy(copy,str,len); 
      return copy; 
 }  }
   
void cJSON_InitHooks(cJSON_Hooks* hooks)/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */
 static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2)
 {  {
    if (!hooks) { /* Reset hooks */    if ((string1 == NULL) || (string2 == NULL))
        cJSON_malloc = malloc;    {
        cJSON_free = free;        return 1;
     }
 
     if (string1 == string2)
     {
         return 0;
     }
 
     for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++)
     {
         if (*string1 == '\0')
         {
             return 0;
         }
     }
 
     return tolower(*string1) - tolower(*string2);
 }
 
 typedef struct internal_hooks
 {
     void *(CJSON_CDECL *allocate)(size_t size);
     void (CJSON_CDECL *deallocate)(void *pointer);
     void *(CJSON_CDECL *reallocate)(void *pointer, size_t size);
 } internal_hooks;
 
 #if defined(_MSC_VER)
 /* work around MSVC error C2322: '...' address of dllimport '...' is not static */
 static void * CJSON_CDECL internal_malloc(size_t size)
 {
     return malloc(size);
 }
 static void CJSON_CDECL internal_free(void *pointer)
 {
     free(pointer);
 }
 static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
 {
     return realloc(pointer, size);
 }
 #else
 #define internal_malloc malloc
 #define internal_free free
 #define internal_realloc realloc
 #endif
 
 /* strlen of character literals resolved at compile time */
 #define static_strlen(string_literal) (sizeof(string_literal) - sizeof(""))
 
 static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc };
 
 static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks)
 {
     size_t length = 0;
     unsigned char *copy = NULL;
 
     if (string == NULL)
     {
         return NULL;
     }
 
     length = strlen((const char*)string) + sizeof("");
     copy = (unsigned char*)hooks->allocate(length);
     if (copy == NULL)
     {
         return NULL;
     }
     memcpy(copy, string, length);
 
     return copy;
 }
 
 CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks)
 {
     if (hooks == NULL)
     {
         /* Reset hooks */
         global_hooks.allocate = malloc;
         global_hooks.deallocate = free;
         global_hooks.reallocate = realloc;
         return;          return;
     }      }
   
        cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;    global_hooks.allocate = malloc;
        cJSON_free     = (hooks->free_fn)?hooks->free_fn:free;    if (hooks->malloc_fn != NULL)
     {
         global_hooks.allocate = hooks->malloc_fn;
     }
 
     global_hooks.deallocate = free;
     if (hooks->free_fn != NULL)
     {
         global_hooks.deallocate = hooks->free_fn;
     }
 
     /* use realloc only if both free and malloc are used */
     global_hooks.reallocate = NULL;
     if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free))
     {
         global_hooks.reallocate = realloc;
     }
 }  }
   
 /* Internal constructor. */  /* Internal constructor. */
static cJSON *cJSON_New_Item(void)static cJSON *cJSON_New_Item(const internal_hooks * const hooks)
 {  {
        cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));    cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON));
        if (node) memset(node,0,sizeof(cJSON));    if (node)
        return node;    {
         memset(node, '\0', sizeof(cJSON));
     }
 
     return node;
 }  }
   
 /* Delete a cJSON structure. */  /* Delete a cJSON structure. */
void cJSON_Delete(cJSON *c)CJSON_PUBLIC(void) cJSON_Delete(cJSON *item)
 {  {
        cJSON *next;    cJSON *next = NULL;
        while (c)    while (item != NULL)
        {    {
                next=c->next;        next = item->next;
                if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);        if (!(item->type & cJSON_IsReference) && (item->child != NULL))
                if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);        {
                if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);            cJSON_Delete(item->child);
                cJSON_free(c);        }
                c=next;        if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL))
        }        {
             global_hooks.deallocate(item->valuestring);
         }
         if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
         {
             global_hooks.deallocate(item->string);
         }
         global_hooks.deallocate(item);
         item = next;
     }
 }  }
   
   /* get the decimal point character of the current locale */
   static unsigned char get_decimal_point(void)
   {
   #ifdef ENABLE_LOCALES
       struct lconv *lconv = localeconv();
       return (unsigned char) lconv->decimal_point[0];
   #else
       return '.';
   #endif
   }
   
   typedef struct
   {
       const unsigned char *content;
       size_t length;
       size_t offset;
       size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */
       internal_hooks hooks;
   } parse_buffer;
   
   /* check if the given size is left to read in a given parse buffer (starting with 1) */
   #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length))
   /* check if the buffer can be accessed at the given index (starting with 0) */
   #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length))
   #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index))
   /* get a pointer to the buffer at the position */
   #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset)
   
 /* Parse the input text to generate a number, and populate the result into item. */  /* Parse the input text to generate a number, and populate the result into item. */
static const char *parse_number(cJSON *item,const char *num)static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer)
 {  {
        double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;    double number = 0;
     unsigned char *after_end = NULL;
     unsigned char number_c_string[64];
     unsigned char decimal_point = get_decimal_point();
     size_t i = 0;
   
        if (*num=='-') sign=-1,num++;       /* Has sign? */    if ((input_buffer == NULL) || (input_buffer->content == NULL))
        if (*num=='0') num++;                   /* is zero */    {
        if (*num>='1' && *num<='9')     do      n=(n*10.0)+(*num++ -'0');       while (*num>='0' && *num<='9'); /* Number? */        return false;
        if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;            do      n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}      /* Fractional part? */    }
        if (*num=='e' || *num=='E')              /* Exponent? */ 
        {       num++;if (*num=='+') num++;     else if (*num=='-') signsubscale=-1,num++;              /* With sign? */ 
                while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');   /* Number? */ 
        } 
   
        n=sign*n*pow(10.0,(scale+subscale*signsubscale));       /* number = +/- number.fraction * 10^+/- exponent */    /* copy the number into a temporary buffer and replace '.' with the decimal point
             * of the current locale (for strtod)
        item->valuedouble=n;     * This also takes care of '\0' not necessarily being available for marking the end of the input */
        item->valueint=(int64_t)n;    for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++)
        item->type=cJSON_Number;    {
        return num;        switch (buffer_at_offset(input_buffer)[i])
         {
             case '0':
             case '1':
             case '2':
             case '3':
             case '4':
             case '5':
             case '6':
             case '7':
             case '8':
             case '9':
             case '+':
             case '-':
             case 'e':
             case 'E':
                 number_c_string[i] = buffer_at_offset(input_buffer)[i];
                 break;
 
             case '.':
                 number_c_string[i] = decimal_point;
                 break;
 
             default:
                 goto loop_end;
         }
     }
 loop_end:
     number_c_string[i] = '\0';
 
     number = strtod((const char*)number_c_string, (char**)&after_end);
     if (number_c_string == after_end)
     {
         return false; /* parse_error */
     }
 
     item->valuedouble = number;
 
     /* use saturation in case of overflow */
     if (number >= LLONG_MAX)
     {
         item->valueint = LLONG_MAX;
     }
     else if (number <= (double)LLONG_MIN)
     {
         item->valueint = LLONG_MIN;
     }
     else
     {
         item->valueint = (int64_t)number;
     }
 
     item->type = cJSON_Number;
 
     input_buffer->offset += (size_t)(after_end - number_c_string);
     return true;
 }  }
   
static int pow2gt (int x)       {       --x;    x|=x>>1;        x|=x>>2;        x|=x>>4;        x|=x>>8;        x|=x>>16;        return x+1;    }/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */
 CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number)
 {
     if (number >= LLONG_MAX)
     {
         object->valueint = LLONG_MAX;
     }
     else if (number <= (double)LLONG_MIN)
     {
         object->valueint = LLONG_MIN;
     }
     else
     {
         object->valueint = (int64_t)number;
     }
   
typedef struct {char *buffer; int length; int offset; } printbuffer;    return object->valuedouble = number;
 }
   
static char* ensure(printbuffer *p,int needed)CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring)
 {  {
        char *newbuffer;int newsize;    char *copy = NULL;
        if (!p || !p->buffer) return 0;    /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */
        needed+=p->offset;    if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference))
        if (needed<=p->length) return p->buffer+p->offset;    {
         return NULL;
     }
     if (strlen(valuestring) <= strlen(object->valuestring))
     {
         strcpy(object->valuestring, valuestring);
         return object->valuestring;
     }
     copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks);
     if (copy == NULL)
     {
         return NULL;
     }
     if (object->valuestring != NULL)
     {
         cJSON_free(object->valuestring);
     }
     object->valuestring = copy;
   
        newsize=pow2gt(needed);    return copy;
        newbuffer=(char*)cJSON_malloc(newsize); 
        if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} 
        if (newbuffer) memcpy(newbuffer,p->buffer,p->length); 
        cJSON_free(p->buffer); 
        p->length=newsize; 
        p->buffer=newbuffer; 
        return newbuffer+p->offset; 
 }  }
   
static int update(printbuffer *p)typedef struct
 {  {
        char *str;    unsigned char *buffer;
        if (!p || !p->buffer) return 0;    size_t length;
        str=p->buffer+p->offset;    size_t offset;
        return p->offset+strlen(str);    size_t depth; /* current nesting depth (for formatted printing) */
     cJSON_bool noalloc;
     cJSON_bool format; /* is this print a formatted print */
     internal_hooks hooks;
 } printbuffer;
 
 /* realloc printbuffer if necessary to have at least "needed" bytes more */
 static unsigned char* ensure(printbuffer * const p, size_t needed)
 {
     unsigned char *newbuffer = NULL;
     size_t newsize = 0;
 
     if ((p == NULL) || (p->buffer == NULL))
     {
         return NULL;
     }
 
     if ((p->length > 0) && (p->offset >= p->length))
     {
         /* make sure that offset is valid */
         return NULL;
     }
 
     if (needed > SIZE_MAX)
     {
         /* sizes bigger than SIZE_MAX are currently not supported */
         return NULL;
     }
 
     needed += p->offset + 1;
     if (needed <= p->length)
     {
         return p->buffer + p->offset;
     }
 
     if (p->noalloc) {
         return NULL;
     }
 
     /* calculate new buffer size */
     if (needed > (SIZE_MAX / 2))
     {
         /* overflow of int, use SIZE_MAX if possible */
         if (needed <= SIZE_MAX)
         {
             newsize = SIZE_MAX;
         }
         else
         {
             return NULL;
         }
     }
     else
     {
         newsize = needed * 2;
     }
 
     if (p->hooks.reallocate != NULL)
     {
         /* reallocate with realloc if available */
         newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize);
         if (newbuffer == NULL)
         {
             p->hooks.deallocate(p->buffer);
             p->length = 0;
             p->buffer = NULL;
 
             return NULL;
         }
     }
     else
     {
         /* otherwise reallocate manually */
         newbuffer = (unsigned char*)p->hooks.allocate(newsize);
         if (!newbuffer)
         {
             p->hooks.deallocate(p->buffer);
             p->length = 0;
             p->buffer = NULL;
 
             return NULL;
         }
 
         memcpy(newbuffer, p->buffer, p->offset + 1);
         p->hooks.deallocate(p->buffer);
     }
     p->length = newsize;
     p->buffer = newbuffer;
 
     return newbuffer + p->offset;
 }  }
   
   /* calculate the new length of the string in a printbuffer and update the offset */
   static void update_offset(printbuffer * const buffer)
   {
       const unsigned char *buffer_pointer = NULL;
       if ((buffer == NULL) || (buffer->buffer == NULL))
       {
           return;
       }
       buffer_pointer = buffer->buffer + buffer->offset;
   
       buffer->offset += strlen((const char*)buffer_pointer);
   }
   
   /* securely comparison of floating-point variables */
   static cJSON_bool compare_double(double a, double b)
   {
       double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b);
       return (fabs(a - b) <= maxVal * DBL_EPSILON);
   }
   
 /* Render the number nicely from the given item into a string. */  /* Render the number nicely from the given item into a string. */
static char *print_number(cJSON *item,printbuffer *p)static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer)
 {  {
        char *str=0;    unsigned char *output_pointer = NULL;
        double d=item->valuedouble;    double d = item->valuedouble;
        if (d==0)    int length = 0;
        {    size_t i = 0;
                if (p)      str=ensure(p,2);    unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */
                else    str=(char*)cJSON_malloc(2);     /* special case for 0. */    unsigned char decimal_point = get_decimal_point();
                if (str) strcpy(str,"0");    double test = 0.0;
        }
        else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=LLONG_MAX && d>=LLONG_MIN)    if (output_buffer == NULL)
        {    {
                if (p)  str=ensure(p,64);        return false;
                else    str=(char*)cJSON_malloc(64);    }
                if (str)        sprintf(str,"%lld",(long long) item->valueint);
        }    /* This checks for NaN and Infinity */
        else    if (isnan(d) || isinf(d))
        {    {
                if (p)  str=ensure(p,64);        length = sprintf((char*)number_buffer, "null");
                else    str=(char*)cJSON_malloc(64);        /* This is a nice tradeoff. */    }
                if (str)    else if(d == (double)item->valueint)
                {    {
                        if (fpclassify(d) != FP_ZERO && !isnormal(d))                                sprintf(str,"null");        length = sprintf((char*)number_buffer, "%" PRId64, item->valueint);
                        else if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)        sprintf(str,"%.0f",d);    }
                        else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)                                        sprintf(str,"%e",d);    else
                        else                                                                                                            sprintf(str,"%f",d);    {
                }        /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */
        }        length = sprintf((char*)number_buffer, "%1.15g", d);
        return str;
         /* Check whether the original double can be recovered */
         if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d))
         {
             /* If not, print with 17 decimal places of precision */
             length = sprintf((char*)number_buffer, "%1.17g", d);
         }
     }
 
     /* sprintf failed or buffer overrun occurred */
     if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1)))
     {
         return false;
     }
 
     /* reserve appropriate space in the output */
     output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));
     if (output_pointer == NULL)
     {
         return false;
     }
 
     /* copy the printed number to the output and replace locale
      * dependent decimal point with '.' */
     for (i = 0; i < ((size_t)length); i++)
     {
         if (number_buffer[i] == decimal_point)
         {
             output_pointer[i] = '.';
             continue;
         }
 
         output_pointer[i] = number_buffer[i];
     }
     output_pointer[i] = '\0';
 
     output_buffer->offset += (size_t)length;
 
     return true;
 }  }
   
static unsigned parse_hex4(const char *str)/* parse 4 digit hexadecimal number */
 static unsigned parse_hex4(const unsigned char * const input)
 {  {
        unsigned h=0;    unsigned int h = 0;
        if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;    size_t i = 0;
        h=h<<4;str++;
        if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;    for (i = 0; i < 4; i++)
        h=h<<4;str++;    {
        if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;        /* parse digit */
        h=h<<4;str++;        if ((input[i] >= '0') && (input[i] <= '9'))
        if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;        {
        return h;            h += (unsigned int) input[i] - '0';
         }
         else if ((input[i] >= 'A') && (input[i] <= 'F'))
         {
             h += (unsigned int) 10 + input[i] - 'A';
         }
         else if ((input[i] >= 'a') && (input[i] <= 'f'))
         {
             h += (unsigned int) 10 + input[i] - 'a';
         }
         else /* invalid */
         {
             return 0;
         }
 
         if (i < 3)
         {
             /* shift left to make place for the next nibble */
             h = h << 4;
         }
     }
 
     return h;
 }  }
   
/* Parse the input text into an unescaped cstring, and populate item. *//* converts a UTF-16 literal to UTF-8
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; * A literal can be one or two sequences of the form \uXXXX */
static const char *parse_string(cJSON *item,const char *str,const char **ep)static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer)
 {  {
        const char *ptr=str+1,*end_ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;    long unsigned int codepoint = 0;
        if (*str!='\"') {*ep=str;return 0;}     /* not a string! */    unsigned int first_code = 0;
            const unsigned char *first_sequence = input_pointer;
        while (*end_ptr!='\"' && *end_ptr && ++len) if (*end_ptr++ == '\\') end_ptr++;  /* Skip escaped quotes. */    unsigned char utf8_length = 0;
            unsigned char utf8_position = 0;
        out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */    unsigned char sequence_length = 0;
        if (!out) return 0;    unsigned char first_byte_mark = 0;
        item->valuestring=out; /* assign here so out will be deleted during cJSON_Delete() later */ 
        item->type=cJSON_String; 
         
        ptr=str+1;ptr2=out; 
        while (ptr < end_ptr) 
        { 
                if (*ptr!='\\') *ptr2++=*ptr++; 
                else 
                { 
                        ptr++; 
                        switch (*ptr) 
                        { 
                                case 'b': *ptr2++='\b'; break; 
                                case 'f': *ptr2++='\f'; break; 
                                case 'n': *ptr2++='\n'; break; 
                                case 'r': *ptr2++='\r'; break; 
                                case 't': *ptr2++='\t'; break; 
                                case 'u':        /* transcode utf16 to utf8. */ 
                                        uc=parse_hex4(ptr+1);ptr+=4;    /* get the unicode char. */ 
                                        if (ptr >= end_ptr) {*ep=str;return 0;} /* invalid */ 
                                         
                                        if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)    {*ep=str;return 0;} /* check for invalid.   */ 
                                         
                                        if (uc>=0xD800 && uc<=0xDBFF)   /* UTF16 surrogate pairs.       */ 
                                        { 
                                                if (ptr+6 > end_ptr)    {*ep=str;return 0;}     /* invalid */ 
                                                if (ptr[1]!='\\' || ptr[2]!='u')    {*ep=str;return 0;} /* missing second-half of surrogate.    */ 
                                                uc2=parse_hex4(ptr+3);ptr+=6; 
                                                if (uc2<0xDC00 || uc2>0xDFFF)       {*ep=str;return 0;} /* invalid second-half of surrogate.    */ 
                                                uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 
                                        } 
   
                                        len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;    if ((input_end - first_sequence) < 6)
                                            {
                                        switch (len) {        /* input ends unexpectedly */
                                                case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;        goto fail;
                                                case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;    }
                                                case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
                                                case 1: *--ptr2 =(uc | firstByteMark[len]);    /* get the first utf16 sequence */
                                        }    first_code = parse_hex4(first_sequence + 2);
                                        ptr2+=len;
                                        break;    /* check that the code is valid */
                                default:  *ptr2++=*ptr; break;    if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)))
                        }    {
                        ptr++;        goto fail;
                }    }
        }
        *ptr2=0;    /* UTF16 surrogate pair */
        if (*ptr=='\"') ptr++;    if ((first_code >= 0xD800) && (first_code <= 0xDBFF))
        return ptr;    {
         const unsigned char *second_sequence = first_sequence + 6;
         unsigned int second_code = 0;
         sequence_length = 12; /* \uXXXX\uXXXX */
 
         if ((input_end - second_sequence) < 6)
         {
             /* input ends unexpectedly */
             goto fail;
         }
 
         if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u'))
         {
             /* missing second half of the surrogate pair */
             goto fail;
         }
 
         /* get the second utf16 sequence */
         second_code = parse_hex4(second_sequence + 2);
         /* check that the code is valid */
         if ((second_code < 0xDC00) || (second_code > 0xDFFF))
         {
             /* invalid second half of the surrogate pair */
             goto fail;
         }
 
 
         /* calculate the unicode codepoint from the surrogate pair */
         codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF));
     }
     else
     {
         sequence_length = 6; /* \uXXXX */
         codepoint = first_code;
     }
 
     /* encode as UTF-8
      * takes at maximum 4 bytes to encode:
      * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
     if (codepoint < 0x80)
     {
         /* normal ascii, encoding 0xxxxxxx */
         utf8_length = 1;
     }
     else if (codepoint < 0x800)
     {
         /* two bytes, encoding 110xxxxx 10xxxxxx */
         utf8_length = 2;
         first_byte_mark = 0xC0; /* 11000000 */
     }
     else if (codepoint < 0x10000)
     {
         /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
         utf8_length = 3;
         first_byte_mark = 0xE0; /* 11100000 */
     }
     else if (codepoint <= 0x10FFFF)
     {
         /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */
         utf8_length = 4;
         first_byte_mark = 0xF0; /* 11110000 */
     }
     else
     {
         /* invalid unicode codepoint */
         goto fail;
     }
 
     /* encode as utf8 */
     for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--)
     {
         /* 10xxxxxx */
         (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF);
         codepoint >>= 6;
     }
     /* encode first byte */
     if (utf8_length > 1)
     {
         (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF);
     }
     else
     {
         (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F);
     }
 
     *output_pointer += utf8_length;
 
     return sequence_length;
 
 fail:
     return 0;
 }  }
   
   /* Parse the input text into an unescaped cinput, and populate item. */
   static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer)
   {
       const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1;
       const unsigned char *input_end = buffer_at_offset(input_buffer) + 1;
       unsigned char *output_pointer = NULL;
       unsigned char *output = NULL;
   
       /* not a string */
       if (buffer_at_offset(input_buffer)[0] != '\"')
       {
           goto fail;
       }
   
       {
           /* calculate approximate size of the output (overestimate) */
           size_t allocation_length = 0;
           size_t skipped_bytes = 0;
           while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"'))
           {
               /* is escape sequence */
               if (input_end[0] == '\\')
               {
                   if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length)
                   {
                       /* prevent buffer overflow when last input character is a backslash */
                       goto fail;
                   }
                   skipped_bytes++;
                   input_end++;
               }
               input_end++;
           }
           if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"'))
           {
               goto fail; /* string ended unexpectedly */
           }
   
           /* This is at most how much we need for the output */
           allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes;
           output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof(""));
           if (output == NULL)
           {
               goto fail; /* allocation failure */
           }
       }
   
       output_pointer = output;
       /* loop through the string literal */
       while (input_pointer < input_end)
       {
           if (*input_pointer != '\\')
           {
               *output_pointer++ = *input_pointer++;
           }
           /* escape sequence */
           else
           {
               unsigned char sequence_length = 2;
               if ((input_end - input_pointer) < 1)
               {
                   goto fail;
               }
   
               switch (input_pointer[1])
               {
                   case 'b':
                       *output_pointer++ = '\b';
                       break;
                   case 'f':
                       *output_pointer++ = '\f';
                       break;
                   case 'n':
                       *output_pointer++ = '\n';
                       break;
                   case 'r':
                       *output_pointer++ = '\r';
                       break;
                   case 't':
                       *output_pointer++ = '\t';
                       break;
                   case '\"':
                   case '\\':
                   case '/':
                       *output_pointer++ = input_pointer[1];
                       break;
   
                   /* UTF-16 literal */
                   case 'u':
                       sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer);
                       if (sequence_length == 0)
                       {
                           /* failed to convert UTF16-literal to UTF-8 */
                           goto fail;
                       }
                       break;
   
                   default:
                       goto fail;
               }
               input_pointer += sequence_length;
           }
       }
   
       /* zero terminate the output */
       *output_pointer = '\0';
   
       item->type = cJSON_String;
       item->valuestring = (char*)output;
   
       input_buffer->offset = (size_t) (input_end - input_buffer->content);
       input_buffer->offset++;
   
       return true;
   
   fail:
       if (output != NULL)
       {
           input_buffer->hooks.deallocate(output);
       }
   
       if (input_pointer != NULL)
       {
           input_buffer->offset = (size_t)(input_pointer - input_buffer->content);
       }
   
       return false;
   }
   
 /* Render the cstring provided to an escaped version that can be printed. */  /* Render the cstring provided to an escaped version that can be printed. */
static char *print_string_ptr(const char *str,printbuffer *p)static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer)
 {  {
        const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;    const unsigned char *input_pointer = NULL;
     unsigned char *output = NULL;
     unsigned char *output_pointer = NULL;
     size_t output_length = 0;
     /* numbers of additional characters needed for escaping */
     size_t escape_characters = 0;
   
        if (!str)    if (output_buffer == NULL)
        {    {
                if (p)      out=ensure(p,3);        return false;
                else    out=(char*)cJSON_malloc(3);    }
                if (!out) return 0; 
                strcpy(out,"\"\""); 
                return out; 
        } 
         
        for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; 
        if (!flag) 
        { 
                len=ptr-str; 
                if (p) out=ensure(p,len+3); 
                else            out=(char*)cJSON_malloc(len+3); 
                if (!out) return 0; 
                ptr2=out;*ptr2++='\"'; 
                strcpy(ptr2,str); 
                ptr2[len]='\"'; 
                ptr2[len+1]=0; 
                return out; 
        } 
         
        ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 
         
        if (p)  out=ensure(p,len+3); 
        else    out=(char*)cJSON_malloc(len+3); 
        if (!out) return 0; 
   
        ptr2=out;ptr=str;    /* empty string */
        *ptr2++='\"';    if (input == NULL)
        while (*ptr)    {
        {        output = ensure(output_buffer, sizeof("\"\""));
                if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;        if (output == NULL)
                else        {
                {            return false;
                        *ptr2++='\\';        }
                        switch (token=*ptr++)        strcpy((char*)output, "\"\"");
                        {
                                case '\\':      *ptr2++='\\';   break;        return true;
                                case '\"':      *ptr2++='\"';   break;    }
                                case '\b':      *ptr2++='b';    break;
                                case '\f':      *ptr2++='f';    break;    /* set "flag" to 1 if something needs to be escaped */
                                case '\n':      *ptr2++='n';    break;    for (input_pointer = input; *input_pointer; input_pointer++)
                                case '\r':      *ptr2++='r';    break;    {
                                case '\t':      *ptr2++='t';    break;        switch (*input_pointer)
                                default: sprintf(ptr2,"u%04x",token);ptr2+=5;    break;        /* escape and print */        {
                        }            case '\"':
                }            case '\\':
        }            case '\b':
        *ptr2++='\"';*ptr2++=0;            case '\f':
        return out;            case '\n':
             case '\r':
             case '\t':
                 /* one character escape sequence */
                 escape_characters++;
                 break;
             default:
                 if (*input_pointer < 32)
                 {
                     /* UTF-16 escape sequence uXXXX */
                     escape_characters += 5;
                 }
                 break;
         }
     }
     output_length = (size_t)(input_pointer - input) + escape_characters;
 
     output = ensure(output_buffer, output_length + sizeof("\"\""));
     if (output == NULL)
     {
         return false;
     }
 
     /* no characters have to be escaped */
     if (escape_characters == 0)
     {
         output[0] = '\"';
         memcpy(output + 1, input, output_length);
         output[output_length + 1] = '\"';
         output[output_length + 2] = '\0';
 
         return true;
     }
 
     output[0] = '\"';
     output_pointer = output + 1;
     /* copy the string */
     for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++)
     {
         if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\'))
         {
             /* normal character, copy */
             *output_pointer = *input_pointer;
         }
         else
         {
             /* character needs to be escaped */
             *output_pointer++ = '\\';
             switch (*input_pointer)
             {
                 case '\\':
                     *output_pointer = '\\';
                     break;
                 case '\"':
                     *output_pointer = '\"';
                     break;
                 case '\b':
                     *output_pointer = 'b';
                     break;
                 case '\f':
                     *output_pointer = 'f';
                     break;
                 case '\n':
                     *output_pointer = 'n';
                     break;
                 case '\r':
                     *output_pointer = 'r';
                     break;
                 case '\t':
                     *output_pointer = 't';
                     break;
                 default:
                     /* escape and print as unicode codepoint */
                     sprintf((char*)output_pointer, "u%04x", *input_pointer);
                     output_pointer += 4;
                     break;
             }
         }
     }
     output[output_length + 1] = '\"';
     output[output_length + 2] = '\0';
 
     return true;
 }  }
 /* Invote print_string_ptr (which is useful) on an item. */  
 static char *print_string(cJSON *item,printbuffer *p)   {return print_string_ptr(item->valuestring,p);}  
   
   /* Invoke print_string_ptr (which is useful) on an item. */
   static cJSON_bool print_string(const cJSON * const item, printbuffer * const p)
   {
       return print_string_ptr((unsigned char*)item->valuestring, p);
   }
   
 /* Predeclare these prototypes. */  /* Predeclare these prototypes. */
static const char *parse_value(cJSON *item,const char *value,const char **ep);static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer);
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer);
static const char *parse_array(cJSON *item,const char *value,const char **ep);static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer);
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer);
static const char *parse_object(cJSON *item,const char *value,const char **ep);static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer);
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer);
   
 /* Utility to jump whitespace and cr/lf */  /* Utility to jump whitespace and cr/lf */
static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer)
 {
     if ((buffer == NULL) || (buffer->content == NULL))
     {
         return NULL;
     }
   
       if (cannot_access_at_index(buffer, 0))
       {
           return buffer;
       }
   
       while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32))
       {
          buffer->offset++;
       }
   
       if (buffer->offset == buffer->length)
       {
           buffer->offset--;
       }
   
       return buffer;
   }
   
   /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */
   static parse_buffer *skip_utf8_bom(parse_buffer * const buffer)
   {
       if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0))
       {
           return NULL;
       }
   
       if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0))
       {
           buffer->offset += 3;
       }
   
       return buffer;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
   {
       size_t buffer_length;
   
       if (NULL == value)
       {
           return NULL;
       }
   
       /* Adding null character size due to require_null_terminated. */
       buffer_length = strlen(value) + sizeof("");
   
       return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated);
   }
   
 /* Parse an object - create a new root, and populate. */  /* Parse an object - create a new root, and populate. */
cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated)
 {  {
        const char *end=0,**ep=return_parse_end?return_parse_end:&global_ep;    parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } };
        cJSON *c=cJSON_New_Item();    cJSON *item = NULL;
        *ep=0; 
        if (!c) return 0;       /* memory fail */ 
   
        end=parse_value(c,skip(value),ep);    /* reset error position */
        if (!end)       {cJSON_Delete(c);return 0;}     /* parse failure. ep is set. */    global_error.json = NULL;
     global_error.position = 0;
   
        /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */    if (value == NULL || 0 == buffer_length)
        if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);*ep=end;return 0;}}    {
        if (return_parse_end) *return_parse_end=end;        goto fail;
        return c;    }
 
     buffer.content = (const unsigned char*)value;
     buffer.length = buffer_length;
     buffer.offset = 0;
     buffer.hooks = global_hooks;
 
     item = cJSON_New_Item(&global_hooks);
     if (item == NULL) /* memory fail */
     {
         goto fail;
     }
 
     if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer))))
     {
         /* parse failure. ep is set. */
         goto fail;
     }
 
     /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
     if (require_null_terminated)
     {
         buffer_skip_whitespace(&buffer);
         if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0')
         {
             goto fail;
         }
     }
     if (return_parse_end)
     {
         *return_parse_end = (const char*)buffer_at_offset(&buffer);
     }
 
     return item;
 
 fail:
     if (item != NULL)
     {
         cJSON_Delete(item);
     }
 
     if (value != NULL)
     {
         error local_error;
         local_error.json = (const unsigned char*)value;
         local_error.position = 0;
 
         if (buffer.offset < buffer.length)
         {
             local_error.position = buffer.offset;
         }
         else if (buffer.length > 0)
         {
             local_error.position = buffer.length - 1;
         }
 
         if (return_parse_end != NULL)
         {
             *return_parse_end = (const char*)local_error.json + local_error.position;
         }
 
         global_error = local_error;
     }
 
     return NULL;
 }  }
   
 /* Default options for cJSON_Parse */  /* Default options for cJSON_Parse */
cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value)
 {
     return cJSON_ParseWithOpts(value, 0, 0);
 }
   
   CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length)
   {
       return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0);
   }
   
   #define cjson_min(a, b) (((a) < (b)) ? (a) : (b))
   
   static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks)
   {
       static const size_t default_buffer_size = 256;
       printbuffer buffer[1];
       unsigned char *printed = NULL;
   
       memset(buffer, 0, sizeof(buffer));
   
       /* create buffer */
       buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size);
       buffer->length = default_buffer_size;
       buffer->format = format;
       buffer->hooks = *hooks;
       if (buffer->buffer == NULL)
       {
           goto fail;
       }
   
       /* print the value */
       if (!print_value(item, buffer))
       {
           goto fail;
       }
       update_offset(buffer);
   
       /* check if reallocate is available */
       if (hooks->reallocate != NULL)
       {
           printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1);
           if (printed == NULL) {
               goto fail;
           }
           buffer->buffer = NULL;
       }
       else /* otherwise copy the JSON over to a new buffer */
       {
           printed = (unsigned char*) hooks->allocate(buffer->offset + 1);
           if (printed == NULL)
           {
               goto fail;
           }
           memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));
           printed[buffer->offset] = '\0'; /* just to be sure */
   
           /* free the buffer */
           hooks->deallocate(buffer->buffer);
       }
   
       return printed;
   
   fail:
       if (buffer->buffer != NULL)
       {
           hooks->deallocate(buffer->buffer);
       }
   
       if (printed != NULL)
       {
           hooks->deallocate(printed);
       }
   
       return NULL;
   }
   
 /* Render a cJSON item/entity/structure to text. */  /* Render a cJSON item/entity/structure to text. */
char *cJSON_Print(cJSON *item)                             {return print_value(item,0,1,0);}CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item)
char *cJSON_PrintUnformatted(cJSON *item)    {return print_value(item,0,0,0);}{
     return (char*)print(item, true, &global_hooks);
 }
   
char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item)
 {  {
        printbuffer p;    return (char*)print(item, false, &global_hooks);
        p.buffer=(char*)cJSON_malloc(prebuffer); 
        p.length=prebuffer; 
        p.offset=0; 
        return print_value(item,0,fmt,&p); 
 }  }
   
   CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)
   {
       printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
   
       if (prebuffer < 0)
       {
           return NULL;
       }
   
       p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer);
       if (!p.buffer)
       {
           return NULL;
       }
   
       p.length = (size_t)prebuffer;
       p.offset = 0;
       p.noalloc = false;
       p.format = fmt;
       p.hooks = global_hooks;
   
       if (!print_value(item, &p))
       {
           global_hooks.deallocate(p.buffer);
           return NULL;
       }
   
       return (char*)p.buffer;
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)
   {
       printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } };
   
       if ((length < 0) || (buffer == NULL))
       {
           return false;
       }
   
       p.buffer = (unsigned char*)buffer;
       p.length = (size_t)length;
       p.offset = 0;
       p.noalloc = true;
       p.format = format;
       p.hooks = global_hooks;
   
       return print_value(item, &p);
   }
   
 /* Parser core - when encountering text, process appropriately. */  /* Parser core - when encountering text, process appropriately. */
static const char *parse_value(cJSON *item,const char *value,const char **ep)static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer)
 {  {
        if (!value)                                                return 0;      /* Fail on null. */    if ((input_buffer == NULL) || (input_buffer->content == NULL))
        if (!strncmp(value,"null",4))   { item->type=cJSON_NULL;  return value+4; }    {
        if (!strncmp(value,"false",5))  { item->type=cJSON_False; return value+5; }        return false; /* no input */
        if (!strncmp(value,"true",4))   { item->type=cJSON_True; item->valueint=1;      return value+4; }    }
        if (*value=='\"')                               { return parse_string(item,value,ep); } 
        if (*value=='-' || (*value>='0' && *value<='9'))        { return parse_number(item,value); } 
        if (*value=='[')                                { return parse_array(item,value,ep); } 
        if (*value=='{')                                { return parse_object(item,value,ep); } 
   
        *ep=value;return 0;        /* failure. */    /* parse the different types of values */
     /* null */
     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0))
     {
         item->type = cJSON_NULL;
         input_buffer->offset += 4;
         return true;
     }
     /* false */
     if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0))
     {
         item->type = cJSON_False;
         input_buffer->offset += 5;
         return true;
     }
     /* true */
     if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0))
     {
         item->type = cJSON_True;
         item->valueint = 1;
         input_buffer->offset += 4;
         return true;
     }
     /* string */
     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"'))
     {
         return parse_string(item, input_buffer);
     }
     /* number */
     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'))))
     {
         return parse_number(item, input_buffer);
     }
     /* array */
     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '['))
     {
         return parse_array(item, input_buffer);
     }
     /* object */
     if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{'))
     {
         return parse_object(item, input_buffer);
     }
 
     return false;
 }  }
   
 /* Render a value to text. */  /* Render a value to text. */
static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer)
 {  {
        char *out=0;    unsigned char *output = NULL;
        if (!item) return 0;
        if (p)    if ((item == NULL) || (output_buffer == NULL))
        {    {
                switch ((item->type)&255)        return false;
                {    }
                        case cJSON_NULL:        {out=ensure(p,5);        if (out) strcpy(out,"null");        break;}
                        case cJSON_False:       {out=ensure(p,6);        if (out) strcpy(out,"false");       break;}    switch ((item->type) & 0xFF)
                        case cJSON_True:        {out=ensure(p,5);        if (out) strcpy(out,"true");        break;}    {
                        case cJSON_Number:      out=print_number(item,p);break;        case cJSON_NULL:
                        case cJSON_String:      out=print_string(item,p);break;            output = ensure(output_buffer, 5);
                        case cJSON_Array:       out=print_array(item,depth,fmt,p);break;            if (output == NULL)
                        case cJSON_Object:      out=print_object(item,depth,fmt,p);break;            {
                }                return false;
        }            }
        else            strcpy((char*)output, "null");
        {            return true;
                switch ((item->type)&255)
                {        case cJSON_False:
                        case cJSON_NULL:        out=cJSON_strdup("null");       break;            output = ensure(output_buffer, 6);
                        case cJSON_False:       out=cJSON_strdup("false");break;            if (output == NULL)
                        case cJSON_True:        out=cJSON_strdup("true"); break;            {
                        case cJSON_Number:      out=print_number(item,0);break;                return false;
                        case cJSON_String:      out=print_string(item,0);break;            }
                        case cJSON_Array:       out=print_array(item,depth,fmt,0);break;            strcpy((char*)output, "false");
                        case cJSON_Object:      out=print_object(item,depth,fmt,0);break;            return true;
                }
        }        case cJSON_True:
        return out;            output = ensure(output_buffer, 5);
             if (output == NULL)
             {
                 return false;
             }
             strcpy((char*)output, "true");
             return true;
 
         case cJSON_Number:
             return print_number(item, output_buffer);
 
         case cJSON_Raw:
         {
             size_t raw_length = 0;
             if (item->valuestring == NULL)
             {
                 return false;
             }
 
             raw_length = strlen(item->valuestring) + sizeof("");
             output = ensure(output_buffer, raw_length);
             if (output == NULL)
             {
                 return false;
             }
             memcpy(output, item->valuestring, raw_length);
             return true;
         }
 
         case cJSON_String:
             return print_string(item, output_buffer);
 
         case cJSON_Array:
             return print_array(item, output_buffer);
 
         case cJSON_Object:
             return print_object(item, output_buffer);
 
         default:
             return false;
     }
 }  }
   
 /* Build an array from input text. */  /* Build an array from input text. */
static const char *parse_array(cJSON *item,const char *value,const char **ep)static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer)
 {  {
        cJSON *child;    cJSON *head = NULL; /* head of the linked list */
        if (*value!='[')        {*ep=value;return 0;}   /* not an array! */    cJSON *current_item = NULL;
   
        item->type=cJSON_Array;    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
        value=skip(value+1);    {
        if (*value==']') return value+1;        /* empty array. */        return false; /* to deeply nested */
     }
     input_buffer->depth++;
   
        item->child=child=cJSON_New_Item();    if (buffer_at_offset(input_buffer)[0] != '[')
        if (!item->child) return 0;          /* memory fail */    {
        value=skip(parse_value(child,skip(value),ep));  /* skip any spacing, get the value. */        /* not an array */
        if (!value) return 0;        goto fail;
     }
   
        while (*value==',')    input_buffer->offset++;
        {    buffer_skip_whitespace(input_buffer);
                cJSON *new_item;    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']'))
                if (!(new_item=cJSON_New_Item())) return 0;     /* memory fail */    {
                child->next=new_item;new_item->prev=child;child=new_item;        /* empty array */
                value=skip(parse_value(child,skip(value+1),ep));        goto success;
                if (!value) return 0;       /* memory fail */    }
        } 
   
        if (*value==']') return value+1;     /* end of array */    /* check if we skipped to the end of the buffer */
        *ep=value;return 0;      /* malformed. */    if (cannot_access_at_index(input_buffer, 0))
     {
         input_buffer->offset--;
         goto fail;
     }
 
     /* step back to character in front of the first element */
     input_buffer->offset--;
     /* loop through the comma separated array elements */
     do
     {
         /* allocate next item */
         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
         if (new_item == NULL)
         {
             goto fail; /* allocation failure */
         }
 
         /* attach next item to list */
         if (head == NULL)
         {
             /* start the linked list */
             current_item = head = new_item;
         }
         else
         {
             /* add to the end and advance */
             current_item->next = new_item;
             new_item->prev = current_item;
             current_item = new_item;
         }
 
         /* parse next value */
         input_buffer->offset++;
         buffer_skip_whitespace(input_buffer);
         if (!parse_value(current_item, input_buffer))
         {
             goto fail; /* failed to parse value */
         }
         buffer_skip_whitespace(input_buffer);
     }
     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
 
     if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']')
     {
         goto fail; /* expected end of array */
     }
 
 success:
     input_buffer->depth--;
 
     if (head != NULL) {
         head->prev = current_item;
     }
 
     item->type = cJSON_Array;
     item->child = head;
 
     input_buffer->offset++;
 
     return true;
 
 fail:
     if (head != NULL)
     {
         cJSON_Delete(head);
     }
 
     return false;
 }  }
   
 /* Render an array to text */  /* Render an array to text */
static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer)
 {  {
        char **entries;    unsigned char *output_pointer = NULL;
        char *out=0,*ptr,*ret;int len=5;    size_t length = 0;
        cJSON *child=item->child;    cJSON *current_element = item->child;
        int numentries=0,i=0,fail=0; 
        size_t tmplen=0; 
         
        /* How many entries in the array? */ 
        while (child) numentries++,child=child->next; 
        /* Explicitly handle numentries==0 */ 
        if (!numentries) 
        { 
                if (p)  out=ensure(p,3); 
                else    out=(char*)cJSON_malloc(3); 
                if (out) strcpy(out,"[]"); 
                return out; 
        } 
   
        if (p)    if (output_buffer == NULL)
        {    {
                /* Compose the output array. */        return false;
                i=p->offset;    }
                ptr=ensure(p,1);if (!ptr) return 0;      *ptr='[';       p->offset++; 
                child=item->child; 
                while (child && !fail) 
                { 
                        print_value(child,depth+1,fmt,p); 
                        p->offset=update(p); 
                        if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} 
                        child=child->next; 
                } 
                ptr=ensure(p,2);if (!ptr) return 0;     *ptr++=']';*ptr=0; 
                out=(p->buffer)+i; 
        } 
        else 
        { 
                /* Allocate an array to hold the values for each */ 
                entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 
                if (!entries) return 0; 
                memset(entries,0,numentries*sizeof(char*)); 
                /* Retrieve all the results: */ 
                child=item->child; 
                while (child && !fail) 
                { 
                        ret=print_value(child,depth+1,fmt,0); 
                        entries[i++]=ret; 
                        if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 
                        child=child->next; 
                } 
                 
                /* If we didn't fail, try to malloc the output string */ 
                if (!fail)      out=(char*)cJSON_malloc(len); 
                /* If that fails, we fail. */ 
                if (!out) fail=1; 
   
                /* Handle failure. */    /* Compose the output array. */
                if (fail)    /* opening square bracket */
                {    output_pointer = ensure(output_buffer, 1);
                        for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);    if (output_pointer == NULL)
                        cJSON_free(entries);    {
                        return 0;        return false;
                }    }
                
                /* Compose the output array. */    *output_pointer = '[';
                *out='[';    output_buffer->offset++;
                ptr=out+1;*ptr=0;    output_buffer->depth++;
                for (i=0;i<numentries;i++)
                {    while (current_element != NULL)
                        tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;    {
                        if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}        if (!print_value(current_element, output_buffer))
                        cJSON_free(entries[i]);        {
                }            return false;
                cJSON_free(entries);        }
                *ptr++=']';*ptr++=0;        update_offset(output_buffer);
        }        if (current_element->next)
        return out;            {
             length = (size_t) (output_buffer->format ? 2 : 1);
             output_pointer = ensure(output_buffer, length + 1);
             if (output_pointer == NULL)
             {
                 return false;
             }
             *output_pointer++ = ',';
             if(output_buffer->format)
             {
                 *output_pointer++ = ' ';
             }
             *output_pointer = '\0';
             output_buffer->offset += length;
         }
         current_element = current_element->next;
     }
 
     output_pointer = ensure(output_buffer, 2);
     if (output_pointer == NULL)
     {
         return false;
     }
     *output_pointer++ = ']';
     *output_pointer = '\0';
     output_buffer->depth--;
 
     return true;
 }  }
   
 /* Build an object from the text. */  /* Build an object from the text. */
static const char *parse_object(cJSON *item,const char *value,const char **ep)static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer)
 {  {
        cJSON *child;    cJSON *head = NULL; /* linked list head */
        if (*value!='{')    {*ep=value;return 0;}        /* not an object! */    cJSON *current_item = NULL;
        
        item->type=cJSON_Object;    if (input_buffer->depth >= CJSON_NESTING_LIMIT)
        value=skip(value+1);    {
        if (*value=='}') return value+1;        /* empty array. */        return false; /* to deeply nested */
            }
        item->child=child=cJSON_New_Item();    input_buffer->depth++;
        if (!item->child) return 0;
        value=skip(parse_string(child,skip(value),ep));    if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{'))
        if (!value) return 0;    {
        child->string=child->valuestring;child->valuestring=0;        goto fail; /* not an object */
        if (*value!=':') {*ep=value;return 0;}  /* fail! */    }
        value=skip(parse_value(child,skip(value+1),ep));        /* skip any spacing, get the value. */
        if (!value) return 0;    input_buffer->offset++;
            buffer_skip_whitespace(input_buffer);
        while (*value==',')    if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}'))
        {    {
                cJSON *new_item;        goto success; /* empty object */
                if (!(new_item=cJSON_New_Item()))     return 0; /* memory fail */    }
                child->next=new_item;new_item->prev=child;child=new_item;
                value=skip(parse_string(child,skip(value+1),ep));    /* check if we skipped to the end of the buffer */
                if (!value) return 0;    if (cannot_access_at_index(input_buffer, 0))
                child->string=child->valuestring;child->valuestring=0;    {
                if (*value!=':') {*ep=value;return 0;}    /* fail! */        input_buffer->offset--;
                value=skip(parse_value(child,skip(value+1),ep));        /* skip any spacing, get the value. */        goto fail;
                if (!value) return 0;    }
        }
            /* step back to character in front of the first element */
        if (*value=='}') return value+1; /* end of array */    input_buffer->offset--;
        *ep=value;return 0;      /* malformed. */    /* loop through the comma separated array elements */
     do
     {
         /* allocate next item */
         cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks));
         if (new_item == NULL)
         {
             goto fail; /* allocation failure */
         }
 
         /* attach next item to list */
         if (head == NULL)
         {
             /* start the linked list */
             current_item = head = new_item;
         }
         else
         {
             /* add to the end and advance */
             current_item->next = new_item;
             new_item->prev = current_item;
             current_item = new_item;
         }
 
         /* parse the name of the child */
         input_buffer->offset++;
         buffer_skip_whitespace(input_buffer);
         if (!parse_string(current_item, input_buffer))
         {
             goto fail; /* failed to parse name */
         }
         buffer_skip_whitespace(input_buffer);
 
         /* swap valuestring and string, because we parsed the name */
         current_item->string = current_item->valuestring;
         current_item->valuestring = NULL;
 
         if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':'))
         {
             goto fail; /* invalid object */
         }
 
         /* parse the value */
         input_buffer->offset++;
         buffer_skip_whitespace(input_buffer);
         if (!parse_value(current_item, input_buffer))
         {
             goto fail; /* failed to parse value */
         }
         buffer_skip_whitespace(input_buffer);
     }
     while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ','));
 
     if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}'))
     {
         goto fail; /* expected end of object */
     }
 
 success:
     input_buffer->depth--;
 
     if (head != NULL) {
         head->prev = current_item;
     }
 
     item->type = cJSON_Object;
     item->child = head;
 
     input_buffer->offset++;
     return true;
 
 fail:
     if (head != NULL)
     {
         cJSON_Delete(head);
     }
 
     return false;
 }  }
   
 /* Render an object to text. */  /* Render an object to text. */
static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer)
 {  {
        char **entries=0,**names=0;    unsigned char *output_pointer = NULL;
        char *out=0,*ptr,*ret,*str;int len=7,i=0,j;    size_t length = 0;
        cJSON *child=item->child;    cJSON *current_item = item->child;
        int numentries=0,fail=0; 
        size_t tmplen=0; 
        /* Count the number of entries. */ 
        while (child) numentries++,child=child->next; 
        /* Explicitly handle empty object case */ 
        if (!numentries) 
        { 
                if (p) out=ensure(p,fmt?depth+4:3); 
                else    out=(char*)cJSON_malloc(fmt?depth+4:3); 
                if (!out)       return 0; 
                ptr=out;*ptr++='{'; 
                if (fmt) {*ptr++='\n';for (i=0;i<depth;i++) *ptr++='\t';} 
                *ptr++='}';*ptr++=0; 
                return out; 
        } 
        if (p) 
        { 
                /* Compose the output: */ 
                i=p->offset; 
                len=fmt?2:1;    ptr=ensure(p,len+1);    if (!ptr) return 0; 
                *ptr++='{';     if (fmt) *ptr++='\n';   *ptr=0; p->offset+=len; 
                child=item->child;depth++; 
                while (child) 
                { 
                        if (fmt) 
                        { 
                                ptr=ensure(p,depth);    if (!ptr) return 0; 
                                for (j=0;j<depth;j++) *ptr++='\t'; 
                                p->offset+=depth; 
                        } 
                        print_string_ptr(child->string,p); 
                        p->offset=update(p); 
                         
                        len=fmt?2:1; 
                        ptr=ensure(p,len);      if (!ptr) return 0; 
                        *ptr++=':';if (fmt) *ptr++='\t'; 
                        p->offset+=len; 
                         
                        print_value(child,depth,fmt,p); 
                        p->offset=update(p); 
   
                        len=(fmt?1:0)+(child->next?1:0);    if (output_buffer == NULL)
                        ptr=ensure(p,len+1); if (!ptr) return 0;    {
                        if (child->next) *ptr++=',';        return false;
                        if (fmt) *ptr++='\n';*ptr=0;    }
                        p->offset+=len; 
                        child=child->next; 
                } 
                ptr=ensure(p,fmt?(depth+1):2);   if (!ptr) return 0; 
                if (fmt)        for (i=0;i<depth-1;i++) *ptr++='\t'; 
                *ptr++='}';*ptr=0; 
                out=(p->buffer)+i; 
        } 
        else 
        { 
                /* Allocate space for the names and the objects */ 
                entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 
                if (!entries) return 0; 
                names=(char**)cJSON_malloc(numentries*sizeof(char*)); 
                if (!names) {cJSON_free(entries);return 0;} 
                memset(entries,0,sizeof(char*)*numentries); 
                memset(names,0,sizeof(char*)*numentries); 
   
                /* Collect all the results into our arrays: */    /* Compose the output: */
                child=item->child;depth++;if (fmt) len+=depth;    length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */
                while (child && !fail)    output_pointer = ensure(output_buffer, length + 1);
                {    if (output_pointer == NULL)
                        names[i]=str=print_string_ptr(child->string,0);    {
                        entries[i++]=ret=print_value(child,depth,fmt,0);        return false;
                        if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;    }
                        child=child->next; 
                } 
                 
                /* Try to allocate the output string */ 
                if (!fail)      out=(char*)cJSON_malloc(len); 
                if (!out) fail=1; 
   
                /* Handle failure */    *output_pointer++ = '{';
                if (fail)    output_buffer->depth++;
                {    if (output_buffer->format)
                        for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}    {
                        cJSON_free(names);cJSON_free(entries);        *output_pointer++ = '\n';
                        return 0;    }
                }    output_buffer->offset += length;
                
                /* Compose the output: */    while (current_item)
                *out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;    {
                for (i=0;i<numentries;i++)        if (output_buffer->format)
                {        {
                        if (fmt) for (j=0;j<depth;j++) *ptr++='\t';            size_t i;
                        tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;            output_pointer = ensure(output_buffer, output_buffer->depth);
                        *ptr++=':';if (fmt) *ptr++='\t';            if (output_pointer == NULL)
                        strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);            {
                        if (i!=numentries-1) *ptr++=',';                return false;
                        if (fmt) *ptr++='\n';*ptr=0;            }
                        cJSON_free(names[i]);cJSON_free(entries[i]);            for (i = 0; i < output_buffer->depth; i++)
                }            {
                                *output_pointer++ = '\t';
                cJSON_free(names);cJSON_free(entries);            }
                if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';            output_buffer->offset += output_buffer->depth;
                *ptr++='}';*ptr++=0;        }
        }
        return out;            /* print key */
         if (!print_string_ptr((unsigned char*)current_item->string, output_buffer))
         {
             return false;
         }
         update_offset(output_buffer);
 
         length = (size_t) (output_buffer->format ? 2 : 1);
         output_pointer = ensure(output_buffer, length);
         if (output_pointer == NULL)
         {
             return false;
         }
         *output_pointer++ = ':';
         if (output_buffer->format)
         {
             *output_pointer++ = '\t';
         }
         output_buffer->offset += length;
 
         /* print value */
         if (!print_value(current_item, output_buffer))
         {
             return false;
         }
         update_offset(output_buffer);
 
         /* print comma if not last */
         length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0));
         output_pointer = ensure(output_buffer, length + 1);
         if (output_pointer == NULL)
         {
             return false;
         }
         if (current_item->next)
         {
             *output_pointer++ = ',';
         }
 
         if (output_buffer->format)
         {
             *output_pointer++ = '\n';
         }
         *output_pointer = '\0';
         output_buffer->offset += length;
 
         current_item = current_item->next;
     }
 
     output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);
     if (output_pointer == NULL)
     {
         return false;
     }
     if (output_buffer->format)
     {
         size_t i;
         for (i = 0; i < (output_buffer->depth - 1); i++)
         {
             *output_pointer++ = '\t';
         }
     }
     *output_pointer++ = '}';
     *output_pointer = '\0';
     output_buffer->depth--;
 
     return true;
 }  }
   
 /* Get Array size/item / object item. */  /* Get Array size/item / object item. */
int    cJSON_GetArraySize(cJSON *array)                                                 {cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array)
cJSON *cJSON_GetArrayItem(cJSON *array,int item)                                {cJSON *c=array?array->child:0;while (c && item>0) item--,c=c->next; return c;}{
cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)    {cJSON *c=object?object->child:0;while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}    cJSON *child = NULL;
int cJSON_HasObjectItem(cJSON *object,const char *string)               {return cJSON_GetObjectItem(object,string)?1:0;}    size_t size = 0;
   
       if (array == NULL)
       {
           return 0;
       }
   
       child = array->child;
   
       while(child != NULL)
       {
           size++;
           child = child->next;
       }
   
       /* FIXME: Can overflow here. Cannot be fixed without breaking the API */
   
       return (int)size;
   }
   
   static cJSON* get_array_item(const cJSON *array, size_t index)
   {
       cJSON *current_child = NULL;
   
       if (array == NULL)
       {
           return NULL;
       }
   
       current_child = array->child;
       while ((current_child != NULL) && (index > 0))
       {
           index--;
           current_child = current_child->next;
       }
   
       return current_child;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index)
   {
       if (index < 0)
       {
           return NULL;
       }
   
       return get_array_item(array, (size_t)index);
   }
   
   static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive)
   {
       cJSON *current_element = NULL;
   
       if ((object == NULL) || (name == NULL))
       {
           return NULL;
       }
   
       current_element = object->child;
       if (case_sensitive)
       {
           while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0))
           {
               current_element = current_element->next;
           }
       }
       else
       {
           while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0))
           {
               current_element = current_element->next;
           }
       }
   
       if ((current_element == NULL) || (current_element->string == NULL)) {
           return NULL;
       }
   
       return current_element;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string)
   {
       return get_object_item(object, string, false);
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string)
   {
       return get_object_item(object, string, true);
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string)
   {
       return cJSON_GetObjectItem(object, string) ? 1 : 0;
   }
   
 /* Utility for array list handling. */  /* Utility for array list handling. */
static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}static void suffix_object(cJSON *prev, cJSON *item)
 {
     prev->next = item;
     item->prev = prev;
 }
 
 /* Utility for handling references. */  /* Utility for handling references. */
static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks)
 {
     cJSON *reference = NULL;
     if (item == NULL)
     {
         return NULL;
     }
   
       reference = cJSON_New_Item(hooks);
       if (reference == NULL)
       {
           return NULL;
       }
   
       memcpy(reference, item, sizeof(cJSON));
       reference->string = NULL;
       reference->type |= cJSON_IsReference;
       reference->next = reference->prev = NULL;
       return reference;
   }
   
   static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
   {
       cJSON *child = NULL;
   
       if ((item == NULL) || (array == NULL) || (array == item))
       {
           return false;
       }
   
       child = array->child;
       /*
        * To find the last item in array quickly, we use prev in array
        */
       if (child == NULL)
       {
           /* list is empty, start new one */
           array->child = item;
           item->prev = item;
           item->next = NULL;
       }
       else
       {
           /* append to the end */
           if (child->prev)
           {
               suffix_object(child->prev, item);
               array->child->prev = item;
           }
       }
   
       return true;
   }
   
 /* Add item to array/object. */  /* Add item to array/object. */
void   cJSON_AddItemToArray(cJSON *array, cJSON *item)                                          {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item)
void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)      {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}{
void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)    {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}    return add_item_to_array(array, item);
void    cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)                                                {cJSON_AddItemToArray(array,create_reference(item));}}
void    cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)    {cJSON_AddItemToObject(object,string,create_reference(item));} 
   
cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)                        {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;#if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
        if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}    #pragma GCC diagnostic push
void   cJSON_DeleteItemFromArray(cJSON *array,int which)                        {cJSON_Delete(cJSON_DetachItemFromArray(array,which));}#endif
cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}#ifdef __GNUC__
void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 
 #endif
 /* helper function to cast away const */
 static void* cast_away_const(const void* string)
 {
     return (void*)string;
 }
 #if defined(__clang__) || (defined(__GNUC__)  && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
     #pragma GCC diagnostic pop
 #endif
   
   
   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)
   {
       char *new_key = NULL;
       int new_type = cJSON_Invalid;
   
       if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
       {
           return false;
       }
   
       if (constant_key)
       {
           new_key = (char*)cast_away_const(string);
           new_type = item->type | cJSON_StringIsConst;
       }
       else
       {
           new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);
           if (new_key == NULL)
           {
               return false;
           }
   
           new_type = item->type & ~cJSON_StringIsConst;
       }
   
       if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
       {
           hooks->deallocate(item->string);
       }
   
       item->string = new_key;
       item->type = new_type;
   
       return add_item_to_array(object, item);
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
   {
       return add_item_to_object(object, string, item, &global_hooks, false);
   }
   
   /* Add an item to an object with constant string as key */
   CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item)
   {
       return add_item_to_object(object, string, item, &global_hooks, true);
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)
   {
       if (array == NULL)
       {
           return false;
       }
   
       return add_item_to_array(array, create_reference(item, &global_hooks));
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item)
   {
       if ((object == NULL) || (string == NULL))
       {
           return false;
       }
   
       return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false);
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name)
   {
       cJSON *null = cJSON_CreateNull();
       if (add_item_to_object(object, name, null, &global_hooks, false))
       {
           return null;
       }
   
       cJSON_Delete(null);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name)
   {
       cJSON *true_item = cJSON_CreateTrue();
       if (add_item_to_object(object, name, true_item, &global_hooks, false))
       {
           return true_item;
       }
   
       cJSON_Delete(true_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name)
   {
       cJSON *false_item = cJSON_CreateFalse();
       if (add_item_to_object(object, name, false_item, &global_hooks, false))
       {
           return false_item;
       }
   
       cJSON_Delete(false_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean)
   {
       cJSON *bool_item = cJSON_CreateBool(boolean);
       if (add_item_to_object(object, name, bool_item, &global_hooks, false))
       {
           return bool_item;
       }
   
       cJSON_Delete(bool_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number)
   {
       cJSON *number_item = cJSON_CreateNumber(number);
       if (add_item_to_object(object, name, number_item, &global_hooks, false))
       {
           return number_item;
       }
   
       cJSON_Delete(number_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string)
   {
       cJSON *string_item = cJSON_CreateString(string);
       if (add_item_to_object(object, name, string_item, &global_hooks, false))
       {
           return string_item;
       }
   
       cJSON_Delete(string_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw)
   {
       cJSON *raw_item = cJSON_CreateRaw(raw);
       if (add_item_to_object(object, name, raw_item, &global_hooks, false))
       {
           return raw_item;
       }
   
       cJSON_Delete(raw_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name)
   {
       cJSON *object_item = cJSON_CreateObject();
       if (add_item_to_object(object, name, object_item, &global_hooks, false))
       {
           return object_item;
       }
   
       cJSON_Delete(object_item);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name)
   {
       cJSON *array = cJSON_CreateArray();
       if (add_item_to_object(object, name, array, &global_hooks, false))
       {
           return array;
       }
   
       cJSON_Delete(array);
       return NULL;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item)
   {
       if ((parent == NULL) || (item == NULL))
       {
           return NULL;
       }
   
       if (item != parent->child)
       {
           /* not the first element */
           item->prev->next = item->next;
       }
       if (item->next != NULL)
       {
           /* not the last element */
           item->next->prev = item->prev;
       }
   
       if (item == parent->child)
       {
           /* first element */
           parent->child = item->next;
       }
       else if (item->next == NULL)
       {
           /* last element */
           parent->child->prev = item->prev;
       }
   
       /* make sure the detached item doesn't point anywhere anymore */
       item->prev = NULL;
       item->next = NULL;
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which)
   {
       if (which < 0)
       {
           return NULL;
       }
   
       return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which));
   }
   
   CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which)
   {
       cJSON_Delete(cJSON_DetachItemFromArray(array, which));
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string)
   {
       cJSON *to_detach = cJSON_GetObjectItem(object, string);
   
       return cJSON_DetachItemViaPointer(object, to_detach);
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string)
   {
       cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string);
   
       return cJSON_DetachItemViaPointer(object, to_detach);
   }
   
   CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string)
   {
       cJSON_Delete(cJSON_DetachItemFromObject(object, string));
   }
   
   CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string)
   {
       cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string));
   }
   
 /* Replace array/object items with new ones. */  /* Replace array/object items with new ones. */
void   cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)           {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem)
        newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}{
void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)          {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;    cJSON *after_inserted = NULL;
        newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 
        if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 
void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} 
   
       if (which < 0)
       {
           return false;
       }
   
       after_inserted = get_array_item(array, (size_t)which);
       if (after_inserted == NULL)
       {
           return add_item_to_array(array, newitem);
       }
   
       newitem->next = after_inserted;
       newitem->prev = after_inserted->prev;
       after_inserted->prev = newitem;
       if (after_inserted == array->child)
       {
           array->child = newitem;
       }
       else
       {
           newitem->prev->next = newitem;
       }
       return true;
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement)
   {
       if ((parent == NULL) || (replacement == NULL) || (item == NULL))
       {
           return false;
       }
   
       if (replacement == item)
       {
           return true;
       }
   
       replacement->next = item->next;
       replacement->prev = item->prev;
   
       if (replacement->next != NULL)
       {
           replacement->next->prev = replacement;
       }
       if (parent->child == item)
       {
           if (parent->child->prev == parent->child)
           {
               replacement->prev = replacement;
           }
           parent->child = replacement;
       }
       else
       {   /*
            * To find the last item in array quickly, we use prev in array.
            * We can't modify the last item's next pointer where this item was the parent's child
            */
           if (replacement->prev != NULL)
           {
               replacement->prev->next = replacement;
           }
           if (replacement->next == NULL)
           {
               parent->child->prev = replacement;
           }
       }
   
       item->next = NULL;
       item->prev = NULL;
       cJSON_Delete(item);
   
       return true;
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem)
   {
       if (which < 0)
       {
           return false;
       }
   
       return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem);
   }
   
   static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive)
   {
       if ((replacement == NULL) || (string == NULL))
       {
           return false;
       }
   
       /* replace the name in the replacement */
       if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL))
       {
           cJSON_free(replacement->string);
       }
       replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
       if (replacement->string == NULL)
       {
           return false;
       }
   
       replacement->type &= ~cJSON_StringIsConst;
   
       return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement);
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem)
   {
       return replace_item_in_object(object, string, newitem, false);
   }
   
   CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem)
   {
       return replace_item_in_object(object, string, newitem, true);
   }
   
 /* Create basic types: */  /* Create basic types: */
cJSON *cJSON_CreateNull(void)                                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void)
cJSON *cJSON_CreateTrue(void)                                   {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}{
cJSON *cJSON_CreateFalse(void)                                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}    cJSON *item = cJSON_New_Item(&global_hooks);
cJSON *cJSON_CreateBool(int b)                                  {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}    if(item)
cJSON *cJSON_CreateNumber(double num)                   {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int64_t)num;}return item;}    {
cJSON *cJSON_CreateString(const char *string)   {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);if(!item->valuestring){cJSON_Delete(item);return 0;}}return item;}        item->type = cJSON_NULL;
cJSON *cJSON_CreateArray(void)                                  {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}    }
cJSON *cJSON_CreateObject(void)                                 {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type = cJSON_True;
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type = cJSON_False;
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type = boolean ? cJSON_True : cJSON_False;
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type = cJSON_Number;
           item->valuedouble = num;
   
           /* use saturation in case of overflow */
           if (num >= LLONG_MAX)
           {
               item->valueint = LLONG_MAX;
           }
           else if (num <= (double)LLONG_MIN)
           {
               item->valueint = LLONG_MIN;
           }
           else
           {
               item->valueint = (int64_t)num;
           }
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type = cJSON_String;
           item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks);
           if(!item->valuestring)
           {
               cJSON_Delete(item);
               return NULL;
           }
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if (item != NULL)
       {
           item->type = cJSON_String | cJSON_IsReference;
           item->valuestring = (char*)cast_away_const(string);
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if (item != NULL) {
           item->type = cJSON_Object | cJSON_IsReference;
           item->child = (cJSON*)cast_away_const(child);
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if (item != NULL) {
           item->type = cJSON_Array | cJSON_IsReference;
           item->child = (cJSON*)cast_away_const(child);
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type = cJSON_Raw;
           item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks);
           if(!item->valuestring)
           {
               cJSON_Delete(item);
               return NULL;
           }
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if(item)
       {
           item->type=cJSON_Array;
       }
   
       return item;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void)
   {
       cJSON *item = cJSON_New_Item(&global_hooks);
       if (item)
       {
           item->type = cJSON_Object;
       }
   
       return item;
   }
   
 /* Create Arrays: */  /* Create Arrays: */
cJSON *cJSON_CreateIntArray(const int *numbers,int count)              {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count)
cJSON *cJSON_CreateFloatArray(const float *numbers,int count)   {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}{
cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}    size_t i = 0;
cJSON *cJSON_CreateStringArray(const char **strings,int count)  {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}    cJSON *n = NULL;
     cJSON *p = NULL;
     cJSON *a = NULL;
   
       if ((count < 0) || (numbers == NULL))
       {
           return NULL;
       }
   
       a = cJSON_CreateArray();
   
       for(i = 0; a && (i < (size_t)count); i++)
       {
           n = cJSON_CreateNumber(numbers[i]);
           if (!n)
           {
               cJSON_Delete(a);
               return NULL;
           }
           if(!i)
           {
               a->child = n;
           }
           else
           {
               suffix_object(p, n);
           }
           p = n;
       }
   
       if (a && a->child) {
           a->child->prev = n;
       }
   
       return a;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count)
   {
       size_t i = 0;
       cJSON *n = NULL;
       cJSON *p = NULL;
       cJSON *a = NULL;
   
       if ((count < 0) || (numbers == NULL))
       {
           return NULL;
       }
   
       a = cJSON_CreateArray();
   
       for(i = 0; a && (i < (size_t)count); i++)
       {
           n = cJSON_CreateNumber((double)numbers[i]);
           if(!n)
           {
               cJSON_Delete(a);
               return NULL;
           }
           if(!i)
           {
               a->child = n;
           }
           else
           {
               suffix_object(p, n);
           }
           p = n;
       }
   
       if (a && a->child) {
           a->child->prev = n;
       }
   
       return a;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count)
   {
       size_t i = 0;
       cJSON *n = NULL;
       cJSON *p = NULL;
       cJSON *a = NULL;
   
       if ((count < 0) || (numbers == NULL))
       {
           return NULL;
       }
   
       a = cJSON_CreateArray();
   
       for(i = 0; a && (i < (size_t)count); i++)
       {
           n = cJSON_CreateNumber(numbers[i]);
           if(!n)
           {
               cJSON_Delete(a);
               return NULL;
           }
           if(!i)
           {
               a->child = n;
           }
           else
           {
               suffix_object(p, n);
           }
           p = n;
       }
   
       if (a && a->child) {
           a->child->prev = n;
       }
   
       return a;
   }
   
   CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count)
   {
       size_t i = 0;
       cJSON *n = NULL;
       cJSON *p = NULL;
       cJSON *a = NULL;
   
       if ((count < 0) || (strings == NULL))
       {
           return NULL;
       }
   
       a = cJSON_CreateArray();
   
       for (i = 0; a && (i < (size_t)count); i++)
       {
           n = cJSON_CreateString(strings[i]);
           if(!n)
           {
               cJSON_Delete(a);
               return NULL;
           }
           if(!i)
           {
               a->child = n;
           }
           else
           {
               suffix_object(p,n);
           }
           p = n;
       }
   
       if (a && a->child) {
           a->child->prev = n;
       }
   
       return a;
   }
   
 /* Duplication */  /* Duplication */
cJSON *cJSON_Duplicate(cJSON *item,int recurse)CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse)
 {  {
        cJSON *newitem,*cptr,*nptr=0,*newchild;    cJSON *newitem = NULL;
        /* Bail on bad ptr */    cJSON *child = NULL;
        if (!item) return 0;    cJSON *next = NULL;
        /* Create new item */    cJSON *newchild = NULL;
        newitem=cJSON_New_Item();
        if (!newitem) return 0;    /* Bail on bad ptr */
        /* Copy over all vars */    if (!item)
        newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;    {
        if (item->valuestring)  {newitem->valuestring=cJSON_strdup(item->valuestring);        if (!newitem->valuestring)      {cJSON_Delete(newitem);return 0;}}        goto fail;
        if (item->string)               {newitem->string=cJSON_strdup(item->string);                        if (!newitem->string)           {cJSON_Delete(newitem);return 0;}}    }
        /* If non-recursive, then we're done! */    /* Create new item */
        if (!recurse) return newitem;    newitem = cJSON_New_Item(&global_hooks);
        /* Walk the ->next chain for the child. */    if (!newitem)
        cptr=item->child;    {
        while (cptr)        goto fail;
        {    }
                newchild=cJSON_Duplicate(cptr,1);                /* Duplicate (with recurse) each item in the ->next chain */    /* Copy over all vars */
                if (!newchild) {cJSON_Delete(newitem);return 0;}    newitem->type = item->type & (~cJSON_IsReference);
                if (nptr)    {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}        /* If newitem->child already set, then crosswire ->prev and ->next and move on */    newitem->valueint = item->valueint;
                else            {newitem->child=newchild;nptr=newchild;}                                      /* Set newitem->child and move to it */    newitem->valuedouble = item->valuedouble;
                cptr=cptr->next;    if (item->valuestring)
        }    {
        return newitem;        newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks);
         if (!newitem->valuestring)
         {
             goto fail;
         }
     }
     if (item->string)
     {
         newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks);
         if (!newitem->string)
         {
             goto fail;
         }
     }
     /* If non-recursive, then we're done! */
     if (!recurse)
     {
         return newitem;
     }
     /* Walk the ->next chain for the child. */
     child = item->child;
     while (child != NULL)
     {
         newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */
         if (!newchild)
         {
             goto fail;
         }
         if (next != NULL)
         {
             /* If newitem->child already set, then crosswire ->prev and ->next and move on */
             next->next = newchild;
             newchild->prev = next;
             next = newchild;
         }
         else
         {
             /* Set newitem->child and move to it */
             newitem->child = newchild;
             next = newchild;
         }
         child = child->next;
     }
     if (newitem && newitem->child)
     {
         newitem->child->prev = newchild;
     }
 
     return newitem;
 
 fail:
     if (newitem != NULL)
     {
         cJSON_Delete(newitem);
     }
 
     return NULL;
 }  }
   
void cJSON_Minify(char *json)static void skip_oneline_comment(char **input)
 {  {
        char *into=json;    *input += static_strlen("//");
        while (*json)
        {    for (; (*input)[0] != '\0'; ++(*input))
                if (*json==' ') json++;    {
                else if (*json=='\t') json++;    /* Whitespace characters. */        if ((*input)[0] == '\n') {
                else if (*json=='\r') json++;            *input += static_strlen("\n");
                else if (*json=='\n') json++;            return;
                else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;    /* double-slash comments, to end of line. */        }
                else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}        /* multiline comments. */    }
                else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */}
                else *into++=*json++;                       /* All other characters. */
        }static void skip_multiline_comment(char **input)
        *into=0;        /* and null-terminate. */{
     *input += static_strlen("/*");
 
     for (; (*input)[0] != '\0'; ++(*input))
     {
         if (((*input)[0] == '*') && ((*input)[1] == '/'))
         {
             *input += static_strlen("*/");
             return;
         }
     }
 }
 
 static void minify_string(char **input, char **output) {
     (*output)[0] = (*input)[0];
     *input += static_strlen("\"");
     *output += static_strlen("\"");
 
 
     for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) {
         (*output)[0] = (*input)[0];
 
         if ((*input)[0] == '\"') {
             (*output)[0] = '\"';
             *input += static_strlen("\"");
             *output += static_strlen("\"");
             return;
         } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) {
             (*output)[1] = (*input)[1];
             *input += static_strlen("\"");
             *output += static_strlen("\"");
         }
     }
 }
 
 CJSON_PUBLIC(void) cJSON_Minify(char *json)
 {
     char *into = json;
 
     if (json == NULL)
     {
         return;
     }
 
     while (json[0] != '\0')
     {
         switch (json[0])
         {
             case ' ':
             case '\t':
             case '\r':
             case '\n':
                 json++;
                 break;
 
             case '/':
                 if (json[1] == '/')
                 {
                     skip_oneline_comment(&json);
                 }
                 else if (json[1] == '*')
                 {
                     skip_multiline_comment(&json);
                 } else {
                     json++;
                 }
                 break;
 
             case '\"':
                 minify_string(&json, (char**)&into);
                 break;
 
             default:
                 into[0] = json[0];
                 json++;
                 into++;
         }
     }
 
     /* and null-terminate. */
     *into = '\0';
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_Invalid;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_False;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xff) == cJSON_True;
 }
 
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & (cJSON_True | cJSON_False)) != 0;
 }
 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_NULL;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_Number;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_String;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_Array;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_Object;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item)
 {
     if (item == NULL)
     {
         return false;
     }
 
     return (item->type & 0xFF) == cJSON_Raw;
 }
 
 CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive)
 {
     if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)))
     {
         return false;
     }
 
     /* check if type is valid */
     switch (a->type & 0xFF)
     {
         case cJSON_False:
         case cJSON_True:
         case cJSON_NULL:
         case cJSON_Number:
         case cJSON_String:
         case cJSON_Raw:
         case cJSON_Array:
         case cJSON_Object:
             break;
 
         default:
             return false;
     }
 
     /* identical objects are equal */
     if (a == b)
     {
         return true;
     }
 
     switch (a->type & 0xFF)
     {
         /* in these cases and equal type is enough */
         case cJSON_False:
         case cJSON_True:
         case cJSON_NULL:
             return true;
 
         case cJSON_Number:
             if (compare_double(a->valuedouble, b->valuedouble))
             {
                 return true;
             }
             return false;
 
         case cJSON_String:
         case cJSON_Raw:
             if ((a->valuestring == NULL) || (b->valuestring == NULL))
             {
                 return false;
             }
             if (strcmp(a->valuestring, b->valuestring) == 0)
             {
                 return true;
             }
 
             return false;
 
         case cJSON_Array:
         {
             cJSON *a_element = a->child;
             cJSON *b_element = b->child;
 
             for (; (a_element != NULL) && (b_element != NULL);)
             {
                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
                 {
                     return false;
                 }
 
                 a_element = a_element->next;
                 b_element = b_element->next;
             }
 
             /* one of the arrays is longer than the other */
             if (a_element != b_element) {
                 return false;
             }
 
             return true;
         }
 
         case cJSON_Object:
         {
             cJSON *a_element = NULL;
             cJSON *b_element = NULL;
             cJSON_ArrayForEach(a_element, a)
             {
                 /* TODO This has O(n^2) runtime, which is horrible! */
                 b_element = get_object_item(b, a_element->string, case_sensitive);
                 if (b_element == NULL)
                 {
                     return false;
                 }
 
                 if (!cJSON_Compare(a_element, b_element, case_sensitive))
                 {
                     return false;
                 }
             }
 
             /* doing this twice, once on a and b to prevent true comparison if a subset of b
              * TODO: Do this the proper way, this is just a fix for now */
             cJSON_ArrayForEach(b_element, b)
             {
                 a_element = get_object_item(a, b_element->string, case_sensitive);
                 if (a_element == NULL)
                 {
                     return false;
                 }
 
                 if (!cJSON_Compare(b_element, a_element, case_sensitive))
                 {
                     return false;
                 }
             }
 
             return true;
         }
 
         default:
             return false;
     }
 }
 
 CJSON_PUBLIC(void *) cJSON_malloc(size_t size)
 {
     return global_hooks.allocate(size);
 }
 
 CJSON_PUBLIC(void) cJSON_free(void *object)
 {
     global_hooks.deallocate(object);
 }  }

Removed from v.1.1  
changed lines
  Added in v.1.1.1.3


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