xref: /iperf/src/cjson.c (revision 5cd3317d)
1 /*
2   Copyright (c) 2009 Dave Gamble
3 
4   Permission is hereby granted, free of charge, to any person obtaining a copy
5   of this software and associated documentation files (the "Software"), to deal
6   in the Software without restriction, including without limitation the rights
7   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8   copies of the Software, and to permit persons to whom the Software is
9   furnished to do so, subject to the following conditions:
10 
11   The above copyright notice and this permission notice shall be included in
12   all copies or substantial portions of the Software.
13 
14   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20   THE SOFTWARE.
21 */
22 
23 /* cJSON */
24 /* JSON parser in C. */
25 
26 #include <string.h>
27 #include <stdio.h>
28 #include <math.h>
29 #include <stdlib.h>
30 #include <float.h>
31 #include <limits.h>
32 #include <ctype.h>
33 #include <sys/types.h>
34 #include "cjson.h"
35 
36 
37 static const char *ep;
38 
39 const char *cJSON_GetErrorPtr( void )
40 {
41 	return ep;
42 }
43 
44 
45 static int cJSON_strcasecmp( const char *s1, const char *s2 )
46 {
47 	if ( ! s1 )
48 		return ( s1 == s2 ) ? 0 : 1;
49 	if ( ! s2 )
50 		return 1;
51 	for ( ; tolower(*s1) == tolower(*s2); ++s1, ++s2)
52 		if( *s1 == 0 )
53 			return 0;
54 	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
55 }
56 
57 
58 static void *(*cJSON_malloc)( size_t ) = malloc;
59 static void (*cJSON_free)( void * ) = free;
60 
61 void cJSON_InitHooks(cJSON_Hooks* hooks)
62 {
63 	if ( ! hooks ) {
64 		/* Reset hooks. */
65 		cJSON_malloc = malloc;
66 		cJSON_free = free;
67 		return;
68 	}
69 	cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
70 	cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
71 }
72 
73 
74 static char* cJSON_strdup( const char* str )
75 {
76 	size_t len;
77 	char* copy;
78 
79 	len = strlen( str ) + 1;
80 	if ( ! ( copy = (char*) cJSON_malloc( len ) ) )
81 		return 0;
82 	memcpy( copy, str, len );
83 	return copy;
84 }
85 
86 
87 /* Internal constructor. */
88 static cJSON *cJSON_New_Item( void )
89 {
90 	cJSON* node = (cJSON*) cJSON_malloc( sizeof(cJSON) );
91 	if ( node )
92 		memset( node, 0, sizeof(cJSON) );
93 	return node;
94 }
95 
96 
97 /* Delete a cJSON structure. */
98 void cJSON_Delete( cJSON *c )
99 {
100 	cJSON *next;
101 
102 	while ( c ) {
103 		next = c->next;
104 		if ( ! ( c->type & cJSON_IsReference ) && c->child )
105 			cJSON_Delete( c->child );
106 		if ( ! ( c->type & cJSON_IsReference ) && c->valuestring )
107 			cJSON_free( c->valuestring );
108 		if ( c->string )
109 			cJSON_free( c->string );
110 		cJSON_free( c );
111 		c = next;
112 	}
113 }
114 
115 
116 static double ipow( double n, int exp )
117 {
118 	double r;
119 
120 	if ( exp < 0 )
121 		return 1.0 / ipow( n, -exp );
122 	r = 1;
123 	while ( exp > 0 ) {
124 		if ( exp & 1 )
125 			r *= n;
126 		exp >>= 1;
127 		n *= n;
128 	}
129 	return r;
130 }
131 
132 
133 /* Parse the input text to generate a number, and populate the result into item. */
134 static const char *parse_number( cJSON *item, const char *num )
135 {
136 	int64_t i = 0;
137 	double f = 0;
138 	int isint = 1;
139 	int sign = 1, scale = 0, subscale = 0, signsubscale = 1;
140 
141 	/* Could use sscanf for this? */
142 	if ( *num == '-' ) {
143 		/* Has sign. */
144 		sign = -1;
145 		++num;
146 	}
147 	if ( *num == '0' )
148 		/* Is zero. */
149 		++num;
150 	if ( *num >= '1' && *num<='9' ) {
151 		/* Number. */
152 		do {
153 			i = ( i * 10 ) + ( *num - '0' );
154 			f = ( f * 10.0 ) + ( *num - '0' );
155 			++num;
156 		} while ( *num >= '0' && *num <= '9' );
157 	}
158 	if ( *num == '.' && num[1] >= '0' && num[1] <= '9' ) {
159 		/* Fractional part. */
160 		isint = 0;
161 		++num;
162 		do {
163 			f = ( f * 10.0 ) + ( *num++ - '0' );
164 			scale--;
165 		} while ( *num >= '0' && *num <= '9' );
166 	}
167 	if ( *num == 'e' || *num == 'E' ) {
168 		/* Exponent. */
169 		isint = 0;
170 		++num;
171 		if ( *num == '+' )
172 			++num;
173 		else if ( *num == '-' ) {
174 			/* With sign. */
175 			signsubscale = -1;
176 			++num;
177 		}
178 		while ( *num >= '0' && *num <= '9' )
179 			subscale = ( subscale * 10 ) + ( *num++ - '0' );
180 	}
181 
182 	/* Put it together. */
183 	if ( isint ) {
184 	    /* Int: number = +/- number */
185 	    i = sign * i;
186 	    item->valueint = i;
187 	    item->valuefloat = i;
188 	} else {
189 	    /* Float: number = +/- number.fraction * 10^+/- exponent */
190 	    f = sign * f * ipow( 10.0, scale + subscale * signsubscale );
191 	    item->valueint = f;
192 	    item->valuefloat = f;
193 	}
194 
195 	item->type = cJSON_Number;
196 	return num;
197 }
198 
199 
200 /* Render the number nicely from the given item into a string. */
201 static char *print_number( cJSON *item )
202 {
203 	char *str;
204 	double d = item->valuefloat;
205 	if ( fabs( ( (double) item->valueint ) - d ) <= DBL_EPSILON && d <= INT_MAX && d >= INT_MIN ) {
206 		str = (char*) cJSON_malloc( 21 );	/* 2^64+1 can be represented in 21 chars. */
207 		if ( str )
208 			sprintf( str, "%lld", (long long int) item->valueint );
209 	} else {
210 		str = (char*) cJSON_malloc( 64 );	/* This is a nice tradeoff. */
211 		if ( str ) {
212 			if ( fabs( floor( d ) - d ) <= DBL_EPSILON )
213 				sprintf( str, "%.0f", d );
214 			else if ( fabs( d ) < 1.0e-6 || fabs( d ) > 1.0e9 )
215 				sprintf( str, "%e", d );
216 			else
217 				sprintf( str, "%f", d );
218 		}
219 	}
220 	return str;
221 }
222 
223 
224 /* Parse the input text into an unescaped cstring, and populate item. */
225 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
226 
227 static const char *parse_string( cJSON *item, const char *str )
228 {
229 	const char *ptr = str + 1;
230 	char *ptr2;
231 	char *out;
232 	int len = 0;
233 	unsigned uc, uc2;
234 
235 	if ( *str != '\"' ) {
236 		/* Not a string! */
237 		ep = str;
238 		return 0;
239 	}
240 
241 	/* Skip escaped quotes. */
242 	while ( *ptr != '\"' && *ptr && ++len )
243 		if ( *ptr++ == '\\' )
244 			ptr++;
245 
246 	if ( ! ( out = (char*) cJSON_malloc( len + 1 ) ) )
247 		return 0;
248 
249 	ptr = str + 1;
250 	ptr2 = out;
251 	while ( *ptr != '\"' && *ptr ) {
252 		if ( *ptr != '\\' )
253 			*ptr2++ = *ptr++;
254 		else {
255 			ptr++;
256 			switch ( *ptr ) {
257 				case 'b': *ptr2++ ='\b'; break;
258 				case 'f': *ptr2++ ='\f'; break;
259 				case 'n': *ptr2++ ='\n'; break;
260 				case 'r': *ptr2++ ='\r'; break;
261 				case 't': *ptr2++ ='\t'; break;
262 				case 'u':
263 					/* Transcode utf16 to utf8. */
264 					/* Get the unicode char. */
265 					sscanf( ptr + 1,"%4x", &uc );
266 					ptr += 4;
267 					/* Check for invalid. */
268 					if ( ( uc >= 0xDC00 && uc <= 0xDFFF ) || uc == 0 )
269 						break;
270 
271 					/* UTF16 surrogate pairs. */
272 					if ( uc >= 0xD800 && uc <= 0xDBFF ) {
273 						if ( ptr[1] != '\\' || ptr[2] != 'u' )
274 							/* Missing second-half of surrogate. */
275 							break;
276 						sscanf( ptr + 3, "%4x", &uc2 );
277 						ptr += 6;
278 						if ( uc2 < 0xDC00 || uc2 > 0xDFFF )
279 							/* Invalid second-half of surrogate. */
280 							break;
281 						uc = 0x10000 | ( ( uc & 0x3FF ) << 10 ) | ( uc2 & 0x3FF );
282 					}
283 
284 					len = 4;
285 					if ( uc < 0x80 )
286 						len = 1;
287 					else if ( uc < 0x800 )
288 						len = 2;
289 					else if ( uc < 0x10000 )
290 						len = 3;
291 					ptr2 += len;
292 
293 					switch ( len ) {
294 						case 4: *--ptr2 = ( ( uc | 0x80) & 0xBF ); uc >>= 6;
295 						case 3: *--ptr2 = ( ( uc | 0x80) & 0xBF ); uc >>= 6;
296 						case 2: *--ptr2 = ( ( uc | 0x80) & 0xBF ); uc >>= 6;
297 						case 1: *--ptr2 = ( uc | firstByteMark[len] );
298 					}
299 					ptr2 += len;
300 					break;
301 				default:  *ptr2++ = *ptr; break;
302 			}
303 			++ptr;
304 		}
305 	}
306 	*ptr2 = 0;
307 	if ( *ptr == '\"' )
308 		++ptr;
309 	item->valuestring = out;
310 	item->type = cJSON_String;
311 	return ptr;
312 }
313 
314 
315 /* Render the cstring provided to an escaped version that can be printed. */
316 static char *print_string_ptr( const char *str )
317 {
318 	const char *ptr;
319 	char *ptr2, *out;
320 	int len = 0;
321 	unsigned char token;
322 
323 	if ( ! str )
324 		return cJSON_strdup( "" );
325 	ptr = str;
326 	while ( ( token = *ptr ) && ++len ) {
327 		if ( strchr( "\"\\\b\f\n\r\t", token ) )
328 			++len;
329 		else if ( token < 32 )
330 			len += 5;
331 		++ptr;
332 	}
333 
334 	if ( ! ( out = (char*) cJSON_malloc( len + 3 ) ) )
335 		return 0;
336 
337 	ptr2 = out;
338 	ptr = str;
339 	*ptr2++ = '\"';
340 	while ( *ptr ) {
341 		if ( (unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\' )
342 			*ptr2++ = *ptr++;
343 		else {
344 			*ptr2++ = '\\';
345 			switch ( token = *ptr++ ) {
346 				case '\\': *ptr2++ = '\\'; break;
347 				case '\"': *ptr2++ = '\"'; break;
348 				case '\b': *ptr2++ = 'b'; break;
349 				case '\f': *ptr2++ = 'f'; break;
350 				case '\n': *ptr2++ = 'n'; break;
351 				case '\r': *ptr2++ = 'r'; break;
352 				case '\t': *ptr2++ = 't'; break;
353 				default:
354 				/* Escape and print. */
355 				sprintf( ptr2, "u%04x", token );
356 				ptr2 += 5;
357 				break;
358 			}
359 		}
360 	}
361 	*ptr2++ = '\"';
362 	*ptr2++ = 0;
363 	return out;
364 }
365 
366 
367 /* Invote print_string_ptr (which is useful) on an item. */
368 static char *print_string( cJSON *item )
369 {
370 	return print_string_ptr( item->valuestring );
371 }
372 
373 
374 /* Predeclare these prototypes. */
375 static const char *parse_value( cJSON *item, const char *value );
376 static char *print_value( cJSON *item, int depth, int fmt );
377 static const char *parse_array( cJSON *item, const char *value );
378 static char *print_array( cJSON *item, int depth, int fmt );
379 static const char *parse_object( cJSON *item, const char *value );
380 static char *print_object( cJSON *item, int depth, int fmt );
381 
382 /* Utility to jump whitespace and cr/lf. */
383 static const char *skip( const char *in )
384 {
385 	while ( in && *in && (unsigned char) *in <= 32 )
386 		in++;
387 	return in;
388 }
389 
390 
391 /* Parse an object - create a new root, and populate. */
392 cJSON *cJSON_Parse( const char *value )
393 {
394 	cJSON *c;
395 	ep = 0;
396 	if ( ! ( c = cJSON_New_Item() ) )
397 		return 0;       /* memory fail */
398 
399 	if ( ! parse_value( c, skip( value ) ) ) {
400 		cJSON_Delete( c );
401 		return 0;
402 	}
403 	return c;
404 }
405 
406 
407 /* Render a cJSON item/entity/structure to text. */
408 char *cJSON_Print( cJSON *item )
409 {
410 	return print_value( item, 0, 1 );
411 }
412 char *cJSON_PrintUnformatted( cJSON *item )
413 {
414 	return print_value( item, 0, 0 );
415 }
416 
417 
418 /* Parser core - when encountering text, process appropriately. */
419 static const char *parse_value( cJSON *item, const char *value )
420 {
421 	if ( ! value )
422 		return 0;	/* Fail on null. */
423 	if ( ! strncmp( value, "null", 4 ) ) {
424 		item->type = cJSON_NULL;
425 		return value + 4;
426 	}
427 	if ( ! strncmp( value, "false", 5 ) ) {
428 		item->type = cJSON_False;
429 		return value + 5;
430 	}
431 	if ( ! strncmp( value, "true", 4 ) ) {
432 		item->type = cJSON_True;
433 		item->valueint = 1;
434 		return value + 4;
435 	}
436 	if ( *value == '\"' )
437 		return parse_string( item, value );
438 	if ( *value == '-' || ( *value >= '0' && *value <= '9' ) )
439 		return parse_number( item, value );
440 	if ( *value == '[' )
441 		return parse_array( item, value );
442 	if ( *value == '{' )
443 		return parse_object( item, value );
444 
445 	/* Fail. */
446 	ep = value;
447 	return 0;
448 }
449 
450 
451 /* Render a value to text. */
452 static char *print_value( cJSON *item, int depth, int fmt )
453 {
454 	char *out = 0;
455 
456 	if ( ! item )
457 		return 0;
458 	switch ( ( item->type ) & 255 ) {
459 		case cJSON_NULL:   out = cJSON_strdup( "null" ); break;
460 		case cJSON_False:  out = cJSON_strdup( "false" ); break;
461 		case cJSON_True:   out = cJSON_strdup( "true" ); break;
462 		case cJSON_Number: out = print_number( item ); break;
463 		case cJSON_String: out = print_string( item ); break;
464 		case cJSON_Array:  out = print_array( item, depth, fmt ); break;
465 		case cJSON_Object: out = print_object( item, depth, fmt ); break;
466 	}
467 	return out;
468 }
469 
470 
471 /* Build an array from input text. */
472 static const char *parse_array( cJSON *item, const char *value )
473 {
474 	cJSON *child;
475 
476 	if ( *value != '[' ) {
477 		/* Not an array! */
478 		ep = value;
479 		return 0;
480 	}
481 
482 	item->type = cJSON_Array;
483 	value = skip( value + 1 );
484 	if ( *value == ']' )
485 		return value + 1;	/* empty array. */
486 
487 	if ( ! ( item->child = child = cJSON_New_Item() ) )
488 		return 0;		 /* memory fail */
489 	if ( ! ( value = skip( parse_value( child, skip( value ) ) ) ) )
490 		return 0;
491 
492 	while ( *value == ',' ) {
493 		cJSON *new_item;
494 		if ( ! ( new_item = cJSON_New_Item() ) )
495 			return 0;	/* memory fail */
496 		child->next = new_item;
497 		new_item->prev = child;
498 		child = new_item;
499 		if ( ! ( value = skip( parse_value( child, skip( value+1 ) ) ) ) )
500 			return 0;	/* memory fail */
501 	}
502 
503 	if ( *value == ']' )
504 		return value + 1;	/* end of array */
505 	/* Malformed. */
506 	ep = value;
507 	return 0;
508 }
509 
510 
511 /* Render an array to text */
512 static char *print_array( cJSON *item, int depth, int fmt )
513 {
514 	char **entries;
515 	char *out = 0, *ptr, *ret;
516 	int len = 5;
517 	cJSON *child = item->child;
518 	int numentries = 0, i = 0, fail = 0;
519 
520 	/* How many entries in the array? */
521 	while ( child ) {
522 		++numentries;
523 		child = child->next;
524 	}
525 	/* Allocate an array to hold the values for each. */
526 	if ( ! ( entries = (char**) cJSON_malloc( numentries * sizeof(char*) ) ) )
527 		return 0;
528 	memset( entries, 0, numentries * sizeof(char*) );
529 	/* Retrieve all the results. */
530 	child = item->child;
531 	while ( child && ! fail ) {
532 		ret = print_value( child, depth + 1, fmt );
533 		entries[i++] = ret;
534 		if ( ret )
535 			len += strlen( ret ) + 2 + ( fmt ? 1 : 0 );
536 		else
537 			fail = 1;
538 		child = child -> next;
539 	}
540 
541 	/* If we didn't fail, try to malloc the output string. */
542 	if ( ! fail ) {
543 		out = (char*) cJSON_malloc( len );
544 		if ( ! out )
545 			fail = 1;
546 	}
547 
548 	/* Handle failure. */
549 	if ( fail ) {
550 		for ( i = 0; i < numentries; ++i )
551 			if ( entries[i] )
552 				cJSON_free( entries[i] );
553 		cJSON_free( entries );
554 		return 0;
555 	}
556 
557 	/* Compose the output array. */
558 	*out = '[';
559 	ptr = out + 1;
560 	*ptr = 0;
561 	for ( i = 0; i < numentries; ++i ) {
562 		strcpy( ptr, entries[i] );
563 		ptr += strlen( entries[i] );
564 		if ( i != numentries - 1 ) {
565 			*ptr++ = ',';
566 			if ( fmt )
567 				*ptr++ = ' ';
568 			*ptr = 0;
569 		}
570 		cJSON_free( entries[i] );
571 	}
572 	cJSON_free( entries );
573 	*ptr++ = ']';
574 	*ptr++ = 0;
575 	return out;
576 }
577 
578 
579 /* Build an object from the text. */
580 static const char *parse_object( cJSON *item, const char *value )
581 {
582 	cJSON *child;
583 
584 	if ( *value != '{' ) {
585 		/* Not an object! */
586 		ep = value;
587 		return 0;
588 	}
589 
590 	item->type = cJSON_Object;
591 	value =skip( value + 1 );
592 	if ( *value == '}' )
593 		return value + 1;	/* empty array. */
594 
595 	if ( ! ( item->child = child = cJSON_New_Item() ) )
596 		return 0;
597 	if ( ! ( value = skip( parse_string( child, skip( value ) ) ) ) )
598 		return 0;
599 	child->string = child->valuestring;
600 	child->valuestring = 0;
601 	if ( *value != ':' ) {
602 		/* Fail! */
603 		ep = value;
604 		return 0;
605 	}
606 	if ( ! ( value = skip( parse_value( child, skip( value + 1 ) ) ) ) )
607 		return 0;
608 
609 	while ( *value == ',' ) {
610 		cJSON *new_item;
611 		if ( ! ( new_item = cJSON_New_Item() ) )
612 			return 0;	/* memory fail */
613 		child->next = new_item;
614 		new_item->prev = child;
615 		child = new_item;
616 		if ( ! ( value = skip( parse_string( child, skip( value + 1 ) ) ) ) )
617 			return 0;
618 		child->string = child->valuestring;
619 		child->valuestring = 0;
620 		if ( *value != ':' ) {
621 			/* Fail! */
622 			ep = value;
623 			return 0;
624 		}
625 		if ( ! ( value = skip( parse_value( child, skip( value + 1 ) ) ) ) )
626 			return 0;
627 	}
628 
629 	if ( *value == '}' )
630 		return value + 1;	/* end of array */
631 	/* Malformed. */
632 	ep = value;
633 	return 0;
634 }
635 
636 
637 /* Render an object to text. */
638 static char *print_object( cJSON *item, int depth, int fmt )
639 {
640 	char **entries = 0, **names = 0;
641 	char *out = 0, *ptr, *ret, *str;
642 	int len = 7, i = 0, j;
643 	cJSON *child = item->child;
644 	int numentries = 0, fail = 0;
645 
646 	/* Count the number of entries. */
647 	while ( child ) {
648 		++numentries;
649 		child = child->next;
650 	}
651 	/* Allocate space for the names and the objects. */
652 	if ( ! ( entries = (char**) cJSON_malloc( numentries * sizeof(char*) ) ) )
653 		return 0;
654 	if ( ! ( names = (char**) cJSON_malloc( numentries * sizeof(char*) ) ) ) {
655 		cJSON_free( entries );
656 		return 0;
657 	}
658 	memset( entries, 0, sizeof(char*) * numentries );
659 	memset( names, 0, sizeof(char*) * numentries );
660 
661 	/* Collect all the results into our arrays. */
662 	child = item->child;
663 	++depth;
664 	if ( fmt )
665 		len += depth;
666 	while ( child ) {
667 		names[i] = str = print_string_ptr( child->string );
668 		entries[i++] = ret = print_value( child, depth, fmt );
669 		if ( str && ret )
670 			len += strlen( ret ) + strlen( str ) + 2 + ( fmt ? 2 + depth : 0 );
671 		else
672 			fail = 1;
673 		child = child->next;
674 	}
675 
676 	/* Try to allocate the output string. */
677 	if ( ! fail ) {
678 		out = (char*) cJSON_malloc( len );
679 		if ( ! out )
680 			fail = 1;
681 	}
682 
683 	/* Handle failure. */
684 	if ( fail ) {
685 		for ( i = 0; i < numentries; ++i ) {
686 			if ( names[i] )
687 				cJSON_free( names[i] );
688 			if ( entries[i] )
689 				cJSON_free( entries[i] );
690 		}
691 		cJSON_free( names );
692 		cJSON_free( entries );
693 		return 0;
694 	}
695 
696 	/* Compose the output. */
697 	*out = '{';
698 	ptr = out + 1;
699 	if ( fmt )
700 		*ptr++ = '\n';
701 	*ptr = 0;
702 	for ( i = 0; i < numentries; ++i ) {
703 		if ( fmt )
704 			for ( j = 0; j < depth; ++j )
705 				*ptr++ = '\t';
706 		strcpy( ptr, names[i] );
707 		ptr += strlen( names[i] );
708 		*ptr++ = ':';
709 		if ( fmt )
710 			*ptr++ = '\t';
711 		strcpy( ptr, entries[i] );
712 		ptr += strlen( entries[i] );
713 		if ( i != numentries - 1 )
714 			*ptr++ = ',';
715 		if ( fmt )
716 			*ptr++ = '\n';
717 		*ptr = 0;
718 		cJSON_free( names[i] );
719 		cJSON_free( entries[i] );
720 	}
721 
722 	cJSON_free( names );
723 	cJSON_free( entries );
724 	if ( fmt )
725 		for ( i = 0; i < depth - 1; ++i )
726 			*ptr++ = '\t';
727 	*ptr++ = '}';
728 	*ptr++ = 0;
729 	return out;
730 }
731 
732 
733 int cJSON_GetArraySize( cJSON *array )
734 {
735 	cJSON *c = array->child;
736 	int i = 0;
737 	while ( c ) {
738 		++i;
739 		c = c->next;
740 	}
741 	return i;
742 }
743 
744 
745 cJSON *cJSON_GetArrayItem( cJSON *array, int item )
746 {
747 	cJSON *c = array->child;
748 	while ( c && item > 0 ) {
749 		--item;
750 		c = c->next;
751 	}
752 	return c;
753 }
754 
755 
756 cJSON *cJSON_GetObjectItem( cJSON *object, const char *string )
757 {
758 	cJSON *c = object->child;
759 	while ( c && cJSON_strcasecmp( c->string, string ) )
760 		c = c->next;
761 	return c;
762 }
763 
764 
765 /* Utility for array list handling. */
766 static void suffix_object( cJSON *prev, cJSON *item )
767 {
768 	prev->next = item;
769 	item->prev = prev;
770 }
771 
772 
773 /* Utility for handling references. */
774 static cJSON *create_reference( cJSON *item )
775 {
776 	cJSON *ref;
777 	if ( ! ( ref = cJSON_New_Item() ) )
778 		return 0;
779 	memcpy( ref, item, sizeof(cJSON) );
780 	ref->string = 0;
781 	ref->type |= cJSON_IsReference;
782 	ref->next = ref->prev = 0;
783 	return ref;
784 }
785 
786 
787 /* Add item to array/object. */
788 void cJSON_AddItemToArray( cJSON *array, cJSON *item )
789 {
790 	cJSON *c = array->child;
791 	if ( ! item )
792 		return;
793 	if ( ! c ) {
794 		array->child = item;
795 	} else {
796 		while ( c && c->next )
797 			c = c->next;
798 		suffix_object( c, item );
799 	}
800 }
801 
802 void cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item )
803 {
804 	if ( ! item )
805 		return;
806 	if ( item->string )
807 		cJSON_free( item->string );
808 	item->string = cJSON_strdup( string );
809 	cJSON_AddItemToArray( object, item );
810 }
811 
812 void cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item )
813 {
814 	cJSON_AddItemToArray( array, create_reference( item ) );
815 }
816 
817 void cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item )
818 {
819 	cJSON_AddItemToObject( object, string, create_reference( item ) );
820 }
821 
822 cJSON *cJSON_DetachItemFromArray( cJSON *array, int which )
823 {
824 	cJSON *c = array->child;
825 	while ( c && which > 0 ) {
826 		c = c->next;
827 		--which;
828 	}
829 	if ( ! c )
830 		return 0;
831 	if ( c->prev )
832 		c->prev->next = c->next;
833 	if ( c->next ) c->next->prev = c->prev;
834 	if ( c == array->child )
835 		array->child = c->next;
836 	c->prev = c->next = 0;
837 	return c;
838 }
839 
840 void cJSON_DeleteItemFromArray( cJSON *array, int which )
841 {
842 	cJSON_Delete( cJSON_DetachItemFromArray( array, which ) );
843 }
844 
845 cJSON *cJSON_DetachItemFromObject( cJSON *object, const char *string )
846 {
847 	int i = 0;
848 	cJSON *c = object->child;
849 	while ( c && cJSON_strcasecmp( c->string, string ) ) {
850 		++i;
851 		c = c->next;
852 	}
853 	if ( c )
854 		return cJSON_DetachItemFromArray( object, i );
855 	return 0;
856 }
857 
858 void cJSON_DeleteItemFromObject( cJSON *object, const char *string )
859 {
860 	cJSON_Delete( cJSON_DetachItemFromObject( object, string ) );
861 }
862 
863 /* Replace array/object items with new ones. */
864 void cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem )
865 {
866 	cJSON *c = array->child;
867 	while ( c && which > 0 ) {
868 		c = c->next;
869 		--which;
870 	}
871 	if ( ! c )
872 		return;
873 	newitem->next = c->next;
874 	newitem->prev = c->prev;
875 	if ( newitem->next )
876 		newitem->next->prev = newitem;
877 	if ( c == array->child )
878 		array->child = newitem;
879 	else
880 		newitem->prev->next = newitem;
881 	c->next = c->prev = 0;
882 	cJSON_Delete( c );
883 }
884 
885 void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem )
886 {
887 	int i = 0;
888 	cJSON *c = object->child;
889 	while ( c && cJSON_strcasecmp( c->string, string ) ) {
890 		++i;
891 		c = c->next;
892 	}
893 	if ( c ) {
894 		newitem->string = cJSON_strdup( string );
895 		cJSON_ReplaceItemInArray( object, i, newitem );
896 	}
897 }
898 
899 
900 /* Create basic types: */
901 
902 cJSON *cJSON_CreateNull( void )
903 {
904 	cJSON *item = cJSON_New_Item();
905 	if ( item )
906 		item->type = cJSON_NULL;
907 	return item;
908 }
909 
910 cJSON *cJSON_CreateTrue( void )
911 {
912 	cJSON *item = cJSON_New_Item();
913 	if ( item )
914 		item->type = cJSON_True;
915 	return item;
916 }
917 
918 cJSON *cJSON_CreateFalse( void )
919 {
920 	cJSON *item = cJSON_New_Item();
921 	if ( item )
922 		item->type = cJSON_False;
923 	return item;
924 }
925 
926 cJSON *cJSON_CreateBool( int b )
927 {
928 	cJSON *item = cJSON_New_Item();
929 	if ( item )
930 		item->type = b ? cJSON_True : cJSON_False;
931 	return item;
932 }
933 
934 cJSON *cJSON_CreateInt( int64_t num )
935 {
936 	cJSON *item = cJSON_New_Item();
937 	if ( item ) {
938 		item->type = cJSON_Number;
939 		item->valuefloat = num;
940 		item->valueint = num;
941 	}
942 	return item;
943 }
944 
945 cJSON *cJSON_CreateFloat( double num )
946 {
947 	cJSON *item = cJSON_New_Item();
948 	if ( item ) {
949 		item->type = cJSON_Number;
950 		item->valuefloat = num;
951 		item->valueint = num;
952 	}
953 	return item;
954 }
955 
956 cJSON *cJSON_CreateString( const char *string )
957 {
958 	cJSON *item = cJSON_New_Item();
959 	if ( item ) {
960 		item->type = cJSON_String;
961 		item->valuestring = cJSON_strdup( string );
962 	}
963 	return item;
964 }
965 
966 cJSON *cJSON_CreateArray( void )
967 {
968 	cJSON *item = cJSON_New_Item();
969 	if ( item )
970 		item->type = cJSON_Array;
971 	return item;
972 }
973 
974 cJSON *cJSON_CreateObject( void )
975 {
976 	cJSON *item = cJSON_New_Item();
977 	if ( item )
978 		item->type = cJSON_Object;
979 	return item;
980 }
981 
982 
983 /* Create Arrays. */
984 
985 cJSON *cJSON_CreateIntArray( int64_t *numbers, int count )
986 {
987 	int i;
988 	cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
989 	for ( i = 0; a && i < count; ++i ) {
990 		n = cJSON_CreateInt( numbers[i] );
991 		if ( ! i )
992 			a->child = n;
993 		else
994 			suffix_object( p, n );
995 		p = n;
996 	}
997 	return a;
998 }
999 
1000 cJSON *cJSON_CreateFloatArray( double *numbers, int count )
1001 {
1002 	int i;
1003 	cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1004 	for ( i = 0; a && i < count; ++i ) {
1005 		n = cJSON_CreateFloat( numbers[i] );
1006 		if ( ! i )
1007 			a->child = n;
1008 		else
1009 			suffix_object( p, n );
1010 		p = n;
1011 	}
1012 	return a;
1013 }
1014 
1015 cJSON *cJSON_CreateStringArray( const char **strings, int count )
1016 {
1017 	int i;
1018 	cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
1019 	for ( i = 0; a && i < count; ++i ) {
1020 		n = cJSON_CreateString( strings[i] );
1021 		if ( ! i )
1022 			a->child = n;
1023 		else
1024 			suffix_object( p, n );
1025 		p = n;
1026 	}
1027 	return a;
1028 }
1029