瀏覽代碼

here it is, cJSON 1.0

git-svn-id: http://svn.code.sf.net/p/cjson/code@1 e3330c51-1366-4df0-8b21-3ccf24e3d50e
Dave Gamble 16 年之前
當前提交
805b652e51
共有 8 個文件被更改,包括 773 次插入0 次删除
  1. 360 0
      cJSON.c
  2. 91 0
      cJSON.h
  3. 148 0
      test.c
  4. 22 0
      tests/test1
  5. 11 0
      tests/test2
  6. 26 0
      tests/test3
  7. 88 0
      tests/test4
  8. 27 0
      tests/test5

+ 360 - 0
cJSON.c

@@ -0,0 +1,360 @@
+/*
+  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 "cJSON.h"
+
+// Internal constructor.
+static cJSON *cJSON_New_Item() { return (cJSON*)calloc(sizeof(cJSON),1); }
+
+// Delete a cJSON structure.
+void cJSON_Delete(cJSON *c)
+{
+	cJSON *next;
+	while (c)
+	{
+		next=c->next;
+		if (c->child) cJSON_Delete(c->child);
+		if (c->valuestring) free(c->valuestring);
+		if (c->string) free(c->string);
+		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,sign=1,scale=0;int subscale=0,signsubscale=1;
+
+	// Could use sscanf for this?
+	if (*num=='-') sign=-1,num++;	// Has sign?
+	if (*num=='0') num++;			// is zero
+	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	// Number?
+	if (*num=='.') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	// Fractional part?
+	if (*num=='e' || *num=='E')		// Exponent?
+	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		// With sign?
+		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	// Number?
+	}
+
+	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	// number = +/- number.fraction * 10^+/- exponent
+	
+	item->valuedouble=n;
+	item->valueint=(int)n;
+	item->type=cJSON_Number;
+	return num;
+}
+
+// Render the number nicely from the given item into a string.
+static char *print_number(cJSON *item)
+{
+	char *str;
+	double d=item->valuedouble;
+	if (fabs(((double)item->valueint)-d)<=DBL_EPSILON)
+	{
+		str=malloc(21);	// 2^64+1 can be represented in 21 chars.
+		sprintf(str,"%d",item->valueint);
+	}
+	else
+	{
+		str=malloc(64);	// This is a nice tradeoff.
+		if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)	sprintf(str,"%e",d);
+		else									sprintf(str,"%f",d);
+	}
+	return str;
+}
+
+// Parse the input text into an unescaped cstring, and populate item.
+static const char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+static const char *parse_string(cJSON *item,const char *str)
+{
+	const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc;
+	if (*str!='\"') return 0;	// not a string!
+	
+	while (*ptr!='\"' && *ptr>31 && ++len) if (*ptr++ == '\\') ptr++;	// Skip escaped quotes.
+	
+	out=(char*)malloc(len+1);	// This is how long we need for the string, roughly.
+	
+	ptr=str+1;ptr2=out;
+	while (*ptr!='\"' && *ptr>31)
+	{
+		if (*ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			ptr++;
+			switch (*ptr)
+			{
+				case 'b': *ptr2++='\b';	break;
+				case 'f': *ptr2++='\f';	break;
+				case 'n': *ptr2++='\n';	break;
+				case 'r': *ptr2++='\r';	break;
+				case 't': *ptr2++='\t';	break;
+				case 'u':	 // transcode utf16 to utf8. DOES NOT SUPPORT SURROGATE PAIRS CORRECTLY.
+					sscanf(ptr+1,"%4x",&uc);	// get the unicode char.
+					len=3;if (uc<0x80) len=1;else if (uc<0x800) len=2;ptr2+=len;
+					
+					switch (len) {
+						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 1: *--ptr2 =(uc | firstByteMark[len]);
+					}
+					ptr2+=len;ptr+=4;
+					break;
+				default:  *ptr2++=*ptr; break;
+			}
+			ptr++;
+		}
+	}
+	*ptr2=0;
+	if (*ptr=='\"') ptr++;
+	item->valuestring=out;
+	item->type=cJSON_String;
+	return ptr;
+}
+
+// Render the cstring provided to an escaped version that can be printed.
+static char *print_string_ptr(const char *str)
+{
+	const char *ptr;char *ptr2,*out;int len=0;
+	
+	ptr=str;while (*ptr && ++len) {if (*ptr<32 || *ptr=='\"' || *ptr=='\\') len++;ptr++;}
+	
+	out=(char*)malloc(len+3);
+	ptr2=out;ptr=str;
+	*ptr2++='\"';
+	while (*ptr)
+	{
+		if (*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			*ptr2++='\\';
+			switch (*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: ptr2--;	break;	// eviscerate with prejudice.
+			}
+		}
+	}
+	*ptr2++='\"';*ptr2++=0;
+	return out;
+}
+// Invote print_string_ptr (which is useful) on an item.
+static char *print_string(cJSON *item)	{return print_string_ptr(item->valuestring);}
+
+// Predeclare these prototypes.
+static const char *parse_value(cJSON *item,const char *value);
+static char *print_value(cJSON *item,int depth);
+static const char *parse_array(cJSON *item,const char *value);
+static char *print_array(cJSON *item,int depth);
+static const char *parse_object(cJSON *item,const char *value);
+static char *print_object(cJSON *item,int depth);
+
+// Parse an object - create a new root, and populate.
+cJSON *cJSON_Parse(const char *value)	{cJSON *c=cJSON_New_Item();parse_value(c,value);return c;}
+// Render a cJSON item/entity/structure to text.
+char *cJSON_Print(cJSON *item)			{return print_value(item,0);}
+
+// Parser core - when encountering text, process appropriately.
+static const char *parse_value(cJSON *item,const char *value)
+{
+	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; }
+	if (*value=='\"')				{ return parse_string(item,value); }
+	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
+	if (*value=='[')				{ return parse_array(item,value); }
+	if (*value=='{')				{ return parse_object(item,value); }
+
+	return 0;	// failure.
+}
+
+// Render a value to text.
+static char *print_value(cJSON *item,int depth)
+{
+	char *out=0;
+	switch (item->type)
+	{
+		case cJSON_NULL:	out=strdup("null");	break;
+		case cJSON_False:	out=strdup("false");break;
+		case cJSON_True:	out=strdup("true"); break;
+		case cJSON_Number:	out=print_number(item);break;
+		case cJSON_String:	out=print_string(item);break;
+		case cJSON_Array:	out=print_array(item,depth);break;
+		case cJSON_Object:	out=print_object(item,depth);break;
+	}
+	return out;
+}
+
+// Utility to jump whitespace and cr/lf
+static const char *skip(const char *in) {while (in && *in<=32) in++; return in;}
+
+// Build an array from input text.
+static const char *parse_array(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='[')	return 0;	// not an array!
+
+	item->type=cJSON_Array;
+	value=skip(value+1);
+	if (*value==']') return value+1;	// empty array.
+
+	item->child=child=cJSON_New_Item();
+	value=skip(parse_value(child,skip(value)));	// skip any spacing, get the value.
+
+	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;
+		value=skip(parse_value(child,skip(value+1)));
+	}
+
+	if (*value==']') return value+1;	// end of array
+	return 0;	// malformed.
+}
+
+// Render an array to text
+static char *print_array(cJSON *item,int depth)
+{
+	char *out,*ptr,*ret;int len=5;
+	cJSON *child=item->child;
+	
+	out=malloc(len);*out='[';
+	ptr=out+1;*ptr=0;
+	while (child)
+	{
+		ret=print_value(child,depth+1);
+		if (!ret) {free(out);return 0;}	// Check for failure!
+		len+=strlen(ret)+3;
+		out=realloc(out,len);
+		ptr=out+strlen(out);
+		ptr+=sprintf(ptr,ret);
+		if (child->next) {*ptr++=',';*ptr++=' ';*ptr=0;}
+		child=child->next;
+		free(ret);
+	}
+	*ptr++=']';*ptr++=0;
+	return out;	
+}
+
+// Build an object from the text.
+static const char *parse_object(cJSON *item,const char *value)
+{
+	cJSON *child;
+	if (*value!='{')	return 0;	// not an object!
+	
+	item->type=cJSON_Object;
+	value=skip(value+1);
+	if (*value=='}') return value+1;	// empty array.
+	
+	item->child=child=cJSON_New_Item();
+	value=skip(parse_string(child,skip(value)));
+	child->string=child->valuestring;child->valuestring=0;
+	if (*value!=':') return 0;	// fail!
+	value=skip(parse_value(child,skip(value+1)));	// skip any spacing, get the value.
+	
+	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;
+		value=skip(parse_string(child,skip(value+1)));
+		child->string=child->valuestring;child->valuestring=0;
+		if (*value!=':') return 0;	// fail!
+		value=skip(parse_value(child,skip(value+1)));	// skip any spacing, get the value.		
+	}
+	
+	if (*value=='}') return value+1;	// end of array
+	return 0;	// malformed.	
+}
+
+// Render an object to text.
+static char *print_object(cJSON *item,int depth)
+{
+	char *out,*ptr,*ret,*str;int len=7,i;
+	cJSON *child=item->child;
+	
+	depth++;out=malloc(len+depth);*out='{';
+	ptr=out+1;*ptr++='\n';*ptr=0;
+	while (child)
+	{
+		str=print_string_ptr(child->string);
+		if (!str) {free(out);return 0;}
+		ret=print_value(child,depth);
+		if (!ret) {free(out);return 0;}	// Check for failure!
+		len+=strlen(ret)+strlen(str)+4+depth;
+		out=realloc(out,len);
+		ptr=out+strlen(out);
+		for (i=0;i<depth;i++) *ptr++='\t';
+		ptr+=sprintf(ptr,str);
+		*ptr++=':';*ptr++='\t';
+		ptr+=sprintf(ptr,ret);
+		if (child->next) *ptr++=',';
+		*ptr++='\n';*ptr=0;
+		child=child->next;
+		free(str);free(ret);
+	}
+	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->child;  while (c && item) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object->child; while (c && strcasecmp(c->string,string)) c=c->next; return c;}
+
+// Utility for array list handling.
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+
+// Add item to array/object.
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;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->string) free(item->string);item->string=strdup(string);cJSON_AddItemToArray(object,item);}
+
+// Create basic types:
+cJSON *cJSON_CreateNull()						{cJSON *item=cJSON_New_Item();item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue()						{cJSON *item=cJSON_New_Item();item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse()						{cJSON *item=cJSON_New_Item();item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_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();item->type=cJSON_String;item->valuestring=strdup(string);return item;}
+cJSON *cJSON_CreateArray()						{cJSON *item=cJSON_New_Item();item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject()						{cJSON *item=cJSON_New_Item();item->type=cJSON_Object;return item;}
+
+// Create Arrays:
+cJSON *cJSON_CreateIntArray(int *numbers,int count)				{cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(float *numbers,int count)			{cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(double *numbers,int count)		{cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count)	{cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(int i=0;i<count;i++){n=cJSON_CreateString(strings[i]);if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}

+ 91 - 0
cJSON.h

@@ -0,0 +1,91 @@
+/*
+  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.
+*/
+
+#ifndef cJSON__h
+#define cJSON__h
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// cJSON Types:
+#define cJSON_False 0
+#define cJSON_True 1
+#define cJSON_NULL 2
+#define cJSON_Number 3
+#define cJSON_String 4
+#define cJSON_Array 5
+#define cJSON_Object 6
+
+// The cJSON structure:
+typedef struct cJSON {
+	struct cJSON *next,*prev;	// next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem
+	struct cJSON *child;		// An array or object item will have a child pointer pointing to a chain of the items in the array/object.
+
+	int type;					// The type of the item, as above.
+
+	char *valuestring;			// The item's string, if type==cJSON_String
+	int valueint;				// The item's number, if type==cJSON_Number
+	double valuedouble;			// The item's number, if type==cJSON_Number
+
+	char *string;				// The item's name string, if this item is the child of, or is in the list of subitems of an object.
+} cJSON;
+
+// Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished.
+extern cJSON *cJSON_Parse(const char *value);
+// Render a cJSON entity to text for transfer/storage. Free the char* when finished.
+extern char  *cJSON_Print(cJSON *item);
+// Delete a cJSON entity and all subentities.
+extern void   cJSON_Delete(cJSON *c);
+
+// Returns the number of items in an array (or object).
+extern int	  cJSON_GetArraySize(cJSON *array);
+// Retrieve item number "item" from array "array". Returns NULL if unsuccessful.
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
+// Get item "string" from object. Case insensitive.
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+
+// These calls create a cJSON item of the appropriate type.
+extern cJSON *cJSON_CreateNull();
+extern cJSON *cJSON_CreateTrue();
+extern cJSON *cJSON_CreateFalse();
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray();
+extern cJSON *cJSON_CreateObject();
+
+// These utilities create an Array of count items.
+extern cJSON *cJSON_CreateIntArray(int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
+
+// Append item to the specified array/object.
+extern void   cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void	  cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+	
+#ifdef __cplusplus
+}
+#endif
+
+#endif

+ 148 - 0
test.c

@@ -0,0 +1,148 @@
+/*
+  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.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "cJSON.h"
+
+// Parse text to JSON, then render back to text, and print!
+void doit(char *text)
+{
+	char *out;cJSON *json;
+	
+	json=cJSON_Parse(text);
+	out=cJSON_Print(json);
+	cJSON_Delete(json);
+	printf("%s\n",out);
+	free(out);	
+}
+
+// Read a file, parse, render back, etc.
+void dofile(char *filename)
+{
+	FILE *f=fopen(filename,"rb");fseek(f,0,SEEK_END);long len=ftell(f);fseek(f,0,SEEK_SET);
+	char *data=malloc(len+1);fread(data,1,len,f);fclose(f);
+	doit(data);
+	free(data);
+}
+
+// Used by some code below as an example datatype.
+struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; };
+
+// Create a bunch of objects as demonstration.
+void create_objects()
+{
+	cJSON *root,*fmt,*img,*thm,*fld;char *out;int i;	// declare a few.
+
+	// Here we construct some JSON standards, from the JSON site.
+	
+	// Our "Video" datatype:
+	root=cJSON_CreateObject();	
+	cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble"));
+	cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject());
+	cJSON_AddItemToObject(fmt,"type",		cJSON_CreateString("rect"));
+	cJSON_AddItemToObject(fmt,"width",		cJSON_CreateNumber(1920));
+	cJSON_AddItemToObject(fmt,"height",		cJSON_CreateNumber(1080));
+	cJSON_AddItemToObject(fmt,"interlace",	cJSON_CreateFalse());
+	cJSON_AddItemToObject(fmt,"frame rate",	cJSON_CreateNumber(24));
+	
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);	// Print to text, Delete the cJSON, print it, release the string.
+
+	// Our "days of the week" array:
+	const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
+	root=cJSON_CreateStringArray(strings,7);
+
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+	// Our matrix:
+	int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}};
+	root=cJSON_CreateArray();
+	for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3));
+
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+
+	// Our "gallery" item:
+	int ids[4]={116,943,234,38793};
+	root=cJSON_CreateObject();
+	cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject());
+	cJSON_AddItemToObject(img,"Width",cJSON_CreateNumber(800));
+	cJSON_AddItemToObject(img,"Height",cJSON_CreateNumber(600));
+	cJSON_AddItemToObject(img,"Title",cJSON_CreateString("View from 15th Floor"));
+	cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject());
+	cJSON_AddItemToObject(thm, "Url", cJSON_CreateString("http://www.example.com/image/481989943"));
+	cJSON_AddItemToObject(thm,"Height",cJSON_CreateNumber(125));
+	cJSON_AddItemToObject(thm,"Width",cJSON_CreateString("100"));
+	cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4));
+
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+	// Our array of "records":
+	struct record fields[2]={
+		{"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"},
+		{"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}};
+
+	root=cJSON_CreateArray();
+	for (int i=0;i<2;i++)
+	{
+		cJSON_AddItemToArray(root,fld=cJSON_CreateObject());
+		cJSON_AddItemToObject(fld, "precision", cJSON_CreateString(fields[i].precision));
+		cJSON_AddItemToObject(fld, "Latitude", cJSON_CreateNumber(fields[i].lat));
+		cJSON_AddItemToObject(fld, "Longitude", cJSON_CreateNumber(fields[i].lon));
+		cJSON_AddItemToObject(fld, "Address", cJSON_CreateString(fields[i].address));
+		cJSON_AddItemToObject(fld, "City", cJSON_CreateString(fields[i].city));
+		cJSON_AddItemToObject(fld, "State", cJSON_CreateString(fields[i].state));
+		cJSON_AddItemToObject(fld, "Zip", cJSON_CreateString(fields[i].zip));
+		cJSON_AddItemToObject(fld, "Country", cJSON_CreateString(fields[i].country));
+	}
+	
+	out=cJSON_Print(root);	cJSON_Delete(root);	printf("%s\n",out);	free(out);
+
+}
+
+int main (int argc, const char * argv[]) {
+	// a bunch of json:
+	char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\":       \"rect\", \n\"width\":      1920, \n\"height\":     1080, \n\"interlace\":  false,\"frame rate\": 24\n}\n}";	
+	char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]";
+	char text3[]="[\n    [0, -1, 0],\n    [1, 0, 0],\n    [0, 0, 1]\n	]\n";
+	char text4[]="{\n		\"Image\": {\n			\"Width\":  800,\n			\"Height\": 600,\n			\"Title\":  \"View from 15th Floor\",\n			\"Thumbnail\": {\n				\"Url\":    \"http://www.example.com/image/481989943\",\n				\"Height\": 125,\n				\"Width\":  \"100\"\n			},\n			\"IDs\": [116, 943, 234, 38793]\n		}\n	}";
+	char text5[]="[\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.7668,\n	 \"Longitude\": -122.3959,\n	 \"Address\":   \"\",\n	 \"City\":      \"SAN FRANCISCO\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94107\",\n	 \"Country\":   \"US\"\n	 },\n	 {\n	 \"precision\": \"zip\",\n	 \"Latitude\":  37.371991,\n	 \"Longitude\": -122.026020,\n	 \"Address\":   \"\",\n	 \"City\":      \"SUNNYVALE\",\n	 \"State\":     \"CA\",\n	 \"Zip\":       \"94085\",\n	 \"Country\":   \"US\"\n	 }\n	 ]";
+
+	// Process each json textblock by parsing, then rebuilding:
+	doit(text1);
+	doit(text2);	
+	doit(text3);
+	doit(text4);
+	doit(text5);
+
+	// Parse standard testfiles:
+//	dofile("../../tests/test1");
+//	dofile("../../tests/test2");
+//	dofile("../../tests/test3");
+//	dofile("../../tests/test4");
+//	dofile("../../tests/test5");
+
+	// Now some samplecode for building objects concisely:
+	create_objects();
+	
+	return 0;
+}

+ 22 - 0
tests/test1

@@ -0,0 +1,22 @@
+{
+    "glossary": {
+        "title": "example glossary",
+		"GlossDiv": {
+            "title": "S",
+			"GlossList": {
+                "GlossEntry": {
+                    "ID": "SGML",
+					"SortAs": "SGML",
+					"GlossTerm": "Standard Generalized Markup Language",
+					"Acronym": "SGML",
+					"Abbrev": "ISO 8879:1986",
+					"GlossDef": {
+                        "para": "A meta-markup language, used to create markup languages such as DocBook.",
+						"GlossSeeAlso": ["GML", "XML"]
+                    },
+					"GlossSee": "markup"
+                }
+            }
+        }
+    }
+}

+ 11 - 0
tests/test2

@@ -0,0 +1,11 @@
+{"menu": {
+  "id": "file",
+  "value": "File",
+  "popup": {
+    "menuitem": [
+      {"value": "New", "onclick": "CreateNewDoc()"},
+      {"value": "Open", "onclick": "OpenDoc()"},
+      {"value": "Close", "onclick": "CloseDoc()"}
+    ]
+  }
+}}

+ 26 - 0
tests/test3

@@ -0,0 +1,26 @@
+{"widget": {
+    "debug": "on",
+    "window": {
+        "title": "Sample Konfabulator Widget",
+        "name": "main_window",
+        "width": 500,
+        "height": 500
+    },
+    "image": { 
+        "src": "Images/Sun.png",
+        "name": "sun1",
+        "hOffset": 250,
+        "vOffset": 250,
+        "alignment": "center"
+    },
+    "text": {
+        "data": "Click Here",
+        "size": 36,
+        "style": "bold",
+        "name": "text1",
+        "hOffset": 250,
+        "vOffset": 100,
+        "alignment": "center",
+        "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;"
+    }
+}}    

+ 88 - 0
tests/test4

@@ -0,0 +1,88 @@
+{"web-app": {
+  "servlet": [   
+    {
+      "servlet-name": "cofaxCDS",
+      "servlet-class": "org.cofax.cds.CDSServlet",
+      "init-param": {
+        "configGlossary:installationAt": "Philadelphia, PA",
+        "configGlossary:adminEmail": "ksm@pobox.com",
+        "configGlossary:poweredBy": "Cofax",
+        "configGlossary:poweredByIcon": "/images/cofax.gif",
+        "configGlossary:staticPath": "/content/static",
+        "templateProcessorClass": "org.cofax.WysiwygTemplate",
+        "templateLoaderClass": "org.cofax.FilesTemplateLoader",
+        "templatePath": "templates",
+        "templateOverridePath": "",
+        "defaultListTemplate": "listTemplate.htm",
+        "defaultFileTemplate": "articleTemplate.htm",
+        "useJSP": false,
+        "jspListTemplate": "listTemplate.jsp",
+        "jspFileTemplate": "articleTemplate.jsp",
+        "cachePackageTagsTrack": 200,
+        "cachePackageTagsStore": 200,
+        "cachePackageTagsRefresh": 60,
+        "cacheTemplatesTrack": 100,
+        "cacheTemplatesStore": 50,
+        "cacheTemplatesRefresh": 15,
+        "cachePagesTrack": 200,
+        "cachePagesStore": 100,
+        "cachePagesRefresh": 10,
+        "cachePagesDirtyRead": 10,
+        "searchEngineListTemplate": "forSearchEnginesList.htm",
+        "searchEngineFileTemplate": "forSearchEngines.htm",
+        "searchEngineRobotsDb": "WEB-INF/robots.db",
+        "useDataStore": true,
+        "dataStoreClass": "org.cofax.SqlDataStore",
+        "redirectionClass": "org.cofax.SqlRedirection",
+        "dataStoreName": "cofax",
+        "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver",
+        "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon",
+        "dataStoreUser": "sa",
+        "dataStorePassword": "dataStoreTestQuery",
+        "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';",
+        "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log",
+        "dataStoreInitConns": 10,
+        "dataStoreMaxConns": 100,
+        "dataStoreConnUsageLimit": 100,
+        "dataStoreLogLevel": "debug",
+        "maxUrlLength": 500}},
+    {
+      "servlet-name": "cofaxEmail",
+      "servlet-class": "org.cofax.cds.EmailServlet",
+      "init-param": {
+      "mailHost": "mail1",
+      "mailHostOverride": "mail2"}},
+    {
+      "servlet-name": "cofaxAdmin",
+      "servlet-class": "org.cofax.cds.AdminServlet"},
+ 
+    {
+      "servlet-name": "fileServlet",
+      "servlet-class": "org.cofax.cds.FileServlet"},
+    {
+      "servlet-name": "cofaxTools",
+      "servlet-class": "org.cofax.cms.CofaxToolsServlet",
+      "init-param": {
+        "templatePath": "toolstemplates/",
+        "log": 1,
+        "logLocation": "/usr/local/tomcat/logs/CofaxTools.log",
+        "logMaxSize": "",
+        "dataLog": 1,
+        "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log",
+        "dataLogMaxSize": "",
+        "removePageCache": "/content/admin/remove?cache=pages&id=",
+        "removeTemplateCache": "/content/admin/remove?cache=templates&id=",
+        "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder",
+        "lookInContext": 1,
+        "adminGroupID": 4,
+        "betaServer": true}}],
+  "servlet-mapping": {
+    "cofaxCDS": "/",
+    "cofaxEmail": "/cofaxutil/aemail/*",
+    "cofaxAdmin": "/admin/*",
+    "fileServlet": "/static/*",
+    "cofaxTools": "/tools/*"},
+ 
+  "taglib": {
+    "taglib-uri": "cofax.tld",
+    "taglib-location": "/WEB-INF/tlds/cofax.tld"}}}

+ 27 - 0
tests/test5

@@ -0,0 +1,27 @@
+{"menu": {
+    "header": "SVG Viewer",
+    "items": [
+        {"id": "Open"},
+        {"id": "OpenNew", "label": "Open New"},
+        null,
+        {"id": "ZoomIn", "label": "Zoom In"},
+        {"id": "ZoomOut", "label": "Zoom Out"},
+        {"id": "OriginalView", "label": "Original View"},
+        null,
+        {"id": "Quality"},
+        {"id": "Pause"},
+        {"id": "Mute"},
+        null,
+        {"id": "Find", "label": "Find..."},
+        {"id": "FindAgain", "label": "Find Again"},
+        {"id": "Copy"},
+        {"id": "CopyAgain", "label": "Copy Again"},
+        {"id": "CopySVG", "label": "Copy SVG"},
+        {"id": "ViewSVG", "label": "View SVG"},
+        {"id": "ViewSource", "label": "View Source"},
+        {"id": "SaveAs", "label": "Save As"},
+        null,
+        {"id": "Help"},
+        {"id": "About", "label": "About Adobe CVG Viewer..."}
+    ]
+}}