2011-08-22 08:43:38 +04:00
/*
Copyright ( c ) 2009 Dave Gamble
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE .
*/
/* cJSON */
/* JSON parser in C. */
# include <string.h>
# include <stdio.h>
# include <math.h>
# include <stdlib.h>
# include <float.h>
# include <limits.h>
# include <ctype.h>
# include "cJSON.h"
2016-03-19 21:41:44 +03:00
static const char * global_ep ;
2011-08-22 08:43:38 +04:00
2016-09-27 19:38:05 +03:00
const char * cJSON_GetErrorPtr ( void )
{
return global_ep ;
}
2011-08-22 08:43:38 +04:00
2016-09-27 19:38:41 +03:00
/* case insensitive strcmp */
static int cJSON_strcasecmp ( const char * s1 , const char * s2 )
2011-08-22 08:43:38 +04:00
{
2016-09-27 19:38:41 +03:00
if ( ! s1 )
{
return ( s1 = = s2 ) ? 0 : 1 ; /* both NULL? */
}
if ( ! s2 )
{
return 1 ;
}
for ( ; tolower ( * s1 ) = = tolower ( * s2 ) ; + + s1 , + + s2 )
{
if ( * s1 = = 0 )
{
return 0 ;
}
}
return tolower ( * ( const unsigned char * ) s1 ) - tolower ( * ( const unsigned char * ) s2 ) ;
2011-08-22 08:43:38 +04:00
}
static void * ( * cJSON_malloc ) ( size_t sz ) = malloc ;
static void ( * cJSON_free ) ( void * ptr ) = free ;
static char * cJSON_strdup ( const char * str )
{
2016-09-27 19:39:22 +03:00
size_t len ;
char * copy ;
2011-08-22 08:43:38 +04:00
2016-09-27 19:39:22 +03:00
len = strlen ( str ) + 1 ;
if ( ! ( copy = ( char * ) cJSON_malloc ( len ) ) )
{
return 0 ;
}
memcpy ( copy , str , len ) ;
return copy ;
2011-08-22 08:43:38 +04:00
}
void cJSON_InitHooks ( cJSON_Hooks * hooks )
{
2016-09-27 19:39:54 +03:00
if ( ! hooks )
{
/* Reset hooks */
2011-08-22 08:43:38 +04:00
cJSON_malloc = malloc ;
cJSON_free = free ;
return ;
}
2016-09-27 19:39:54 +03:00
cJSON_malloc = ( hooks - > malloc_fn ) ? hooks - > malloc_fn : malloc ;
cJSON_free = ( hooks - > free_fn ) ? hooks - > free_fn : free ;
2011-08-22 08:43:38 +04:00
}
/* Internal constructor. */
2013-02-05 21:00:31 +04:00
static cJSON * cJSON_New_Item ( void )
2011-08-22 08:43:38 +04:00
{
2016-09-27 19:40:16 +03:00
cJSON * node = ( cJSON * ) cJSON_malloc ( sizeof ( cJSON ) ) ;
if ( node )
{
memset ( node , 0 , sizeof ( cJSON ) ) ;
}
return node ;
2011-08-22 08:43:38 +04:00
}
/* Delete a cJSON structure. */
void cJSON_Delete ( cJSON * c )
{
2016-09-27 19:42:50 +03:00
cJSON * next ;
while ( c )
{
next = c - > next ;
if ( ! ( c - > type & cJSON_IsReference ) & & c - > child )
{
cJSON_Delete ( c - > child ) ;
}
if ( ! ( c - > type & cJSON_IsReference ) & & c - > valuestring )
{
cJSON_free ( c - > valuestring ) ;
}
if ( ! ( c - > type & cJSON_StringIsConst ) & & c - > string )
{
cJSON_free ( c - > string ) ;
}
cJSON_free ( c ) ;
c = next ;
}
2011-08-22 08:43:38 +04:00
}
/* Parse the input text to generate a number, and populate the result into item. */
2016-09-27 19:44:13 +03:00
static const char * parse_number ( cJSON * item , const char * num )
2011-08-22 08:43:38 +04:00
{
2016-09-27 19:44:13 +03:00
double n = 0 ;
double sign = 1 ;
double scale = 0 ;
int subscale = 0 ;
int signsubscale = 1 ;
/* Has sign? */
if ( * num = = ' - ' )
{
sign = - 1 ;
num + + ;
}
/* is zero */
if ( * num = = ' 0 ' )
{
num + + ;
}
/* Number? */
if ( ( * num > = ' 1 ' ) & & ( * num < = ' 9 ' ) )
{
do
{
n = ( n * 10.0 ) + ( * num + + - ' 0 ' ) ;
}
while ( ( * num > = ' 0 ' ) & & ( * num < = ' 9 ' ) ) ;
}
/* Fractional part? */
if ( ( * num = = ' . ' ) & & ( num [ 1 ] > = ' 0 ' ) & & ( num [ 1 ] < = ' 9 ' ) )
{
num + + ;
do
{
n = ( n * 10.0 ) + ( * num + + - ' 0 ' ) ;
scale - - ;
} while ( ( * num > = ' 0 ' ) & & ( * num < = ' 9 ' ) ) ;
}
/* Exponent? */
if ( ( * num = = ' e ' ) | | ( * num = = ' E ' ) )
{
num + + ;
/* With sign? */
if ( * num = = ' + ' )
{
num + + ;
}
else if ( * num = = ' - ' )
{
signsubscale = - 1 ;
num + + ;
}
/* Number? */
while ( ( * num > = ' 0 ' ) & & ( * num < = ' 9 ' ) )
{
subscale = ( subscale * 10 ) + ( * num + + - ' 0 ' ) ;
}
}
/* number = +/- number.fraction * 10^+/- exponent */
n = sign * n * pow ( 10.0 , ( scale + subscale * signsubscale ) ) ;
item - > valuedouble = n ;
item - > valueint = ( int ) n ;
item - > type = cJSON_Number ;
return num ;
2011-08-22 08:43:38 +04:00
}
2016-09-27 19:44:47 +03:00
/* calculate the next largest power of 2 */
static int pow2gt ( int x )
{
- - x ;
x | = x > > 1 ;
x | = x > > 2 ;
x | = x > > 4 ;
x | = x > > 8 ;
x | = x > > 16 ;
return x + 1 ;
}
2015-02-09 20:34:35 +03:00
2016-09-27 19:45:52 +03:00
typedef struct
{
char * buffer ;
int length ;
int offset ;
} printbuffer ;
2015-02-09 20:34:35 +03:00
2016-09-27 19:46:22 +03:00
/* realloc printbuffer if necessary to have at least "needed" bytes more */
static char * ensure ( printbuffer * p , int needed )
2015-02-09 20:34:35 +03:00
{
2016-09-27 19:46:22 +03:00
char * newbuffer ;
int newsize ;
if ( ! p | | ! p - > buffer )
{
return 0 ;
}
needed + = p - > offset ;
if ( needed < = p - > length )
{
return p - > buffer + p - > offset ;
}
newsize = pow2gt ( needed ) ;
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 ;
2015-02-09 20:34:35 +03:00
}
2016-09-27 19:46:39 +03:00
/* calculate the new length of the string in a printbuffer */
2015-02-09 20:34:35 +03:00
static int update ( printbuffer * p )
2011-08-22 08:43:38 +04:00
{
2016-09-27 19:46:39 +03:00
char * str ;
if ( ! p | | ! p - > buffer )
{
return 0 ;
}
str = p - > buffer + p - > offset ;
return p - > offset + strlen ( str ) ;
2015-02-09 20:34:35 +03:00
}
/* Render the number nicely from the given item into a string. */
2016-09-27 19:47:13 +03:00
static char * print_number ( cJSON * item , printbuffer * p )
2015-02-09 20:34:35 +03:00
{
2016-09-27 19:47:13 +03:00
char * str = 0 ;
double d = item - > valuedouble ;
/* special case for 0. */
if ( d = = 0 )
{
if ( p )
{
str = ensure ( p , 2 ) ;
}
else
{
str = ( char * ) cJSON_malloc ( 2 ) ;
}
if ( str )
{
strcpy ( str , " 0 " ) ;
}
}
/* value is an int */
else if ( ( fabs ( ( ( double ) item - > valueint ) - d ) < = DBL_EPSILON ) & & ( d < = INT_MAX ) & & ( d > = INT_MIN ) )
{
if ( p )
{
str = ensure ( p , 21 ) ;
}
else
{
/* 2^64+1 can be represented in 21 chars. */
str = ( char * ) cJSON_malloc ( 21 ) ;
}
if ( str )
{
sprintf ( str , " %d " , item - > valueint ) ;
}
}
/* value is a floating point number */
else
{
if ( p )
{
/* This is a nice tradeoff. */
str = ensure ( p , 64 ) ;
}
else
{
/* This is a nice tradeoff. */
str = ( char * ) cJSON_malloc ( 64 ) ;
}
if ( str )
{
/* This checks for NaN and Infinity */
if ( ( d * 0 ) ! = 0 )
{
sprintf ( str , " null " ) ;
}
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
{
sprintf ( str , " %f " , d ) ;
}
}
}
return str ;
2011-08-22 08:43:38 +04:00
}
2016-09-27 19:47:58 +03:00
/* parse 4 digit hexadecimal number */
2013-08-14 17:20:42 +04:00
static unsigned parse_hex4 ( const char * str )
{
2016-09-27 19:47:58 +03:00
unsigned h = 0 ;
/* first digit */
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 /* invalid */
{
return 0 ;
}
/* second digit */
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 /* invalid */
{
return 0 ;
}
/* third digit */
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 /* invalid */
{
return 0 ;
}
/* fourth digit */
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 /* invalid */
{
return 0 ;
}
return h ;
2013-08-14 17:20:42 +04:00
}
2016-09-27 21:32:09 +03:00
/* first bytes of UTF8 encoding for a given length in bytes */
static const unsigned char firstByteMark [ 7 ] =
{
0x00 , /* should never happen */
0x00 , /* 0xxxxxxx */
0xC0 , /* 110xxxxx */
0xE0 , /* 1110xxxx */
0xF0 , /* 11110xxx */
0xF8 ,
0xFC
} ;
2011-08-22 08:43:38 +04:00
/* Parse the input text into an unescaped cstring, and populate item. */
2016-09-27 21:34:47 +03:00
static const char * parse_string ( cJSON * item , const char * str , const char * * ep )
2011-08-22 08:43:38 +04:00
{
2016-09-27 21:34:47 +03:00
const char * ptr = str + 1 ;
const char * end_ptr = str + 1 ;
char * ptr2 ;
char * out ;
int len = 0 ;
unsigned uc ;
unsigned uc2 ;
/* not a string! */
if ( * str ! = ' \" ' )
{
* ep = str ;
return 0 ;
}
2016-10-02 14:56:53 +03:00
2016-09-27 21:34:47 +03:00
while ( ( * end_ptr ! = ' \" ' ) & & * end_ptr & & + + len )
{
if ( * end_ptr + + = = ' \\ ' )
{
if ( * end_ptr = = ' \0 ' )
{
/* prevent buffer overflow when last input character is a backslash */
return 0 ;
}
/* Skip escaped quotes. */
end_ptr + + ;
}
}
2016-10-02 14:56:53 +03:00
2016-09-27 21:34:47 +03:00
/* This is at most how long we need for the string, roughly. */
out = ( char * ) cJSON_malloc ( len + 1 ) ;
if ( ! out )
{
return 0 ;
}
item - > valuestring = out ; /* assign here so out will be deleted during cJSON_Delete() later */
item - > type = cJSON_String ;
ptr = str + 1 ;
ptr2 = out ;
/* loop through the string literal */
while ( ptr < end_ptr )
{
if ( * ptr ! = ' \\ ' )
{
* ptr2 + + = * ptr + + ;
}
/* escape sequence */
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. See RFC2781 and RFC3629. */
uc = parse_hex4 ( ptr + 1 ) ; /* get the unicode char. */
ptr + = 4 ;
if ( ptr > = end_ptr )
{
/* invalid */
* ep = str ;
return 0 ;
}
/* check for invalid. */
if ( ( ( uc > = 0xDC00 ) & & ( uc < = 0xDFFF ) ) | | ( uc = = 0 ) )
{
* ep = str ;
return 0 ;
}
/* UTF16 surrogate pairs. */
if ( ( uc > = 0xD800 ) & & ( uc < = 0xDBFF ) )
{
if ( ( ptr + 6 ) > end_ptr )
{
/* invalid */
* ep = str ;
return 0 ;
}
if ( ( ptr [ 1 ] ! = ' \\ ' ) | | ( ptr [ 2 ] ! = ' u ' ) )
{
/* missing second-half of surrogate. */
* ep = str ;
return 0 ;
}
uc2 = parse_hex4 ( ptr + 3 ) ;
ptr + = 6 ; /* \uXXXX */
if ( ( uc2 < 0xDC00 ) | | ( uc2 > 0xDFFF ) )
{
/* invalid second-half of surrogate. */
* ep = str ;
return 0 ;
}
/* calculate unicode codepoint from the surrogate pair */
uc = 0x10000 + ( ( ( uc & 0x3FF ) < < 10 ) | ( uc2 & 0x3FF ) ) ;
}
/* encode as UTF8
* takes at maximum 4 bytes to encode :
* 11110 xxx 10 xxxxxx 10 xxxxxx 10 xxxxxx */
len = 4 ;
if ( uc < 0x80 )
{
/* normal ascii, encoding 0xxxxxxx */
len = 1 ;
}
else if ( uc < 0x800 )
{
/* two bytes, encoding 110xxxxx 10xxxxxx */
len = 2 ;
}
else if ( uc < 0x10000 )
{
/* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */
len = 3 ;
}
ptr2 + = len ;
switch ( len ) {
case 4 :
/* 10xxxxxx */
* - - ptr2 = ( ( uc | 0x80 ) & 0xBF ) ;
uc > > = 6 ;
case 3 :
/* 10xxxxxx */
* - - ptr2 = ( ( uc | 0x80 ) & 0xBF ) ;
uc > > = 6 ;
case 2 :
/* 10xxxxxx */
* - - ptr2 = ( ( uc | 0x80 ) & 0xBF ) ;
uc > > = 6 ;
case 1 :
/* depending on the length in bytes this determines the
* encoding ofthe first UTF8 byte */
* - - ptr2 = ( uc | firstByteMark [ len ] ) ;
}
ptr2 + = len ;
break ;
default :
* ptr2 + + = * ptr ;
break ;
}
ptr + + ;
}
}
* ptr2 = ' \0 ' ;
if ( * ptr = = ' \" ' )
{
ptr + + ;
}
return ptr ;
2011-08-22 08:43:38 +04:00
}
/* Render the cstring provided to an escaped version that can be printed. */
2016-09-28 19:17:34 +03:00
static char * print_string_ptr ( const char * str , printbuffer * p )
2011-08-22 08:43:38 +04:00
{
2016-09-28 19:17:34 +03:00
const char * ptr ;
char * ptr2 ;
char * out ;
int len = 0 ;
int flag = 0 ;
unsigned char token ;
/* empty string */
if ( ! str )
{
if ( p )
{
out = ensure ( p , 3 ) ;
}
else
{
out = ( char * ) cJSON_malloc ( 3 ) ;
}
if ( ! out )
{
return 0 ;
}
strcpy ( out , " \" \" " ) ;
return out ;
}
/* set "flag" to 1 if something needs to be escaped */
for ( ptr = str ; * ptr ; ptr + + )
{
flag | = ( ( ( * ptr > 0 ) & & ( * ptr < 32 ) ) /* unprintable characters */
| | ( * ptr = = ' \" ' ) /* double quote */
| | ( * ptr = = ' \\ ' ) ) /* backslash */
? 1
: 0 ;
}
/* no characters have to be escaped */
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 ;
/* calculate additional space that is needed for escaping */
while ( ( token = * ptr ) & & + + len )
{
if ( strchr ( " \" \\ \b \f \n \r \t " , token ) )
{
len + + ; /* +1 for the backslash */
}
else if ( token < 32 )
{
len + = 5 ; /* +5 for \uXXXX */
}
ptr + + ;
}
if ( p )
{
out = ensure ( p , len + 3 ) ;
}
else
{
out = ( char * ) cJSON_malloc ( len + 3 ) ;
}
if ( ! out )
{
return 0 ;
}
ptr2 = out ;
ptr = str ;
* ptr2 + + = ' \" ' ;
/* copy the string */
while ( * ptr )
{
if ( ( ( unsigned char ) * ptr > 31 ) & & ( * ptr ! = ' \" ' ) & & ( * ptr ! = ' \\ ' ) )
{
/* normal character, copy */
* ptr2 + + = * ptr + + ;
}
else
{
/* character needs to be escaped */
* ptr2 + + = ' \\ ' ;
switch ( token = * ptr + + )
{
case ' \\ ' :
* ptr2 + + = ' \\ ' ;
break ;
case ' \" ' :
* ptr2 + + = ' \" ' ;
break ;
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 ;
default :
/* escape and print as unicode codepoint */
sprintf ( ptr2 , " u%04x " , token ) ;
ptr2 + = 5 ;
break ;
}
}
}
* ptr2 + + = ' \" ' ;
* ptr2 + + = ' \0 ' ;
return out ;
2011-08-22 08:43:38 +04:00
}
2016-09-28 19:17:34 +03:00
2016-09-28 16:40:45 +03:00
/* Invoke print_string_ptr (which is useful) on an item. */
static char * print_string ( cJSON * item , printbuffer * p )
{
return print_string_ptr ( item - > valuestring , p ) ;
}
2011-08-22 08:43:38 +04:00
/* Predeclare these prototypes. */
2016-09-28 16:41:07 +03:00
static const char * parse_value ( cJSON * item , const char * value , const char * * ep ) ;
static char * print_value ( cJSON * item , int depth , int fmt , printbuffer * p ) ;
static const char * parse_array ( cJSON * item , const char * value , const char * * ep ) ;
static char * print_array ( cJSON * item , int depth , int fmt , printbuffer * p ) ;
static const char * parse_object ( cJSON * item , const char * value , const char * * ep ) ;
static char * print_object ( cJSON * item , int depth , int fmt , printbuffer * p ) ;
2011-08-22 08:43:38 +04:00
/* Utility to jump whitespace and cr/lf */
2016-09-28 16:41:24 +03:00
static const char * skip ( const char * in )
{
while ( in & & * in & & ( ( unsigned char ) * in < = 32 ) )
{
in + + ;
}
return in ;
}
2011-08-22 08:43:38 +04:00
/* Parse an object - create a new root, and populate. */
2016-09-28 16:42:09 +03:00
cJSON * cJSON_ParseWithOpts ( const char * value , const char * * return_parse_end , int require_null_terminated )
2011-08-22 08:43:38 +04:00
{
2016-09-28 16:42:09 +03:00
const char * end = 0 ;
/* use global error pointer if no specific one was given */
const char * * ep = return_parse_end ? return_parse_end : & global_ep ;
cJSON * c = cJSON_New_Item ( ) ;
* ep = 0 ;
if ( ! c ) /* memory fail */
{
return 0 ;
}
end = parse_value ( c , skip ( value ) , ep ) ;
if ( ! end )
{
/* parse failure. ep is set. */
cJSON_Delete ( c ) ;
return 0 ;
}
/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
if ( require_null_terminated )
{
end = skip ( end ) ;
if ( * end )
{
cJSON_Delete ( c ) ;
* ep = end ;
return 0 ;
}
}
if ( return_parse_end )
{
* return_parse_end = end ;
}
return c ;
2011-08-22 08:43:38 +04:00
}
2016-09-28 16:42:09 +03:00
2013-02-06 16:44:17 +04:00
/* Default options for cJSON_Parse */
cJSON * cJSON_Parse ( const char * value ) { return cJSON_ParseWithOpts ( value , 0 , 0 ) ; }
2011-08-22 08:43:38 +04:00
/* Render a cJSON item/entity/structure to text. */
2015-02-09 20:34:35 +03:00
char * cJSON_Print ( cJSON * item ) { return print_value ( item , 0 , 1 , 0 ) ; }
char * cJSON_PrintUnformatted ( cJSON * item ) { return print_value ( item , 0 , 0 , 0 ) ; }
char * cJSON_PrintBuffered ( cJSON * item , int prebuffer , int fmt )
{
printbuffer p ;
p . buffer = ( char * ) cJSON_malloc ( prebuffer ) ;
p . length = prebuffer ;
p . offset = 0 ;
return print_value ( item , 0 , fmt , & p ) ;
}
2011-08-22 08:43:38 +04:00
/* Parser core - when encountering text, process appropriately. */
2016-03-19 21:41:44 +03:00
static const char * parse_value ( cJSON * item , const char * value , const char * * ep )
2011-08-22 08:43:38 +04:00
{
if ( ! value ) return 0 ; /* Fail on 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 ; }
if ( ! strncmp ( value , " true " , 4 ) ) { item - > type = cJSON_True ; item - > valueint = 1 ; return value + 4 ; }
2016-03-19 21:41:44 +03:00
if ( * value = = ' \" ' ) { return parse_string ( item , value , ep ) ; }
2011-08-22 08:43:38 +04:00
if ( * value = = ' - ' | | ( * value > = ' 0 ' & & * value < = ' 9 ' ) ) { return parse_number ( item , value ) ; }
2016-03-19 21:41:44 +03:00
if ( * value = = ' [ ' ) { return parse_array ( item , value , ep ) ; }
if ( * value = = ' { ' ) { return parse_object ( item , value , ep ) ; }
2011-08-22 08:43:38 +04:00
2016-03-19 21:41:44 +03:00
* ep = value ; return 0 ; /* failure. */
2011-08-22 08:43:38 +04:00
}
/* Render a value to text. */
2015-02-09 20:34:35 +03:00
static char * print_value ( cJSON * item , int depth , int fmt , printbuffer * p )
2011-08-22 08:43:38 +04:00
{
char * out = 0 ;
if ( ! item ) return 0 ;
2015-02-09 20:34:35 +03:00
if ( p )
2009-08-26 07:55:20 +04:00
{
2015-02-09 20:34:35 +03:00
switch ( ( item - > type ) & 255 )
{
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 ; }
case cJSON_True : { out = ensure ( p , 5 ) ; if ( out ) strcpy ( out , " true " ) ; break ; }
case cJSON_Number : out = print_number ( item , p ) ; break ;
case cJSON_String : out = print_string ( item , p ) ; break ;
case cJSON_Array : out = print_array ( item , depth , fmt , p ) ; break ;
case cJSON_Object : out = print_object ( item , depth , fmt , p ) ; break ;
}
}
else
2011-08-22 08:43:38 +04:00
{
2015-02-09 20:34:35 +03:00
switch ( ( item - > type ) & 255 )
{
case cJSON_NULL : out = cJSON_strdup ( " null " ) ; break ;
case cJSON_False : out = cJSON_strdup ( " false " ) ; break ;
case cJSON_True : out = cJSON_strdup ( " true " ) ; break ;
case cJSON_Number : out = print_number ( item , 0 ) ; break ;
case cJSON_String : out = print_string ( item , 0 ) ; break ;
case cJSON_Array : out = print_array ( item , depth , fmt , 0 ) ; break ;
case cJSON_Object : out = print_object ( item , depth , fmt , 0 ) ; break ;
}
2011-08-22 08:43:38 +04:00
}
return out ;
}
/* Build an array from input text. */
2016-03-19 21:41:44 +03:00
static const char * parse_array ( cJSON * item , const char * value , const char * * ep )
2011-08-22 08:43:38 +04:00
{
cJSON * child ;
2016-03-19 21:41:44 +03:00
if ( * value ! = ' [ ' ) { * ep = value ; return 0 ; } /* not an array! */
2011-08-22 08:43:38 +04:00
item - > type = cJSON_Array ;
value = skip ( value + 1 ) ;
if ( * value = = ' ] ' ) return value + 1 ; /* empty array. */
item - > child = child = cJSON_New_Item ( ) ;
if ( ! item - > child ) return 0 ; /* memory fail */
2016-03-19 21:41:44 +03:00
value = skip ( parse_value ( child , skip ( value ) , ep ) ) ; /* skip any spacing, get the value. */
2011-08-22 08:43:38 +04:00
if ( ! value ) return 0 ;
while ( * value = = ' , ' )
{
cJSON * new_item ;
if ( ! ( new_item = cJSON_New_Item ( ) ) ) return 0 ; /* memory fail */
child - > next = new_item ; new_item - > prev = child ; child = new_item ;
2016-03-19 21:41:44 +03:00
value = skip ( parse_value ( child , skip ( value + 1 ) , ep ) ) ;
2011-08-22 08:43:38 +04:00
if ( ! value ) return 0 ; /* memory fail */
}
if ( * value = = ' ] ' ) return value + 1 ; /* end of array */
2016-03-19 21:41:44 +03:00
* ep = value ; return 0 ; /* malformed. */
2011-08-22 08:43:38 +04:00
}
/* Render an array to text */
2015-02-09 20:34:35 +03:00
static char * print_array ( cJSON * item , int depth , int fmt , printbuffer * p )
2011-08-22 08:43:38 +04:00
{
char * * entries ;
char * out = 0 , * ptr , * ret ; int len = 5 ;
cJSON * child = item - > child ;
int numentries = 0 , i = 0 , fail = 0 ;
2015-02-09 20:28:26 +03:00
size_t tmplen = 0 ;
2011-08-22 08:43:38 +04:00
/* How many entries in the array? */
while ( child ) numentries + + , child = child - > next ;
2013-02-05 21:27:59 +04:00
/* Explicitly handle numentries==0 */
if ( ! numentries )
2009-08-26 07:55:20 +04:00
{
2015-02-09 20:34:35 +03:00
if ( p ) out = ensure ( p , 3 ) ;
else out = ( char * ) cJSON_malloc ( 3 ) ;
2013-02-05 21:27:59 +04:00
if ( out ) strcpy ( out , " [] " ) ;
return out ;
}
2011-08-22 08:43:38 +04:00
2015-02-09 20:34:35 +03:00
if ( p )
2011-08-22 08:43:38 +04:00
{
2015-02-09 20:34:35 +03:00
/* Compose the output array. */
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 ;
2011-08-22 08:43:38 +04:00
}
2015-02-09 20:34:35 +03:00
else
2011-08-22 08:43:38 +04:00
{
2015-02-09 20:34:35 +03:00
/* 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. */
if ( fail )
{
for ( i = 0 ; i < numentries ; i + + ) if ( entries [ i ] ) cJSON_free ( entries [ i ] ) ;
cJSON_free ( entries ) ;
return 0 ;
}
/* Compose the output array. */
* out = ' [ ' ;
ptr = out + 1 ; * ptr = 0 ;
for ( i = 0 ; i < numentries ; i + + )
{
2015-02-09 20:38:18 +03:00
tmplen = strlen ( entries [ i ] ) ; memcpy ( ptr , entries [ i ] , tmplen ) ; ptr + = tmplen ;
2015-02-09 20:34:35 +03:00
if ( i ! = numentries - 1 ) { * ptr + + = ' , ' ; if ( fmt ) * ptr + + = ' ' ; * ptr = 0 ; }
cJSON_free ( entries [ i ] ) ;
}
cJSON_free ( entries ) ;
* ptr + + = ' ] ' ; * ptr + + = 0 ;
2011-08-22 08:43:38 +04:00
}
return out ;
}
/* Build an object from the text. */
2016-03-19 21:41:44 +03:00
static const char * parse_object ( cJSON * item , const char * value , const char * * ep )
2011-08-22 08:43:38 +04:00
{
cJSON * child ;
2016-03-19 21:41:44 +03:00
if ( * value ! = ' { ' ) { * ep = value ; return 0 ; } /* not an object! */
2011-08-22 08:43:38 +04:00
item - > type = cJSON_Object ;
value = skip ( value + 1 ) ;
if ( * value = = ' } ' ) return value + 1 ; /* empty array. */
item - > child = child = cJSON_New_Item ( ) ;
if ( ! item - > child ) return 0 ;
2016-03-19 21:41:44 +03:00
value = skip ( parse_string ( child , skip ( value ) , ep ) ) ;
2011-08-22 08:43:38 +04:00
if ( ! value ) return 0 ;
child - > string = child - > valuestring ; child - > valuestring = 0 ;
2016-03-19 21:41:44 +03:00
if ( * value ! = ' : ' ) { * ep = value ; return 0 ; } /* fail! */
value = skip ( parse_value ( child , skip ( value + 1 ) , ep ) ) ; /* skip any spacing, get the value. */
2011-08-22 08:43:38 +04:00
if ( ! value ) return 0 ;
while ( * value = = ' , ' )
{
cJSON * new_item ;
if ( ! ( new_item = cJSON_New_Item ( ) ) ) return 0 ; /* memory fail */
child - > next = new_item ; new_item - > prev = child ; child = new_item ;
2016-03-19 21:41:44 +03:00
value = skip ( parse_string ( child , skip ( value + 1 ) , ep ) ) ;
2011-08-22 08:43:38 +04:00
if ( ! value ) return 0 ;
child - > string = child - > valuestring ; child - > valuestring = 0 ;
2016-03-19 21:41:44 +03:00
if ( * value ! = ' : ' ) { * ep = value ; return 0 ; } /* fail! */
value = skip ( parse_value ( child , skip ( value + 1 ) , ep ) ) ; /* skip any spacing, get the value. */
2011-08-22 08:43:38 +04:00
if ( ! value ) return 0 ;
}
if ( * value = = ' } ' ) return value + 1 ; /* end of array */
2016-03-19 21:41:44 +03:00
* ep = value ; return 0 ; /* malformed. */
2011-08-22 08:43:38 +04:00
}
/* Render an object to text. */
2015-02-09 20:34:35 +03:00
static char * print_object ( cJSON * item , int depth , int fmt , printbuffer * p )
2011-08-22 08:43:38 +04:00
{
char * * entries = 0 , * * names = 0 ;
char * out = 0 , * ptr , * ret , * str ; int len = 7 , i = 0 , j ;
cJSON * child = item - > child ;
int numentries = 0 , fail = 0 ;
2015-02-09 20:28:26 +03:00
size_t tmplen = 0 ;
2011-08-22 08:43:38 +04:00
/* Count the number of entries. */
while ( child ) numentries + + , child = child - > next ;
2013-02-05 21:27:59 +04:00
/* Explicitly handle empty object case */
if ( ! numentries )
{
2015-02-09 20:34:35 +03:00
if ( p ) out = ensure ( p , fmt ? depth + 4 : 3 ) ;
else out = ( char * ) cJSON_malloc ( fmt ? depth + 4 : 3 ) ;
2013-02-05 21:27:59 +04:00
if ( ! out ) return 0 ;
ptr = out ; * ptr + + = ' { ' ;
2015-10-26 04:43:44 +03:00
if ( fmt ) { * ptr + + = ' \n ' ; for ( i = 0 ; i < depth ; i + + ) * ptr + + = ' \t ' ; }
2013-02-05 21:27:59 +04:00
* ptr + + = ' } ' ; * ptr + + = 0 ;
return out ;
}
2015-02-09 20:34:35 +03:00
if ( p )
2011-08-22 08:43:38 +04:00
{
2015-02-09 20:34:35 +03:00
/* 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 ) ;
ptr = ensure ( p , len + 1 ) ; if ( ! ptr ) return 0 ;
if ( child - > next ) * ptr + + = ' , ' ;
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 ;
2011-08-22 08:43:38 +04:00
}
2015-02-09 20:34:35 +03:00
else
2011-08-22 08:43:38 +04:00
{
2015-02-09 20:34:35 +03:00
/* 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: */
child = item - > child ; depth + + ; if ( fmt ) len + = depth ;
2015-07-28 00:48:06 +03:00
while ( child & & ! fail )
2015-02-09 20:34:35 +03:00
{
names [ i ] = str = print_string_ptr ( child - > string , 0 ) ;
entries [ i + + ] = ret = print_value ( child , depth , fmt , 0 ) ;
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 */
if ( fail )
{
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 ) ;
return 0 ;
}
/* Compose the output: */
* out = ' { ' ; ptr = out + 1 ; if ( fmt ) * ptr + + = ' \n ' ; * ptr = 0 ;
for ( i = 0 ; i < numentries ; i + + )
{
if ( fmt ) for ( j = 0 ; j < depth ; j + + ) * ptr + + = ' \t ' ;
2015-02-09 20:38:18 +03:00
tmplen = strlen ( names [ i ] ) ; memcpy ( ptr , names [ i ] , tmplen ) ; ptr + = tmplen ;
2015-02-09 20:34:35 +03:00
* ptr + + = ' : ' ; if ( fmt ) * ptr + + = ' \t ' ;
strcpy ( ptr , entries [ i ] ) ; ptr + = strlen ( entries [ i ] ) ;
if ( i ! = numentries - 1 ) * ptr + + = ' , ' ;
if ( fmt ) * ptr + + = ' \n ' ; * ptr = 0 ;
cJSON_free ( names [ i ] ) ; cJSON_free ( entries [ i ] ) ;
}
2011-08-22 08:43:38 +04:00
cJSON_free ( names ) ; cJSON_free ( entries ) ;
2015-02-09 20:34:35 +03:00
if ( fmt ) for ( i = 0 ; i < depth - 1 ; i + + ) * ptr + + = ' \t ' ;
* ptr + + = ' } ' ; * ptr + + = 0 ;
2011-08-22 08:43:38 +04:00
}
return out ;
}
/* 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 ; }
2016-03-20 03:21:19 +03:00
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 ; }
int cJSON_HasObjectItem ( cJSON * object , const char * string ) { return cJSON_GetObjectItem ( object , string ) ? 1 : 0 ; }
2011-08-22 08:43:38 +04:00
/* Utility for array list handling. */
static void suffix_object ( cJSON * prev , cJSON * item ) { prev - > next = item ; item - > prev = prev ; }
/* 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 ; }
/* 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 ) ; } }
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 ) ; }
2015-02-09 20:34:35 +03:00
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 ) ; }
2011-08-22 08:43:38 +04:00
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 ( 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 ; }
void cJSON_DeleteItemFromArray ( cJSON * array , int which ) { cJSON_Delete ( cJSON_DetachItemFromArray ( array , which ) ) ; }
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 ; }
void cJSON_DeleteItemFromObject ( cJSON * object , const char * string ) { cJSON_Delete ( cJSON_DetachItemFromObject ( object , string ) ) ; }
/* Replace array/object items with new ones. */
2015-02-10 17:17:59 +03:00
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 ; }
newitem - > next = c ; newitem - > prev = c - > prev ; c - > prev = newitem ; if ( c = = array - > child ) array - > child = newitem ; else newitem - > prev - > next = newitem ; }
2011-08-22 08:43:38 +04:00
void cJSON_ReplaceItemInArray ( cJSON * array , int which , cJSON * newitem ) { cJSON * c = array - > child ; while ( c & & which > 0 ) c = c - > next , which - - ; if ( ! c ) return ;
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 ) ; } }
/* Create basic types: */
2013-02-05 21:00:31 +04:00
cJSON * cJSON_CreateNull ( void ) { cJSON * item = cJSON_New_Item ( ) ; if ( item ) item - > type = cJSON_NULL ; return item ; }
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 ; }
2011-08-22 08:43:38 +04:00
cJSON * cJSON_CreateBool ( int b ) { cJSON * item = cJSON_New_Item ( ) ; if ( item ) item - > type = b ? cJSON_True : cJSON_False ; return item ; }
cJSON * cJSON_CreateNumber ( double num ) { cJSON * item = cJSON_New_Item ( ) ; if ( item ) { item - > type = cJSON_Number ; item - > valuedouble = num ; item - > valueint = ( int ) num ; } return item ; }
2016-03-19 14:27:41 +03:00
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 ; }
2013-02-05 21:00:31 +04:00
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 ; }
2011-08-22 08:43:38 +04:00
/* Create Arrays: */
2016-03-19 14:27:41 +03:00
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 * 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 ; }
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 ; }
2013-02-05 22:23:22 +04:00
/* Duplication */
cJSON * cJSON_Duplicate ( cJSON * item , int recurse )
{
cJSON * newitem , * cptr , * nptr = 0 , * newchild ;
/* Bail on bad ptr */
if ( ! item ) return 0 ;
/* Create new item */
newitem = cJSON_New_Item ( ) ;
if ( ! newitem ) return 0 ;
/* Copy over all vars */
newitem - > type = item - > type & ( ~ cJSON_IsReference ) , newitem - > valueint = item - > valueint , newitem - > valuedouble = item - > valuedouble ;
2013-02-05 22:26:51 +04:00
if ( item - > valuestring ) { newitem - > valuestring = cJSON_strdup ( item - > valuestring ) ; if ( ! newitem - > valuestring ) { cJSON_Delete ( newitem ) ; return 0 ; } }
if ( item - > string ) { newitem - > string = cJSON_strdup ( item - > string ) ; if ( ! newitem - > string ) { cJSON_Delete ( newitem ) ; return 0 ; } }
2013-02-05 22:23:22 +04:00
/* If non-recursive, then we're done! */
if ( ! recurse ) return newitem ;
/* Walk the ->next chain for the child. */
cptr = item - > child ;
while ( cptr )
{
newchild = cJSON_Duplicate ( cptr , 1 ) ; /* Duplicate (with recurse) each item in the ->next chain */
2013-02-05 22:26:51 +04:00
if ( ! newchild ) { cJSON_Delete ( newitem ) ; return 0 ; }
2013-02-05 22:23:22 +04:00
if ( nptr ) { nptr - > next = newchild , newchild - > prev = nptr ; nptr = newchild ; } /* If newitem->child already set, then crosswire ->prev and ->next and move on */
else { newitem - > child = newchild ; nptr = newchild ; } /* Set newitem->child and move to it */
cptr = cptr - > next ;
}
return newitem ;
}
2013-08-14 16:58:13 +04:00
void cJSON_Minify ( char * json )
{
char * into = json ;
while ( * json )
{
if ( * json = = ' ' ) json + + ;
2015-01-30 17:06:14 +03:00
else if ( * json = = ' \t ' ) json + + ; /* Whitespace characters. */
2013-08-14 16:58:13 +04:00
else if ( * json = = ' \r ' ) json + + ;
else if ( * json = = ' \n ' ) json + + ;
2015-01-30 17:06:14 +03:00
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. */
2013-08-14 16:58:13 +04:00
}
2015-01-30 17:06:14 +03:00
* into = 0 ; /* and null-terminate. */
2014-05-21 07:03:20 +04:00
}