/*
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"
static const char * global_ep ;
const char * cJSON_GetErrorPtr ( void )
{
return global_ep ;
}
/* case insensitive strcmp */
static int cJSON_strcasecmp ( const char * s1 , const char * s2 )
{
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 ) ;
}
static void * ( * cJSON_malloc ) ( size_t sz ) = malloc ;
static void ( * cJSON_free ) ( void * ptr ) = free ;
static char * cJSON_strdup ( const char * str )
{
size_t len ;
char * copy ;
len = strlen ( str ) + 1 ;
if ( ! ( copy = ( char * ) cJSON_malloc ( len ) ) )
{
return 0 ;
}
memcpy ( copy , str , len ) ;
return copy ;
}
void cJSON_InitHooks ( cJSON_Hooks * hooks )
{
if ( ! hooks )
{
/* Reset hooks */
cJSON_malloc = malloc ;
cJSON_free = free ;
return ;
}
cJSON_malloc = ( hooks - > malloc_fn ) ? hooks - > malloc_fn : malloc ;
cJSON_free = ( hooks - > free_fn ) ? hooks - > free_fn : free ;
}
/* Internal constructor. */
static cJSON * cJSON_New_Item ( void )
{
cJSON * node = ( cJSON * ) cJSON_malloc ( sizeof ( cJSON ) ) ;
if ( node )
{
memset ( node , 0 , sizeof ( cJSON ) ) ;
}
return node ;
}
/* Delete a cJSON structure. */
void cJSON_Delete ( cJSON * c )
{
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 ;
}
}
/* Parse the input text to generate a number, and populate the result into item. */
static const char * parse_number ( cJSON * item , const char * num )
{
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 ;
}
/* 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 ;
}
typedef struct
{
char * buffer ;
int length ;
int offset ;
} printbuffer ;
/* realloc printbuffer if necessary to have at least "needed" bytes more */
static char * ensure ( printbuffer * p , int needed )
{
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 ;
}
/* calculate the new length of the string in a printbuffer */
static int update ( printbuffer * p )
{
char * str ;
if ( ! p | | ! p - > buffer )
{
return 0 ;
}
str = p - > buffer + p - > offset ;
return p - > offset + strlen ( str ) ;
}
/* Render the number nicely from the given item into a string. */
static char * print_number ( cJSON * item , printbuffer * p )
{
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 ;
}
/* parse 4 digit hexadecimal number */
static unsigned parse_hex4 ( const char * str )
{
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 ;
}
/* 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
} ;
/* Parse the input text into an unescaped cstring, and populate item. */
static const char * parse_string ( cJSON * item , const char * str , const char * * ep )
{
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 ;
}
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 + + ;
}
}
/* 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 ;
}
/* Render the cstring provided to an escaped version that can be printed. */
static char * print_string_ptr ( const char * str , printbuffer * p )
{
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 ;
}
/* 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 ) ;
}
/* Predeclare these prototypes. */
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 ) ;
/* Utility to jump whitespace and cr/lf */
static const char * skip ( const char * in )
{
while ( in & & * in & & ( ( unsigned char ) * in < = 32 ) )
{
in + + ;
}
return in ;
}
/* Parse an object - create a new root, and populate. */
cJSON * cJSON_ParseWithOpts ( const char * value , const char * * return_parse_end , int require_null_terminated )
{
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 ;
}
/* Default options for cJSON_Parse */
cJSON * cJSON_Parse ( const char * value )
{
return cJSON_ParseWithOpts ( value , 0 , 0 ) ;
}
/* Render a cJSON item/entity/structure to text. */
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 ) ;
}
/* Parser core - when encountering text, process appropriately. */
static const char * parse_value ( cJSON * item , const char * value , const char * * ep )
{
if ( ! value )
{
/* Fail on null. */
return 0 ;
}
/* parse the different types of values */
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 ;
}
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. */
}
/* Render a value to text. */
static char * print_value ( cJSON * item , int depth , int fmt , printbuffer * p )
{
char * out = 0 ;
if ( ! item )
{
return 0 ;
}
if ( p )
{
switch ( ( item - > type ) & 0xFF )
{
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
{
switch ( ( item - > type ) & 0xFF )
{
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 ;
}
}
return out ;
}
/* Build an array from input text. */
static const char * parse_array ( cJSON * item , const char * value , const char * * ep )
{
cJSON * child ;
if ( * value ! = ' [ ' )
{
/* not an array! */
* ep = value ;
return 0 ;
}
item - > type = cJSON_Array ;
value = skip ( value + 1 ) ;
if ( * value = = ' ] ' )
{
/* empty array. */
return value + 1 ;
}
item - > child = child = cJSON_New_Item ( ) ;
if ( ! item - > child )
{
/* memory fail */
return 0 ;
}
/* skip any spacing, get the value. */
value = skip ( parse_value ( child , skip ( value ) , ep ) ) ;
if ( ! value )
{
return 0 ;
}
/* loop through the comma separated array elements */
while ( * value = = ' , ' )
{
cJSON * new_item ;
if ( ! ( new_item = cJSON_New_Item ( ) ) )
{
/* memory fail */
return 0 ;
}
/* add new item to end of the linked list */
child - > next = new_item ;
new_item - > prev = child ;
child = new_item ;
/* go to the next comma */
value = skip ( parse_value ( child , skip ( value + 1 ) , ep ) ) ;
if ( ! value )
{
/* memory fail */
return 0 ;
}
}
if ( * value = = ' ] ' )
{
/* end of array */
return value + 1 ;
}
/* malformed. */
* ep = value ;
return 0 ;
}
/* Render an array to text */
static char * print_array ( cJSON * item , int depth , int fmt , printbuffer * p )
{
char * * entries ;
char * out = 0 ;
char * ptr ;
char * ret ;
int len = 5 ;
cJSON * child = item - > child ;
int numentries = 0 ;
int i = 0 ;
int 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 )
{
/* Compose the output array. */
/* opening square bracket */
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 pointers to all printed values */
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 )
{
/* free all the entries in the array */
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 + + )
{
tmplen = strlen ( entries [ i ] ) ;
memcpy ( ptr , entries [ i ] , tmplen ) ;
ptr + = tmplen ;
if ( i ! = ( numentries - 1 ) )
{
* ptr + + = ' , ' ;
if ( fmt )
{
* ptr + + = ' ' ;
}
* ptr = 0 ;
}
cJSON_free ( entries [ i ] ) ;
}
cJSON_free ( entries ) ;
* ptr + + = ' ] ' ;
* ptr + + = ' \0 ' ;
}
return out ;
}
/* Build an object from the text. */
static const char * parse_object ( cJSON * item , const char * value , const char * * ep )
{
cJSON * child ;
if ( * value ! = ' { ' )
{
/* not an object! */
* ep = value ;
return 0 ;
}
item - > type = cJSON_Object ;
value = skip ( value + 1 ) ;
if ( * value = = ' } ' )
{
/* empty object. */
return value + 1 ;
}
child = cJSON_New_Item ( ) ;
item - > child = child ;
if ( ! item - > child )
{
return 0 ;
}
/* parse first key */
value = skip ( parse_string ( child , skip ( value ) , ep ) ) ;
if ( ! value )
{
return 0 ;
}
/* use string as key, not value */
child - > string = child - > valuestring ;
child - > valuestring = 0 ;
if ( * value ! = ' : ' )
{
/* invalid object. */
* ep = value ;
return 0 ;
}
/* skip any spacing, get the value. */
value = skip ( parse_value ( child , skip ( value + 1 ) , ep ) ) ;
if ( ! value )
{
return 0 ;
}
while ( * value = = ' , ' )
{
cJSON * new_item ;
if ( ! ( new_item = cJSON_New_Item ( ) ) )
{
/* memory fail */
return 0 ;
}
/* add to linked list */
child - > next = new_item ;
new_item - > prev = child ;
child = new_item ;
value = skip ( parse_string ( child , skip ( value + 1 ) , ep ) ) ;
if ( ! value )
{
return 0 ;
}
/* use string as key, not value */
child - > string = child - > valuestring ;
child - > valuestring = 0 ;
if ( * value ! = ' : ' )
{
/* invalid object. */
* ep = value ;
return 0 ;
}
/* skip any spacing, get the value. */
value = skip ( parse_value ( child , skip ( value + 1 ) , ep ) ) ;
if ( ! value )
{
return 0 ;
}
}
/* end of object */
if ( * value = = ' } ' )
{
return value + 1 ;
}
/* malformed */
* ep = value ;
return 0 ;
}
/* Render an object to text. */
static char * print_object ( cJSON * item , int depth , int fmt , printbuffer * p )
{
char * * entries = 0 ;
char * * names = 0 ;
char * out = 0 ;
char * ptr ;
char * ret ;
char * str ;
int len = 7 ;
int i = 0 ;
int j ;
cJSON * child = item - > child ;
int numentries = 0 ;
int 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 ; /* fmt: {\n */
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 key */
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 */
print_value ( child , depth , fmt , p ) ;
p - > offset = update ( p ) ;
/* print comma if not last */
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 ;
}
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: */
child = item - > child ;
depth + + ;
if ( fmt )
{
len + = depth ;
}
while ( child & & ! fail )
{
names [ i ] = str = print_string_ptr ( child - > string , 0 ) ; /* print key */
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 )
{
/* free all the printed keys and values */
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 ' ;
}
}
tmplen = strlen ( names [ i ] ) ;
memcpy ( ptr , names [ i ] , tmplen ) ;
ptr + = tmplen ;
* 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 ] ) ;
}
cJSON_free ( names ) ;
cJSON_free ( entries ) ;
if ( fmt )
{
for ( i = 0 ; i < ( depth - 1 ) ; i + + )
{
* ptr + + = ' \t ' ;
}
}
* ptr + + = ' } ' ;
* ptr + + = ' \0 ' ;
}
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 ;
}
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 ;
}
/* 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 )
{
/* list is empty, start new one */
array - > child = item ;
}
else
{
/* append to the end */
while ( c & & c - > next )
{
c = c - > next ;
}
suffix_object ( c , item ) ;
}
}
void cJSON_AddItemToObject ( cJSON * object , const char * string , cJSON * item )
{
if ( ! item )
{
return ;
}
/* free old key and set new one */
if ( item - > string )
{
cJSON_free ( item - > string ) ;
}
item - > string = cJSON_strdup ( string ) ;
cJSON_AddItemToArray ( object , item ) ;
}
/* Add an item to an object with constant string as key */
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 ) ;
}
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. */
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 ; }
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: */
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 ; }
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 ; }
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 ; }
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 ; }
/* 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 * 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 ; }
/* 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 ;
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 ; } }
/* 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 */
if ( ! newchild ) { cJSON_Delete ( newitem ) ; return 0 ; }
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 ;
}
void cJSON_Minify ( char * json )
{
char * into = json ;
while ( * json )
{
if ( * json = = ' ' ) json + + ;
else if ( * json = = ' \t ' ) json + + ; /* Whitespace characters. */
else if ( * json = = ' \r ' ) json + + ;
else if ( * json = = ' \n ' ) json + + ;
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. */
}
* into = 0 ; /* and null-terminate. */
}