Browse Source
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5267 42af7a65-404d-4744-a932-0658087f49c3sbg
21 changed files with 2894 additions and 201 deletions
@ -0,0 +1,14 @@
@@ -0,0 +1,14 @@
|
||||
# |
||||
# For a description of the syntax of this configuration file, |
||||
# see misc/tools/kconfig-language.txt. |
||||
# |
||||
|
||||
config EXAMPLES_JSON |
||||
bool "JSON example" |
||||
default n |
||||
select NETUTILS_JSON |
||||
---help--- |
||||
An example for the netutils/json library. |
||||
|
||||
if EXAMPLES_JSON |
||||
endif |
@ -0,0 +1,103 @@
@@ -0,0 +1,103 @@
|
||||
############################################################################
|
||||
# apps/examples/json/Makefile
|
||||
#
|
||||
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name NuttX nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
-include $(TOPDIR)/.config |
||||
-include $(TOPDIR)/Make.defs |
||||
include $(APPDIR)/Make.defs |
||||
|
||||
# cJSON built-in application info
|
||||
|
||||
APPNAME = json
|
||||
PRIORITY = SCHED_PRIORITY_DEFAULT
|
||||
STACKSIZE = 2048
|
||||
|
||||
ASRCS =
|
||||
CSRCS = json_main.c
|
||||
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
|
||||
ifeq ($(WINTOOL),y) |
||||
BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}"
|
||||
else |
||||
BIN = "$(APPDIR)/libapps$(LIBEXT)"
|
||||
endif |
||||
|
||||
ROOTDEPPATH = --dep-path .
|
||||
|
||||
# Common build
|
||||
|
||||
VPATH =
|
||||
|
||||
all: .built |
||||
.PHONY: clean depend distclean |
||||
|
||||
$(AOBJS): %$(OBJEXT): %.S |
||||
$(call ASSEMBLE, $<, $@)
|
||||
|
||||
$(COBJS): %$(OBJEXT): %.c |
||||
$(call COMPILE, $<, $@)
|
||||
|
||||
.built: $(OBJS) |
||||
@( for obj in $(OBJS) ; do \
|
||||
$(call ARCHIVE, $(BIN), $${obj}); \
|
||||
done ; )
|
||||
@touch .built
|
||||
|
||||
.context: |
||||
ifeq ($(CONFIG_NSH_BUILTIN_APPS),y) |
||||
$(call REGISTER,$(APPNAME),$(PRIORITY),$(STACKSIZE),$(APPNAME)_main)
|
||||
@touch $@
|
||||
endif |
||||
|
||||
context: .context |
||||
|
||||
.depend: Makefile $(SRCS) |
||||
@$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
|
||||
@touch $@
|
||||
|
||||
depend: .depend |
||||
|
||||
clean: |
||||
@rm -f *.o *~ .*.swp .built
|
||||
$(call CLEAN)
|
||||
|
||||
distclean: clean |
||||
@rm -f Make.dep .depend
|
||||
|
||||
-include Make.dep |
@ -0,0 +1,258 @@
@@ -0,0 +1,258 @@
|
||||
apps/examples/json/README.txt |
||||
============================= |
||||
|
||||
This directory contains logic taken from the cJSON project: |
||||
|
||||
http://sourceforge.net/projects/cjson/ |
||||
|
||||
This corresponds to SVN revision r42 (with lots of changes for NuttX coding |
||||
standards). As of r42, the SVN repository was last updated on 2011-10-10 |
||||
so I presume that the code is stable and there is no risk of maintaining |
||||
duplicate logic in the NuttX repository. |
||||
|
||||
Contents |
||||
======== |
||||
|
||||
o License |
||||
o Welcome to cJSON |
||||
|
||||
License |
||||
======= |
||||
|
||||
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. |
||||
|
||||
Welcome to cJSON |
||||
================ |
||||
|
||||
cJSON aims to be the dumbest possible parser that you can get your job done with. |
||||
It's a single file of C, and a single header file. |
||||
|
||||
JSON is described best here: http://www.json.org/ |
||||
It's like XML, but fat-free. You use it to move data around, store things, or just |
||||
generally represent your program's state. |
||||
|
||||
First up, how do I build? |
||||
Add cJSON.c to your project, and put cJSON.h somewhere in the header search path. |
||||
For example, to build the test app: |
||||
|
||||
gcc cJSON.c test.c -o test -lm |
||||
./test |
||||
|
||||
As a library, cJSON exists to take away as much legwork as it can, but not get in your way. |
||||
As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it |
||||
in one of two modes: Auto and Manual. Let's have a quick run-through. |
||||
|
||||
I lifted some JSON from this page: http://www.json.org/fatfree.html |
||||
That page inspired me to write cJSON, which is a parser that tries to share the same |
||||
philosophy as JSON itself. Simple, dumb, out of the way. |
||||
|
||||
Some JSON: |
||||
{ |
||||
"name": "Jack (\"Bee\") Nimble", |
||||
"format": { |
||||
"type": "rect", |
||||
"width": 1920, |
||||
"height": 1080, |
||||
"interlace": false, |
||||
"frame rate": 24 |
||||
} |
||||
} |
||||
|
||||
Assume that you got this from a file, a webserver, or magic JSON elves, whatever, |
||||
you have a char * to it. Everything is a cJSON struct. |
||||
Get it parsed: |
||||
cJSON *root = cJSON_Parse(my_json_string); |
||||
|
||||
This is an object. We're in C. We don't have objects. But we do have structs. |
||||
What's the framerate? |
||||
|
||||
cJSON *format = cJSON_GetObjectItem(root,"format"); |
||||
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint; |
||||
|
||||
Want to change the framerate? |
||||
cJSON_GetObjectItem(format,"frame rate")->valueint=25; |
||||
|
||||
Back to disk? |
||||
char *rendered=cJSON_Print(root); |
||||
|
||||
Finished? Delete the root (this takes care of everything else). |
||||
cJSON_Delete(root); |
||||
|
||||
That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers |
||||
before you dereference them. If you want to see how you'd build this struct in code? |
||||
cJSON *root,*fmt; |
||||
root=cJSON_CreateObject(); |
||||
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); |
||||
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); |
||||
cJSON_AddStringToObject(fmt,"type", "rect"); |
||||
cJSON_AddNumberToObject(fmt,"width", 1920); |
||||
cJSON_AddNumberToObject(fmt,"height", 1080); |
||||
cJSON_AddFalseToObject (fmt,"interlace"); |
||||
cJSON_AddNumberToObject(fmt,"frame rate", 24); |
||||
|
||||
Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. |
||||
Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and |
||||
a few from elsewhere. |
||||
|
||||
What about manual mode? First up you need some detail. |
||||
Let's cover how the cJSON objects represent the JSON data. |
||||
cJSON doesn't distinguish arrays from objects in handling; just type. |
||||
Each cJSON has, potentially, a child, siblings, value, a name. |
||||
|
||||
The root object has: Object Type and a Child |
||||
The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: |
||||
Sibling has type Object, name "format", and a child. |
||||
That child has type String, name "type", value "rect", and a sibling: |
||||
Sibling has type Number, name "width", value 1920, and a sibling: |
||||
Sibling has type Number, name "height", value 1080, and a sibling: |
||||
Sibling hs type False, name "interlace", and a sibling: |
||||
Sibling has type Number, name "frame rate", value 24 |
||||
|
||||
Here's the structure: |
||||
typedef struct cJSON { |
||||
struct cJSON *next,*prev; |
||||
struct cJSON *child; |
||||
|
||||
int type; |
||||
|
||||
char *valuestring; |
||||
int valueint; |
||||
double valuedouble; |
||||
|
||||
char *string; |
||||
} cJSON; |
||||
|
||||
By default all values are 0 unless set by virtue of being meaningful. |
||||
|
||||
next/prev is a doubly linked list of siblings. next takes you to your sibling, |
||||
prev takes you back from your sibling to you. |
||||
Only objects and arrays have a "child", and it's the head of the doubly linked list. |
||||
A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0. |
||||
The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in |
||||
cJSON.h |
||||
|
||||
A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read |
||||
valuedouble. |
||||
|
||||
Any entry which is in the linked list which is the child of an object will have a "string" |
||||
which is the "name" of the entry. When I said "name" in the above example, that's "string". |
||||
"string" is the JSON name for the 'variable name' if you will. |
||||
|
||||
Now you can trivially walk the lists, recursively, and parse as you please. |
||||
You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take |
||||
the root object, and traverse the structure (which is, formally, an N-tree), |
||||
and tokenise as you please. If you wanted to build a callback style parser, this is how |
||||
you'd do it (just an example, since these things are very specific): |
||||
|
||||
void parse_and_callback(cJSON *item,const char *prefix) |
||||
{ |
||||
while (item) |
||||
{ |
||||
char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2); |
||||
sprintf(newprefix,"%s/%s",prefix,item->name); |
||||
int dorecurse=callback(newprefix, item->type, item); |
||||
if (item->child && dorecurse) parse_and_callback(item->child,newprefix); |
||||
item=item->next; |
||||
free(newprefix); |
||||
} |
||||
} |
||||
|
||||
The prefix process will build you a separated list, to simplify your callback handling. |
||||
The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or |
||||
let you invoke it per-item. For the item above, your callback might look like this: |
||||
|
||||
int callback(const char *name,int type,cJSON *item) |
||||
{ |
||||
if (!strcmp(name,"name")) { /* populate name */ } |
||||
else if (!strcmp(name,"format/type") { /* handle "rect" */ } |
||||
else if (!strcmp(name,"format/width") { /* 800 */ } |
||||
else if (!strcmp(name,"format/height") { /* 600 */ } |
||||
else if (!strcmp(name,"format/interlace") { /* false */ } |
||||
else if (!strcmp(name,"format/frame rate") { /* 24 */ } |
||||
return 1; |
||||
} |
||||
|
||||
Alternatively, you might like to parse iteratively. |
||||
You'd use: |
||||
|
||||
void parse_object(cJSON *item) |
||||
{ |
||||
int i; for (i=0;i<cJSON_GetArraySize(item);i++) |
||||
{ |
||||
cJSON *subitem=cJSON_GetArrayItem(item,i); |
||||
// handle subitem. |
||||
} |
||||
} |
||||
|
||||
Or, for PROPER manual mode: |
||||
|
||||
void parse_object(cJSON *item) |
||||
{ |
||||
cJSON *subitem=item->child; |
||||
while (subitem) |
||||
{ |
||||
// handle subitem |
||||
if (subitem->child) parse_object(subitem->child); |
||||
|
||||
subitem=subitem->next; |
||||
} |
||||
} |
||||
|
||||
Of course, this should look familiar, since this is just a stripped-down version |
||||
of the callback-parser. |
||||
|
||||
This should cover most uses you'll find for parsing. The rest should be possible |
||||
to infer.. and if in doubt, read the source! There's not a lot of it! ;) |
||||
|
||||
In terms of constructing JSON data, the example code above is the right way to do it. |
||||
You can, of course, hand your sub-objects to other functions to populate. |
||||
Also, if you find a use for it, you can manually build the objects. |
||||
For instance, suppose you wanted to build an array of objects? |
||||
|
||||
cJSON *objects[24]; |
||||
|
||||
cJSON *Create_array_of_anything(cJSON **items,int num) |
||||
{ |
||||
int i;cJSON *prev, *root=cJSON_CreateArray(); |
||||
for (i=0;i<24;i++) |
||||
{ |
||||
if (!i) root->child=objects[i]; |
||||
else prev->next=objects[i], objects[i]->prev=prev; |
||||
prev=objects[i]; |
||||
} |
||||
return root; |
||||
} |
||||
|
||||
and simply: Create_array_of_anything(objects,24); |
||||
|
||||
cJSON doesn't make any assumptions about what order you create things in. |
||||
You can attach the objects, as above, and later add children to each |
||||
of those objects. |
||||
|
||||
As soon as you call cJSON_Print, it renders the structure to text. |
||||
|
||||
The test.c code shows how to handle a bunch of typical cases. If you uncomment |
||||
the code, it'll load, parse and print a bunch of test files, also from json.org, |
||||
which are more complex than I'd care to try and stash into a const char array[]. |
||||
|
||||
Enjoy cJSON! |
||||
|
||||
- Dave Gamble, Aug 2009 |
@ -0,0 +1,325 @@
@@ -0,0 +1,325 @@
|
||||
/****************************************************************************
|
||||
* apps/examples/json/json_main.c |
||||
* |
||||
* This file is a part of NuttX: |
||||
* |
||||
* Copyright (C) 2012 Gregory Nutt. All rights reserved. |
||||
* Ported by: Darcy Gong |
||||
* |
||||
* And derives from the cJSON Project which has an MIT license: |
||||
* |
||||
* 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. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
/****************************************************************************
|
||||
* Included Files |
||||
****************************************************************************/ |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
|
||||
#include <apps/netutils/cJSON.h> |
||||
|
||||
/****************************************************************************
|
||||
* Private Types |
||||
****************************************************************************/ |
||||
|
||||
/* Used by some code below as an example datatype. */ |
||||
|
||||
struct record |
||||
{ |
||||
const char *precision; |
||||
double lat; |
||||
double lon; |
||||
const char *address; |
||||
const char *city; |
||||
const char *state; |
||||
const char *zip; |
||||
const char *country; |
||||
}; |
||||
|
||||
/****************************************************************************
|
||||
* Private Functions |
||||
****************************************************************************/ |
||||
|
||||
/****************************************************************************
|
||||
* Name: doit |
||||
* |
||||
* Description: |
||||
* Parse text to JSON, then render back to text, and print! |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
static void doit(const char *text) |
||||
{ |
||||
char *out; |
||||
cJSON *json; |
||||
json = cJSON_Parse(text); |
||||
if (!json) |
||||
{ |
||||
printf("Error before: [%s]\n", cJSON_GetErrorPtr()); |
||||
} |
||||
else |
||||
{ |
||||
out = cJSON_Print(json); |
||||
cJSON_Delete(json); |
||||
printf("%s\n", out); |
||||
free(out); |
||||
} |
||||
} |
||||
|
||||
/****************************************************************************
|
||||
* Name: dofile |
||||
* |
||||
* Description: |
||||
* Read a file, parse, render back, etc. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
#if 0 /* Not used */
|
||||
static 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); |
||||
} |
||||
#endif |
||||
|
||||
/****************************************************************************
|
||||
* Name: create_objects |
||||
* |
||||
* Description: |
||||
* Create a bunch of objects as demonstration. |
||||
* |
||||
****************************************************************************/ |
||||
|
||||
static void create_objects(void) |
||||
{ |
||||
cJSON *root; |
||||
cJSON *fmt; |
||||
cJSON *img; |
||||
cJSON *thm; |
||||
cJSON *fld; |
||||
char *out; |
||||
int i; |
||||
|
||||
/* Our "days of the week" array */ |
||||
|
||||
static const char *strings[7] = |
||||
{ |
||||
"Sunday", "Monday", "Tuesday", "Wednesday", |
||||
"Thursday", "Friday", "Saturday" |
||||
}; |
||||
|
||||
/* Our matrix: */ |
||||
|
||||
static const int numbers[3][3] = { {0, -1, 0}, {1, 0, 0}, {0, 0, 1} }; |
||||
|
||||
/* Our "gallery" item: */ |
||||
|
||||
static const int ids[4] = { 116, 943, 234, 38793 }; |
||||
|
||||
/* Our array of "records": */ |
||||
|
||||
static const 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"} |
||||
}; |
||||
|
||||
/* 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_AddStringToObject(fmt, "type", "rect"); |
||||
cJSON_AddNumberToObject(fmt, "width", 1920); |
||||
cJSON_AddNumberToObject(fmt, "height", 1080); |
||||
cJSON_AddFalseToObject(fmt, "interlace"); |
||||
cJSON_AddNumberToObject(fmt, "frame rate", 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. */ |
||||
|
||||
root = cJSON_CreateStringArray(strings, 7); |
||||
out = cJSON_Print(root); |
||||
cJSON_Delete(root); |
||||
printf("%s\n", out); |
||||
free(out); |
||||
|
||||
root = cJSON_CreateArray(); |
||||
for (i = 0; i < 3; i++) |
||||
{ |
||||
cJSON_AddItemToArray(root, cJSON_CreateIntArray(numbers[i], 3)); |
||||
} |
||||
|
||||
/*cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */ |
||||
out = cJSON_Print(root); |
||||
cJSON_Delete(root); |
||||
printf("%s\n", out); |
||||
free(out); |
||||
|
||||
root = cJSON_CreateObject(); |
||||
cJSON_AddItemToObject(root, "Image", img = cJSON_CreateObject()); |
||||
cJSON_AddNumberToObject(img, "Width", 800); |
||||
cJSON_AddNumberToObject(img, "Height", 600); |
||||
cJSON_AddStringToObject(img, "Title", "View from 15th Floor"); |
||||
cJSON_AddItemToObject(img, "Thumbnail", thm = cJSON_CreateObject()); |
||||
cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943"); |
||||
cJSON_AddNumberToObject(thm, "Height", 125); |
||||
cJSON_AddStringToObject(thm, "Width", "100"); |
||||
cJSON_AddItemToObject(img, "IDs", cJSON_CreateIntArray(ids, 4)); |
||||
out = cJSON_Print(root); |
||||
cJSON_Delete(root); |
||||
printf("%s\n", out); |
||||
free(out); |
||||
|
||||
root = cJSON_CreateArray(); |
||||
for (i = 0; i < 2; i++) |
||||
{ |
||||
cJSON_AddItemToArray(root, fld = cJSON_CreateObject()); |
||||
cJSON_AddStringToObject(fld, "precision", fields[i].precision); |
||||
cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat); |
||||
cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon); |
||||
cJSON_AddStringToObject(fld, "Address", fields[i].address); |
||||
cJSON_AddStringToObject(fld, "City", fields[i].city); |
||||
cJSON_AddStringToObject(fld, "State", fields[i].state); |
||||
cJSON_AddStringToObject(fld, "Zip", fields[i].zip); |
||||
cJSON_AddStringToObject(fld, "Country", fields[i].country); |
||||
} |
||||
|
||||
/*cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */ |
||||
out = cJSON_Print(root); |
||||
cJSON_Delete(root); |
||||
printf("%s\n", out); |
||||
free(out); |
||||
} |
||||
|
||||
/****************************************************************************
|
||||
* Public Functions |
||||
****************************************************************************/ |
||||
/****************************************************************************
|
||||
* Name:
|
||||
* |
||||
* Description: |
||||
*
|
||||
* |
||||
****************************************************************************/ |
||||
|
||||
int json_main(int argc, const char *argv[]) |
||||
{ |
||||
/* a bunch of json: */ |
||||
|
||||
static const char text1[] = |
||||
"{\n" |
||||
" \"name\": \"Jack (\\\"Bee\\\") Nimble\",\n" |
||||
" \"format\": {\n" |
||||
" \"type\": \"rect\",\n" |
||||
" \"width\": 1920,\n" |
||||
" \"height\": 1080,\n" |
||||
" \"interlace\": false,\n" |
||||
" \"frame rate\": 24\n" |
||||
" }\n" |
||||
"}"; |
||||
|
||||
static const char text2[] =
|
||||
"[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]"; |
||||
|
||||
static const char text3[] = |
||||
"[\n" |
||||
" [0, -1, 0],\n" |
||||
" [1, 0, 0],\n" |
||||
" [0, 0, 1]\n" |
||||
"]\n"; |
||||
|
||||
static const 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" |
||||
"}"; |
||||
|
||||
static const 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: */ |
||||
|
||||
#if 0 /* Not yet */
|
||||
dofile("../../tests/test1"); |
||||
dofile("../../tests/test2"); |
||||
dofile("../../tests/test3"); |
||||
dofile("../../tests/test4"); |
||||
dofile("../../tests/test5"); |
||||
#endif |
||||
|
||||
/* Now some samplecode for building objects concisely: */ |
||||
|
||||
create_objects(); |
||||
return 0; |
||||
} |
@ -0,0 +1,206 @@
@@ -0,0 +1,206 @@
|
||||
/****************************************************************************
|
||||
* apps/netutils/json/cJSON.c |
||||
* |
||||
* This file is a part of NuttX: |
||||
* |
||||
* Copyright (C) 2011 Gregory Nutt. All rights reserved. |
||||
* Ported by: Darcy Gong |
||||
* |
||||
* And derives from the cJSON Project which has an MIT license: |
||||
* |
||||
* 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 __APPS_INCLUDE_NETUTILS_JSON_H |
||||
#define __APPS_INCLUDE_NETUTILS_JSON_H |
||||
|
||||
#ifdef __cplusplus |
||||
extern "C" |
||||
{ |
||||
#endif |
||||
|
||||
/****************************************************************************
|
||||
* Included Files |
||||
****************************************************************************/ |
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions |
||||
****************************************************************************/ |
||||
|
||||
#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 |
||||
|
||||
#define cJSON_IsReference 256 |
||||
|
||||
#define cJSON_AddNullToObject(object,name) \ |
||||
cJSON_AddItemToObject(object, name, cJSON_CreateNull()) |
||||
#define cJSON_AddTrueToObject(object,name) \ |
||||
cJSON_AddItemToObject(object, name, cJSON_CreateTrue())cd
|
||||
#define cJSON_AddFalseToObject(object,name) \ |
||||
cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) |
||||
#define cJSON_AddNumberToObject(object,name,n) \ |
||||
cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) |
||||
#define cJSON_AddStringToObject(object,name,s) \ |
||||
cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) |
||||
|
||||
/****************************************************************************
|
||||
* Public Types |
||||
****************************************************************************/ |
||||
|
||||
/* The cJSON structure: */ |
||||
|
||||
typedef struct cJSON |
||||
{ |
||||
/* next/prev allow you to walk array/object chains. Alternatively, use
|
||||
* GetArraySize/GetArrayItem/GetObjectItem |
||||
*/ |
||||
|
||||
struct cJSON *next,*prev;
|
||||
|
||||
/* An array or object item will have a child pointer pointing to a chain
|
||||
* of the items in the array/object. |
||||
*/ |
||||
|
||||
struct cJSON *child;
|
||||
|
||||
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 */ |
||||
|
||||
/* The item's name string, if this item is the child of, or is in the list
|
||||
* of subitems of an object. |
||||
*/ |
||||
|
||||
char *string; |
||||
} cJSON; |
||||
|
||||
typedef struct cJSON_Hooks |
||||
{ |
||||
void *(*malloc_fn)(size_t sz); |
||||
void (*free_fn)(void *ptr); |
||||
} cJSON_Hooks; |
||||
|
||||
/****************************************************************************
|
||||
* Public Functions |
||||
****************************************************************************/ |
||||
|
||||
/* Supply malloc, realloc and free functions to cJSON */ |
||||
|
||||
void cJSON_InitHooks(cJSON_Hooks* hooks); |
||||
|
||||
/* Supply a block of JSON, and this returns a cJSON object you can
|
||||
* interrogate. Call cJSON_Delete when finished. |
||||
*/ |
||||
|
||||
cJSON *cJSON_Parse(const char *value); |
||||
|
||||
/* Render a cJSON entity to text for transfer/storage. Free the char* when
|
||||
* finished. |
||||
*/ |
||||
|
||||
char *cJSON_Print(cJSON *item); |
||||
|
||||
/* Render a cJSON entity to text for transfer/storage without any
|
||||
* formatting. Free the char* when finished. |
||||
*/ |
||||
|
||||
char *cJSON_PrintUnformatted(cJSON *item); |
||||
|
||||
/* Delete a cJSON entity and all subentities. */ |
||||
|
||||
void cJSON_Delete(cJSON *c); |
||||
|
||||
/* Returns the number of items in an array (or object). */ |
||||
|
||||
int cJSON_GetArraySize(cJSON *array); |
||||
|
||||
/* Retrieve item number "item" from array "array". Returns NULL if
|
||||
* unsuccessful. |
||||
*/ |
||||
|
||||
cJSON *cJSON_GetArrayItem(cJSON *array, int item); |
||||
|
||||
/* Get item "string" from object. Case insensitive. */ |
||||
|
||||
cJSON *cJSON_GetObjectItem(cJSON *object, const char *string); |
||||
|
||||
/* For analysing failed parses. This returns a pointer to the parse error.
|
||||
* You'll probably need to look a few chars back to make sense of it. |
||||
* Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. |
||||
*/ |
||||
|
||||
const char *cJSON_GetErrorPtr(); |
||||
|
||||
/* These calls create a cJSON item of the appropriate type. */ |
||||
|
||||
cJSON *cJSON_CreateNull(); |
||||
cJSON *cJSON_CreateTrue(); |
||||
cJSON *cJSON_CreateFalse(); |
||||
cJSON *cJSON_CreateBool(int b); |
||||
cJSON *cJSON_CreateNumber(double num); |
||||
cJSON *cJSON_CreateString(const char *string); |
||||
cJSON *cJSON_CreateArray(); |
||||
cJSON *cJSON_CreateObject(); |
||||
|
||||
/* These utilities create an Array of count items. */ |
||||
|
||||
cJSON *cJSON_CreateIntArray(const int *numbers, int count); |
||||
cJSON *cJSON_CreateFloatArray(const float *numbers, int count); |
||||
cJSON *cJSON_CreateDoubleArray(const double *numbers, int count); |
||||
cJSON *cJSON_CreateStringArray(const char **strings, int count); |
||||
|
||||
/* Append item to the specified array/object. */ |
||||
|
||||
void cJSON_AddItemToArray(cJSON *array, cJSON *item); |
||||
void cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); |
||||
|
||||
/* Append reference to item to the specified array/object. Use this when you
|
||||
* want to add an existing cJSON to a new cJSON, but don't want to corrupt |
||||
* your existing cJSON. |
||||
*/ |
||||
|
||||
void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); |
||||
void cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); |
||||
|
||||
/* Remove/Detatch items from Arrays/Objects. */ |
||||
|
||||
cJSON *cJSON_DetachItemFromArray(cJSON *array, int which); |
||||
void cJSON_DeleteItemFromArray(cJSON *array, int which); |
||||
cJSON *cJSON_DetachItemFromObject(cJSON *object, const char *string); |
||||
void cJSON_DeleteItemFromObject(cJSON *object, const char *string); |
||||
|
||||
/* Update array items. */ |
||||
|
||||
void cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); |
||||
void cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem); |
||||
|
||||
#ifdef __cplusplus |
||||
} |
||||
#endif |
||||
|
||||
#endif /* __APPS_INCLUDE_NETUTILS_JSON_H */ |
@ -0,0 +1,18 @@
@@ -0,0 +1,18 @@
|
||||
# |
||||
# For a description of the syntax of this configuration file, |
||||
# see misc/tools/kconfig-language.txt. |
||||
# |
||||
|
||||
config NETUTILS_JSON |
||||
bool "cJSON library" |
||||
default n |
||||
---help--- |
||||
Enables the cJSON library. cJSON is an ultra-lightweight, portable, |
||||
single-file, simple-as-can-be ANSI-C compliant JSON parser, under MIT |
||||
license. Embeddable Lightweight XML-RPC Server discussed at |
||||
http://www.drdobbs.com/web-development/an-embeddable-lightweight-xml-rpc-server/184405364. |
||||
This code was taken from http://sourceforge.net/projects/cjson/ and |
||||
adapted for NuttX by Darcy Gong. |
||||
|
||||
if NETUTILS_JSON |
||||
endif |
@ -0,0 +1,91 @@
@@ -0,0 +1,91 @@
|
||||
############################################################################
|
||||
# apps/netutils/json/Makefile
|
||||
#
|
||||
# Copyright (C) 2012 Gregory Nutt. All rights reserved.
|
||||
# Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name NuttX nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
-include $(TOPDIR)/.config |
||||
-include $(TOPDIR)/Make.defs |
||||
include $(APPDIR)/Make.defs |
||||
|
||||
ASRCS =
|
||||
CSRCS = cJSON.c
|
||||
|
||||
AOBJS = $(ASRCS:.S=$(OBJEXT))
|
||||
COBJS = $(CSRCS:.c=$(OBJEXT))
|
||||
|
||||
SRCS = $(ASRCS) $(CSRCS)
|
||||
OBJS = $(AOBJS) $(COBJS)
|
||||
|
||||
ifeq ($(WINTOOL),y) |
||||
BIN = "${shell cygpath -w $(APPDIR)/libapps$(LIBEXT)}"
|
||||
else |
||||
BIN = "$(APPDIR)/libapps$(LIBEXT)"
|
||||
endif |
||||
|
||||
ROOTDEPPATH = --dep-path .
|
||||
|
||||
# Common build
|
||||
|
||||
VPATH =
|
||||
|
||||
all: .built |
||||
.PHONY: context depend clean distclean |
||||
|
||||
$(AOBJS): %$(OBJEXT): %.S |
||||
$(call ASSEMBLE, $<, $@)
|
||||
|
||||
$(COBJS): %$(OBJEXT): %.c |
||||
$(call COMPILE, $<, $@)
|
||||
|
||||
.built: $(OBJS) |
||||
@( for obj in $(OBJS) ; do \
|
||||
$(call ARCHIVE, $(BIN), $${obj}); \
|
||||
done ; )
|
||||
@touch .built
|
||||
|
||||
context: |
||||
|
||||
.depend: Makefile $(SRCS) |
||||
@$(MKDEP) $(ROOTDEPPATH) $(CC) -- $(CFLAGS) -- $(SRCS) >Make.dep
|
||||
@touch $@
|
||||
|
||||
depend: .depend |
||||
|
||||
clean: |
||||
@rm -f *.o *~ .*.swp .built
|
||||
$(call CLEAN)
|
||||
|
||||
distclean: clean |
||||
@rm -f Make.dep .depend
|
||||
|
||||
-include Make.dep |
@ -0,0 +1,258 @@
@@ -0,0 +1,258 @@
|
||||
apps/netutils/json/README.txt |
||||
============================= |
||||
|
||||
This directory contains logic taken from the cJSON project: |
||||
|
||||
http://sourceforge.net/projects/cjson/ |
||||
|
||||
This corresponds to SVN revision r42 (with lots of changes for NuttX coding |
||||
standards). As of r42, the SVN repository was last updated on 2011-10-10 |
||||
so I presume that the code is stable and there is no risk of maintaining |
||||
duplicate logic in the NuttX repository. |
||||
|
||||
Contents |
||||
======== |
||||
|
||||
o License |
||||
o Welcome to cJSON |
||||
|
||||
License |
||||
======= |
||||
|
||||
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. |
||||
|
||||
Welcome to cJSON |
||||
================ |
||||
|
||||
cJSON aims to be the dumbest possible parser that you can get your job done with. |
||||
It's a single file of C, and a single header file. |
||||
|
||||
JSON is described best here: http://www.json.org/ |
||||
It's like XML, but fat-free. You use it to move data around, store things, or just |
||||
generally represent your program's state. |
||||
|
||||
First up, how do I build? |
||||
Add cJSON.c to your project, and put cJSON.h somewhere in the header search path. |
||||
For example, to build the test app: |
||||
|
||||
gcc cJSON.c test.c -o test -lm |
||||
./test |
||||
|
||||
As a library, cJSON exists to take away as much legwork as it can, but not get in your way. |
||||
As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it |
||||
in one of two modes: Auto and Manual. Let's have a quick run-through. |
||||
|
||||
I lifted some JSON from this page: http://www.json.org/fatfree.html |
||||
That page inspired me to write cJSON, which is a parser that tries to share the same |
||||
philosophy as JSON itself. Simple, dumb, out of the way. |
||||
|
||||
Some JSON: |
||||
{ |
||||
"name": "Jack (\"Bee\") Nimble", |
||||
"format": { |
||||
"type": "rect", |
||||
"width": 1920, |
||||
"height": 1080, |
||||
"interlace": false, |
||||
"frame rate": 24 |
||||
} |
||||
} |
||||
|
||||
Assume that you got this from a file, a webserver, or magic JSON elves, whatever, |
||||
you have a char * to it. Everything is a cJSON struct. |
||||
Get it parsed: |
||||
cJSON *root = cJSON_Parse(my_json_string); |
||||
|
||||
This is an object. We're in C. We don't have objects. But we do have structs. |
||||
What's the framerate? |
||||
|
||||
cJSON *format = cJSON_GetObjectItem(root,"format"); |
||||
int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint; |
||||
|
||||
Want to change the framerate? |
||||
cJSON_GetObjectItem(format,"frame rate")->valueint=25; |
||||
|
||||
Back to disk? |
||||
char *rendered=cJSON_Print(root); |
||||
|
||||
Finished? Delete the root (this takes care of everything else). |
||||
cJSON_Delete(root); |
||||
|
||||
That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers |
||||
before you dereference them. If you want to see how you'd build this struct in code? |
||||
cJSON *root,*fmt; |
||||
root=cJSON_CreateObject(); |
||||
cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); |
||||
cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); |
||||
cJSON_AddStringToObject(fmt,"type", "rect"); |
||||
cJSON_AddNumberToObject(fmt,"width", 1920); |
||||
cJSON_AddNumberToObject(fmt,"height", 1080); |
||||
cJSON_AddFalseToObject (fmt,"interlace"); |
||||
cJSON_AddNumberToObject(fmt,"frame rate", 24); |
||||
|
||||
Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. |
||||
Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and |
||||
a few from elsewhere. |
||||
|
||||
What about manual mode? First up you need some detail. |
||||
Let's cover how the cJSON objects represent the JSON data. |
||||
cJSON doesn't distinguish arrays from objects in handling; just type. |
||||
Each cJSON has, potentially, a child, siblings, value, a name. |
||||
|
||||
The root object has: Object Type and a Child |
||||
The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: |
||||
Sibling has type Object, name "format", and a child. |
||||
That child has type String, name "type", value "rect", and a sibling: |
||||
Sibling has type Number, name "width", value 1920, and a sibling: |
||||
Sibling has type Number, name "height", value 1080, and a sibling: |
||||
Sibling hs type False, name "interlace", and a sibling: |
||||
Sibling has type Number, name "frame rate", value 24 |
||||
|
||||
Here's the structure: |
||||
typedef struct cJSON { |
||||
struct cJSON *next,*prev; |
||||
struct cJSON *child; |
||||
|
||||
int type; |
||||
|
||||
char *valuestring; |
||||
int valueint; |
||||
double valuedouble; |
||||
|
||||
char *string; |
||||
} cJSON; |
||||
|
||||
By default all values are 0 unless set by virtue of being meaningful. |
||||
|
||||
next/prev is a doubly linked list of siblings. next takes you to your sibling, |
||||
prev takes you back from your sibling to you. |
||||
Only objects and arrays have a "child", and it's the head of the doubly linked list. |
||||
A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0. |
||||
The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in |
||||
cJSON.h |
||||
|
||||
A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read |
||||
valuedouble. |
||||
|
||||
Any entry which is in the linked list which is the child of an object will have a "string" |
||||
which is the "name" of the entry. When I said "name" in the above example, that's "string". |
||||
"string" is the JSON name for the 'variable name' if you will. |
||||
|
||||
Now you can trivially walk the lists, recursively, and parse as you please. |
||||
You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take |
||||
the root object, and traverse the structure (which is, formally, an N-tree), |
||||
and tokenise as you please. If you wanted to build a callback style parser, this is how |
||||
you'd do it (just an example, since these things are very specific): |
||||
|
||||
void parse_and_callback(cJSON *item,const char *prefix) |
||||
{ |
||||
while (item) |
||||
{ |
||||
char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2); |
||||
sprintf(newprefix,"%s/%s",prefix,item->name); |
||||
int dorecurse=callback(newprefix, item->type, item); |
||||
if (item->child && dorecurse) parse_and_callback(item->child,newprefix); |
||||
item=item->next; |
||||
free(newprefix); |
||||
} |
||||
} |
||||
|
||||
The prefix process will build you a separated list, to simplify your callback handling. |
||||
The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or |
||||
let you invoke it per-item. For the item above, your callback might look like this: |
||||
|
||||
int callback(const char *name,int type,cJSON *item) |
||||
{ |
||||
if (!strcmp(name,"name")) { /* populate name */ } |
||||
else if (!strcmp(name,"format/type") { /* handle "rect" */ } |
||||
else if (!strcmp(name,"format/width") { /* 800 */ } |
||||
else if (!strcmp(name,"format/height") { /* 600 */ } |
||||
else if (!strcmp(name,"format/interlace") { /* false */ } |
||||
else if (!strcmp(name,"format/frame rate") { /* 24 */ } |
||||
return 1; |
||||
} |
||||
|
||||
Alternatively, you might like to parse iteratively. |
||||
You'd use: |
||||
|
||||
void parse_object(cJSON *item) |
||||
{ |
||||
int i; for (i=0;i<cJSON_GetArraySize(item);i++) |
||||
{ |
||||
cJSON *subitem=cJSON_GetArrayItem(item,i); |
||||
// handle subitem. |
||||
} |
||||
} |
||||
|
||||
Or, for PROPER manual mode: |
||||
|
||||
void parse_object(cJSON *item) |
||||
{ |
||||
cJSON *subitem=item->child; |
||||
while (subitem) |
||||
{ |
||||
// handle subitem |
||||
if (subitem->child) parse_object(subitem->child); |
||||
|
||||
subitem=subitem->next; |
||||
} |
||||
} |
||||
|
||||
Of course, this should look familiar, since this is just a stripped-down version |
||||
of the callback-parser. |
||||
|
||||
This should cover most uses you'll find for parsing. The rest should be possible |
||||
to infer.. and if in doubt, read the source! There's not a lot of it! ;) |
||||
|
||||
In terms of constructing JSON data, the example code above is the right way to do it. |
||||
You can, of course, hand your sub-objects to other functions to populate. |
||||
Also, if you find a use for it, you can manually build the objects. |
||||
For instance, suppose you wanted to build an array of objects? |
||||
|
||||
cJSON *objects[24]; |
||||
|
||||
cJSON *Create_array_of_anything(cJSON **items,int num) |
||||
{ |
||||
int i;cJSON *prev, *root=cJSON_CreateArray(); |
||||
for (i=0;i<24;i++) |
||||
{ |
||||
if (!i) root->child=objects[i]; |
||||
else prev->next=objects[i], objects[i]->prev=prev; |
||||
prev=objects[i]; |
||||
} |
||||
return root; |
||||
} |
||||
|
||||
and simply: Create_array_of_anything(objects,24); |
||||
|
||||
cJSON doesn't make any assumptions about what order you create things in. |
||||
You can attach the objects, as above, and later add children to each |
||||
of those objects. |
||||
|
||||
As soon as you call cJSON_Print, it renders the structure to text. |
||||
|
||||
The test.c code shows how to handle a bunch of typical cases. If you uncomment |
||||
the code, it'll load, parse and print a bunch of test files, also from json.org, |
||||
which are more complex than I'd care to try and stash into a const char array[]. |
||||
|
||||
Enjoy cJSON! |
||||
|
||||
- Dave Gamble, Aug 2009 |
Loading…
Reference in new issue