├── .gitignore ├── LICENSE ├── README ├── cJSON ├── LICENSE ├── README ├── cJSON.c └── cJSON.h ├── cobj.c ├── cobj.h ├── test.c └── vc8prj ├── test.sln └── test.vcproj /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Libraries 12 | *.lib 13 | *.a 14 | *.la 15 | *.lo 16 | 17 | # Shared objects (inc. Windows DLLs) 18 | *.dll 19 | *.so 20 | *.so.* 21 | *.dylib 22 | 23 | # Executables 24 | *.exe 25 | *.out 26 | *.app 27 | *.i*86 28 | *.x86_64 29 | *.hex 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 xphh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 xphh 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 all 12 | 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 THE 20 | SOFTWARE. 21 | */ 22 | 23 | Welcome to cobj. 24 | 25 | ============================== 26 | What's cobj? 27 | ============================== 28 | cobj is a simple implementation of C object with reflection function, which 29 | is very common in Java. An object defined by cobj's rules can easily convert 30 | to/from Json string automatically. 31 | 32 | The source code of cobj project is brief, which contains: 33 | cobj.h --- header file of cobj 34 | cobj.c --- implementation 35 | test.c --- test code for demo 36 | cJSON/ --- cJSON directory 37 | cJSON.h 38 | cJSON.c 39 | 40 | You can add cobj.h and cobj.c files into your project directly as you wish. 41 | Also if you just want to compile and test cobj only, build like this: 42 | gcc cobj.c test.c cJSON/cJSON.c -o test -lm 43 | and run test: 44 | ./test 45 | 46 | ============================== 47 | Things you must know! 48 | ============================== 49 | As you have seen before, cobj is rely on cJSON to convert between objects and 50 | Json strings. cobj project already contains cJSON source code in cJSON directory, 51 | but you might prefer the latest version of cJSON, just visit here: 52 | http://sourceforge.net/projects/cjson/ 53 | 54 | The first thing you need to know is that cobj makes the rules for defining an 55 | object. The object must be defined as cobj need, or it cannot be convert 56 | to/from Json string automatically. You can learn it in 'How to use' chapter. 57 | 58 | A cobj-need object is only support a few data types now, which are listed below: 59 | int --- integer 60 | BOOL --- boolean, typedef from int 61 | CSTR --- const string, defined in cobj 62 | struct --- custom-declared structure 63 | DECALRE_LIST(int) --- array list of int 64 | DECALRE_LIST(CSTR) --- array list of CSTR 65 | DECALRE_LIST(struct) --- array list of struct 66 | 67 | cobj provides two custom types for use: 68 | 69 | CSTR --- Actually it is a struct contains a char pointer. 70 | To initialize a CSTR, use 'CS' macro: CSTR s = CS("hello word"); 71 | To delete a CSTR, use 'CS_CLEAR' macro: CS_CLEAR(s); 72 | or memory leak might occur. 73 | 74 | list --- Define with 'DECALRE_LIST' macro, can be generic. 75 | To initialize a list, use 'LIST_INIT' macro. 76 | To delete a list, use 'LIST_CLEAR' macro. 77 | Before deleting a list, make sure you have freed the items inside. 78 | For more details, please read cobj.h. 79 | 80 | ============================== 81 | How to use cobj? 82 | ============================== 83 | The way to make C object with reflection function possible is to adhere an 84 | additional 'metainfo' to this object. A metainfo saves the hierarchy 85 | information of an object's structure. Therefore you need to declare object's 86 | structure and metainfo at the same time. 87 | 88 | metainfo must be defined in .c files, start with 'DEFINE_METAINFO' macro. 89 | 90 | Think a structure declared like this: 91 | struct BigBox 92 | { 93 | int pen; 94 | CSTR text; 95 | } 96 | Then the corresponding metainfo is like this: 97 | DEFINE_METAINFO(BigBox) 98 | { 99 | // must create it on first line 100 | METAINFO_CREATE(BigBox); 101 | // add members, the parameters are: 102 | // (structure name, member data type, member name) 103 | METAINFO_ADD_MEMBER(BigBox, FIELD_TYPE_INT, pen); 104 | METAINFO_ADD_MEMBER(BigBox, FIELD_TYPE_CSTR, text); 105 | } 106 | 107 | Structure can nest structure if like this: 108 | struct BigBox 109 | { 110 | struct SmallBox 111 | { 112 | int pen; 113 | CSTR text; 114 | } sb; 115 | } 116 | which metainfo is like this: 117 | DEFINE_METAINFO(BigBox) 118 | { 119 | // must create it on first line 120 | METAINFO_CREATE(BigBox); 121 | // 'SmallBox' begin, the parameters are: 122 | // (outer structure name, inner structure name, member name) 123 | METAINFO_CHILD_BEGIN(BigBox, SmallBox, sb); 124 | // add members 125 | METAINFO_ADD_MEMBER(SmallBox, FIELD_TYPE_INT, pen); 126 | METAINFO_ADD_MEMBER(SmallBox, FIELD_TYPE_CSTR, text); 127 | // 'SmallBox' end 128 | METAINFO_CHILD_END(); 129 | } 130 | 131 | In many cases, we need define a list, think about this: 132 | struct BigBox 133 | { 134 | DECLARE_LIST(int) penList; 135 | DECLARE_LIST(struct SmallBox 136 | { 137 | int pen; 138 | CSTR text; 139 | }) sbList; 140 | } 141 | which metainfo is like this: 142 | DEFINE_METAINFO(BigBox) 143 | { 144 | // must create it on first line 145 | METAINFO_CREATE(BigBox); 146 | // add a member as list, the parameters are the same. 147 | METAINFO_ADD_MEMBER_LIST(BigBox, FIELD_TYPE_INT, penList); 148 | // 'SmallBox' list begin, the parameters are the same. 149 | METAINFO_CHILD_LIST_BEGIN(BigBox, SmallBox, sbList); 150 | // add members 151 | METAINFO_ADD_MEMBER(SmallBox, FIELD_TYPE_INT, pen); 152 | METAINFO_ADD_MEMBER(SmallBox, FIELD_TYPE_CSTR, text); 153 | // 'SmallBox' end, the same. 154 | METAINFO_CHILD_END(); 155 | } 156 | 157 | After metainfo created, you must register it at the beginning of your program: 158 | REGISTER_METAINFO(BigBox); 159 | 160 | At this point, the prepare works are done. 161 | 162 | To new an object from a struct('s' for name), will return a pointer: 163 | OBJECT_NEW(s) 164 | To delete an object(point to ptr) and free all memories inside: 165 | OBJECT_DELETE(ptr, s) 166 | To convert an object('s' for object's struct name) to a json string: 167 | OBJECT_TO_JSON(ptr, s) 168 | To convert from a json string('str'), will return a pointer to object of s: 169 | OBJECT_FROM_JSON(s, str) 170 | 171 | Want to learn more? Please read and run test.c. 172 | 173 | ============================== 174 | About author 175 | ============================== 176 | cobj is written by xphh(Ping Xu), lived in Hangzhou, China. 177 | Bug report and communication, please send E-mail: netten2005@163.com 178 | 179 | -------------------------------------------------------------------------------- /cJSON/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Dave Gamble 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /cJSON/README: -------------------------------------------------------------------------------- 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 | Welcome to cJSON. 24 | 25 | cJSON aims to be the dumbest possible parser that you can get your job done with. 26 | It's a single file of C, and a single header file. 27 | 28 | JSON is described best here: http://www.json.org/ 29 | It's like XML, but fat-free. You use it to move data around, store things, or just 30 | generally represent your program's state. 31 | 32 | 33 | First up, how do I build? 34 | Add cJSON.c to your project, and put cJSON.h somewhere in the header search path. 35 | For example, to build the test app: 36 | 37 | gcc cJSON.c test.c -o test -lm 38 | ./test 39 | 40 | 41 | As a library, cJSON exists to take away as much legwork as it can, but not get in your way. 42 | As a point of pragmatism (i.e. ignoring the truth), I'm going to say that you can use it 43 | in one of two modes: Auto and Manual. Let's have a quick run-through. 44 | 45 | 46 | I lifted some JSON from this page: http://www.json.org/fatfree.html 47 | That page inspired me to write cJSON, which is a parser that tries to share the same 48 | philosophy as JSON itself. Simple, dumb, out of the way. 49 | 50 | Some JSON: 51 | { 52 | "name": "Jack (\"Bee\") Nimble", 53 | "format": { 54 | "type": "rect", 55 | "width": 1920, 56 | "height": 1080, 57 | "interlace": false, 58 | "frame rate": 24 59 | } 60 | } 61 | 62 | Assume that you got this from a file, a webserver, or magic JSON elves, whatever, 63 | you have a char * to it. Everything is a cJSON struct. 64 | Get it parsed: 65 | cJSON *root = cJSON_Parse(my_json_string); 66 | 67 | This is an object. We're in C. We don't have objects. But we do have structs. 68 | What's the framerate? 69 | 70 | cJSON *format = cJSON_GetObjectItem(root,"format"); 71 | int framerate = cJSON_GetObjectItem(format,"frame rate")->valueint; 72 | 73 | 74 | Want to change the framerate? 75 | cJSON_GetObjectItem(format,"frame rate")->valueint=25; 76 | 77 | Back to disk? 78 | char *rendered=cJSON_Print(root); 79 | 80 | Finished? Delete the root (this takes care of everything else). 81 | cJSON_Delete(root); 82 | 83 | That's AUTO mode. If you're going to use Auto mode, you really ought to check pointers 84 | before you dereference them. If you want to see how you'd build this struct in code? 85 | cJSON *root,*fmt; 86 | root=cJSON_CreateObject(); 87 | cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); 88 | cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); 89 | cJSON_AddStringToObject(fmt,"type", "rect"); 90 | cJSON_AddNumberToObject(fmt,"width", 1920); 91 | cJSON_AddNumberToObject(fmt,"height", 1080); 92 | cJSON_AddFalseToObject (fmt,"interlace"); 93 | cJSON_AddNumberToObject(fmt,"frame rate", 24); 94 | 95 | Hopefully we can agree that's not a lot of code? There's no overhead, no unnecessary setup. 96 | Look at test.c for a bunch of nice examples, mostly all ripped off the json.org site, and 97 | a few from elsewhere. 98 | 99 | What about manual mode? First up you need some detail. 100 | Let's cover how the cJSON objects represent the JSON data. 101 | cJSON doesn't distinguish arrays from objects in handling; just type. 102 | Each cJSON has, potentially, a child, siblings, value, a name. 103 | 104 | The root object has: Object Type and a Child 105 | The Child has name "name", with value "Jack ("Bee") Nimble", and a sibling: 106 | Sibling has type Object, name "format", and a child. 107 | That child has type String, name "type", value "rect", and a sibling: 108 | Sibling has type Number, name "width", value 1920, and a sibling: 109 | Sibling has type Number, name "height", value 1080, and a sibling: 110 | Sibling hs type False, name "interlace", and a sibling: 111 | Sibling has type Number, name "frame rate", value 24 112 | 113 | Here's the structure: 114 | typedef struct cJSON { 115 | struct cJSON *next,*prev; 116 | struct cJSON *child; 117 | 118 | int type; 119 | 120 | char *valuestring; 121 | int valueint; 122 | double valuedouble; 123 | 124 | char *string; 125 | } cJSON; 126 | 127 | By default all values are 0 unless set by virtue of being meaningful. 128 | 129 | next/prev is a doubly linked list of siblings. next takes you to your sibling, 130 | prev takes you back from your sibling to you. 131 | Only objects and arrays have a "child", and it's the head of the doubly linked list. 132 | A "child" entry will have prev==0, but next potentially points on. The last sibling has next=0. 133 | The type expresses Null/True/False/Number/String/Array/Object, all of which are #defined in 134 | cJSON.h 135 | 136 | A Number has valueint and valuedouble. If you're expecting an int, read valueint, if not read 137 | valuedouble. 138 | 139 | Any entry which is in the linked list which is the child of an object will have a "string" 140 | which is the "name" of the entry. When I said "name" in the above example, that's "string". 141 | "string" is the JSON name for the 'variable name' if you will. 142 | 143 | Now you can trivially walk the lists, recursively, and parse as you please. 144 | You can invoke cJSON_Parse to get cJSON to parse for you, and then you can take 145 | the root object, and traverse the structure (which is, formally, an N-tree), 146 | and tokenise as you please. If you wanted to build a callback style parser, this is how 147 | you'd do it (just an example, since these things are very specific): 148 | 149 | void parse_and_callback(cJSON *item,const char *prefix) 150 | { 151 | while (item) 152 | { 153 | char *newprefix=malloc(strlen(prefix)+strlen(item->name)+2); 154 | sprintf(newprefix,"%s/%s",prefix,item->name); 155 | int dorecurse=callback(newprefix, item->type, item); 156 | if (item->child && dorecurse) parse_and_callback(item->child,newprefix); 157 | item=item->next; 158 | free(newprefix); 159 | } 160 | } 161 | 162 | The prefix process will build you a separated list, to simplify your callback handling. 163 | The 'dorecurse' flag would let the callback decide to handle sub-arrays on it's own, or 164 | let you invoke it per-item. For the item above, your callback might look like this: 165 | 166 | int callback(const char *name,int type,cJSON *item) 167 | { 168 | if (!strcmp(name,"name")) { /* populate name */ } 169 | else if (!strcmp(name,"format/type") { /* handle "rect" */ } 170 | else if (!strcmp(name,"format/width") { /* 800 */ } 171 | else if (!strcmp(name,"format/height") { /* 600 */ } 172 | else if (!strcmp(name,"format/interlace") { /* false */ } 173 | else if (!strcmp(name,"format/frame rate") { /* 24 */ } 174 | return 1; 175 | } 176 | 177 | Alternatively, you might like to parse iteratively. 178 | You'd use: 179 | 180 | void parse_object(cJSON *item) 181 | { 182 | int i; for (i=0;ichild; 194 | while (subitem) 195 | { 196 | // handle subitem 197 | if (subitem->child) parse_object(subitem->child); 198 | 199 | subitem=subitem->next; 200 | } 201 | } 202 | 203 | Of course, this should look familiar, since this is just a stripped-down version 204 | of the callback-parser. 205 | 206 | This should cover most uses you'll find for parsing. The rest should be possible 207 | to infer.. and if in doubt, read the source! There's not a lot of it! ;) 208 | 209 | 210 | In terms of constructing JSON data, the example code above is the right way to do it. 211 | You can, of course, hand your sub-objects to other functions to populate. 212 | Also, if you find a use for it, you can manually build the objects. 213 | For instance, suppose you wanted to build an array of objects? 214 | 215 | cJSON *objects[24]; 216 | 217 | cJSON *Create_array_of_anything(cJSON **items,int num) 218 | { 219 | int i;cJSON *prev, *root=cJSON_CreateArray(); 220 | for (i=0;i<24;i++) 221 | { 222 | if (!i) root->child=objects[i]; 223 | else prev->next=objects[i], objects[i]->prev=prev; 224 | prev=objects[i]; 225 | } 226 | return root; 227 | } 228 | 229 | and simply: Create_array_of_anything(objects,24); 230 | 231 | cJSON doesn't make any assumptions about what order you create things in. 232 | You can attach the objects, as above, and later add children to each 233 | of those objects. 234 | 235 | As soon as you call cJSON_Print, it renders the structure to text. 236 | 237 | 238 | 239 | The test.c code shows how to handle a bunch of typical cases. If you uncomment 240 | the code, it'll load, parse and print a bunch of test files, also from json.org, 241 | which are more complex than I'd care to try and stash into a const char array[]. 242 | 243 | 244 | Enjoy cJSON! 245 | 246 | 247 | - Dave Gamble, Aug 2009 248 | -------------------------------------------------------------------------------- /cJSON/cJSON.c: -------------------------------------------------------------------------------- 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 | #define _CRT_SECURE_NO_WARNINGS 23 | 24 | /* cJSON */ 25 | /* JSON parser in C. */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "cJSON.h" 35 | 36 | static const char *ep; 37 | 38 | const char *cJSON_GetErrorPtr(void) {return ep;} 39 | 40 | static int cJSON_strcasecmp(const char *s1,const char *s2) 41 | { 42 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; 43 | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; 44 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 45 | } 46 | 47 | static void *(*cJSON_malloc)(size_t sz) = malloc; 48 | static void (*cJSON_free)(void *ptr) = free; 49 | 50 | static char* cJSON_strdup(const char* str) 51 | { 52 | size_t len; 53 | char* copy; 54 | 55 | len = strlen(str) + 1; 56 | if (!(copy = (char*)cJSON_malloc(len))) return 0; 57 | memcpy(copy,str,len); 58 | return copy; 59 | } 60 | 61 | void cJSON_InitHooks(cJSON_Hooks* hooks) 62 | { 63 | if (!hooks) { /* Reset hooks */ 64 | cJSON_malloc = malloc; 65 | cJSON_free = free; 66 | return; 67 | } 68 | 69 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 70 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 71 | } 72 | 73 | /* Internal constructor. */ 74 | static cJSON *cJSON_New_Item(void) 75 | { 76 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 77 | if (node) memset(node,0,sizeof(cJSON)); 78 | return node; 79 | } 80 | 81 | /* Delete a cJSON structure. */ 82 | void cJSON_Delete(cJSON *c) 83 | { 84 | cJSON *next; 85 | while (c) 86 | { 87 | next=c->next; 88 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 89 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 90 | if (c->string) cJSON_free(c->string); 91 | cJSON_free(c); 92 | c=next; 93 | } 94 | } 95 | 96 | /* Parse the input text to generate a number, and populate the result into item. */ 97 | static const char *parse_number(cJSON *item,const char *num) 98 | { 99 | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; 100 | 101 | if (*num=='-') sign=-1,num++; /* Has sign? */ 102 | if (*num=='0') num++; /* is zero */ 103 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 104 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ 105 | if (*num=='e' || *num=='E') /* Exponent? */ 106 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ 107 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ 108 | } 109 | 110 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 111 | 112 | item->valuedouble=n; 113 | item->valueint=(int)n; 114 | item->type=cJSON_Number; 115 | return num; 116 | } 117 | 118 | /* Render the number nicely from the given item into a string. */ 119 | static char *print_number(cJSON *item) 120 | { 121 | char *str; 122 | double d=item->valuedouble; 123 | if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) 124 | { 125 | str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 126 | if (str) sprintf(str,"%d",item->valueint); 127 | } 128 | else 129 | { 130 | str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 131 | if (str) 132 | { 133 | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); 134 | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); 135 | else sprintf(str,"%f",d); 136 | } 137 | } 138 | return str; 139 | } 140 | 141 | static unsigned parse_hex4(const char *str) 142 | { 143 | unsigned h=0; 144 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; 145 | h=h<<4;str++; 146 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; 147 | h=h<<4;str++; 148 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; 149 | h=h<<4;str++; 150 | if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0; 151 | return h; 152 | } 153 | 154 | /* Parse the input text into an unescaped cstring, and populate item. */ 155 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 156 | static const char *parse_string(cJSON *item,const char *str) 157 | { 158 | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; 159 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ 160 | 161 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ 162 | 163 | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 164 | if (!out) return 0; 165 | 166 | ptr=str+1;ptr2=out; 167 | while (*ptr!='\"' && *ptr) 168 | { 169 | if (*ptr!='\\') *ptr2++=*ptr++; 170 | else 171 | { 172 | ptr++; 173 | switch (*ptr) 174 | { 175 | case 'b': *ptr2++='\b'; break; 176 | case 'f': *ptr2++='\f'; break; 177 | case 'n': *ptr2++='\n'; break; 178 | case 'r': *ptr2++='\r'; break; 179 | case 't': *ptr2++='\t'; break; 180 | case 'u': /* transcode utf16 to utf8. */ 181 | uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ 182 | 183 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ 184 | 185 | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 186 | { 187 | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ 188 | uc2=parse_hex4(ptr+3);ptr+=6; 189 | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ 190 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 191 | } 192 | 193 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 194 | 195 | switch (len) { 196 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 197 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 198 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 199 | case 1: *--ptr2 =(uc | firstByteMark[len]); 200 | } 201 | ptr2+=len; 202 | break; 203 | default: *ptr2++=*ptr; break; 204 | } 205 | ptr++; 206 | } 207 | } 208 | *ptr2=0; 209 | if (*ptr=='\"') ptr++; 210 | item->valuestring=out; 211 | item->type=cJSON_String; 212 | return ptr; 213 | } 214 | 215 | /* Render the cstring provided to an escaped version that can be printed. */ 216 | static char *print_string_ptr(const char *str) 217 | { 218 | const char *ptr;char *ptr2,*out;int len=0;unsigned char token; 219 | 220 | if (!str) return cJSON_strdup(""); 221 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 222 | 223 | out=(char*)cJSON_malloc(len+3); 224 | if (!out) return 0; 225 | 226 | ptr2=out;ptr=str; 227 | *ptr2++='\"'; 228 | while (*ptr) 229 | { 230 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 231 | else 232 | { 233 | *ptr2++='\\'; 234 | switch (token=*ptr++) 235 | { 236 | case '\\': *ptr2++='\\'; break; 237 | case '\"': *ptr2++='\"'; break; 238 | case '\b': *ptr2++='b'; break; 239 | case '\f': *ptr2++='f'; break; 240 | case '\n': *ptr2++='n'; break; 241 | case '\r': *ptr2++='r'; break; 242 | case '\t': *ptr2++='t'; break; 243 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 244 | } 245 | } 246 | } 247 | *ptr2++='\"';*ptr2++=0; 248 | return out; 249 | } 250 | /* Invote print_string_ptr (which is useful) on an item. */ 251 | static char *print_string(cJSON *item) {return print_string_ptr(item->valuestring);} 252 | 253 | /* Predeclare these prototypes. */ 254 | static const char *parse_value(cJSON *item,const char *value); 255 | static char *print_value(cJSON *item,int depth,int fmt); 256 | static const char *parse_array(cJSON *item,const char *value); 257 | static char *print_array(cJSON *item,int depth,int fmt); 258 | static const char *parse_object(cJSON *item,const char *value); 259 | static char *print_object(cJSON *item,int depth,int fmt); 260 | 261 | /* Utility to jump whitespace and cr/lf */ 262 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 263 | 264 | /* Parse an object - create a new root, and populate. */ 265 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 266 | { 267 | const char *end=0; 268 | cJSON *c=cJSON_New_Item(); 269 | ep=0; 270 | if (!c) return 0; /* memory fail */ 271 | 272 | end=parse_value(c,skip(value)); 273 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 274 | 275 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 276 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} 277 | if (return_parse_end) *return_parse_end=end; 278 | return c; 279 | } 280 | /* Default options for cJSON_Parse */ 281 | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 282 | 283 | /* Render a cJSON item/entity/structure to text. */ 284 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1);} 285 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0);} 286 | 287 | /* Parser core - when encountering text, process appropriately. */ 288 | static const char *parse_value(cJSON *item,const char *value) 289 | { 290 | if (!value) return 0; /* Fail on null. */ 291 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 292 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 293 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 294 | if (*value=='\"') { return parse_string(item,value); } 295 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 296 | if (*value=='[') { return parse_array(item,value); } 297 | if (*value=='{') { return parse_object(item,value); } 298 | 299 | ep=value;return 0; /* failure. */ 300 | } 301 | 302 | /* Render a value to text. */ 303 | static char *print_value(cJSON *item,int depth,int fmt) 304 | { 305 | char *out=0; 306 | if (!item) return 0; 307 | switch ((item->type)&255) 308 | { 309 | case cJSON_NULL: out=cJSON_strdup("null"); break; 310 | case cJSON_False: out=cJSON_strdup("false");break; 311 | case cJSON_True: out=cJSON_strdup("true"); break; 312 | case cJSON_Number: out=print_number(item);break; 313 | case cJSON_String: out=print_string(item);break; 314 | case cJSON_Array: out=print_array(item,depth,fmt);break; 315 | case cJSON_Object: out=print_object(item,depth,fmt);break; 316 | } 317 | return out; 318 | } 319 | 320 | /* Build an array from input text. */ 321 | static const char *parse_array(cJSON *item,const char *value) 322 | { 323 | cJSON *child; 324 | if (*value!='[') {ep=value;return 0;} /* not an array! */ 325 | 326 | item->type=cJSON_Array; 327 | value=skip(value+1); 328 | if (*value==']') return value+1; /* empty array. */ 329 | 330 | item->child=child=cJSON_New_Item(); 331 | if (!item->child) return 0; /* memory fail */ 332 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ 333 | if (!value) return 0; 334 | 335 | while (*value==',') 336 | { 337 | cJSON *new_item; 338 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 339 | child->next=new_item;new_item->prev=child;child=new_item; 340 | value=skip(parse_value(child,skip(value+1))); 341 | if (!value) return 0; /* memory fail */ 342 | } 343 | 344 | if (*value==']') return value+1; /* end of array */ 345 | ep=value;return 0; /* malformed. */ 346 | } 347 | 348 | /* Render an array to text */ 349 | static char *print_array(cJSON *item,int depth,int fmt) 350 | { 351 | char **entries; 352 | char *out=0,*ptr,*ret;int len=5; 353 | cJSON *child=item->child; 354 | int numentries=0,i=0,fail=0; 355 | 356 | /* How many entries in the array? */ 357 | while (child) numentries++,child=child->next; 358 | /* Explicitly handle numentries==0 */ 359 | if (!numentries) 360 | { 361 | out=(char*)cJSON_malloc(3); 362 | if (out) strcpy(out,"[]"); 363 | return out; 364 | } 365 | /* Allocate an array to hold the values for each */ 366 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 367 | if (!entries) return 0; 368 | memset(entries,0,numentries*sizeof(char*)); 369 | /* Retrieve all the results: */ 370 | child=item->child; 371 | while (child && !fail) 372 | { 373 | ret=print_value(child,depth+1,fmt); 374 | entries[i++]=ret; 375 | if (ret) len+=(int)strlen(ret)+2+(fmt?1:0); else fail=1; 376 | child=child->next; 377 | } 378 | 379 | /* If we didn't fail, try to malloc the output string */ 380 | if (!fail) out=(char*)cJSON_malloc(len); 381 | /* If that fails, we fail. */ 382 | if (!out) fail=1; 383 | 384 | /* Handle failure. */ 385 | if (fail) 386 | { 387 | for (i=0;itype=cJSON_Object; 413 | value=skip(value+1); 414 | if (*value=='}') return value+1; /* empty array. */ 415 | 416 | item->child=child=cJSON_New_Item(); 417 | if (!item->child) return 0; 418 | value=skip(parse_string(child,skip(value))); 419 | if (!value) return 0; 420 | child->string=child->valuestring;child->valuestring=0; 421 | if (*value!=':') {ep=value;return 0;} /* fail! */ 422 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 423 | if (!value) return 0; 424 | 425 | while (*value==',') 426 | { 427 | cJSON *new_item; 428 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 429 | child->next=new_item;new_item->prev=child;child=new_item; 430 | value=skip(parse_string(child,skip(value+1))); 431 | if (!value) return 0; 432 | child->string=child->valuestring;child->valuestring=0; 433 | if (*value!=':') {ep=value;return 0;} /* fail! */ 434 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 435 | if (!value) return 0; 436 | } 437 | 438 | if (*value=='}') return value+1; /* end of array */ 439 | ep=value;return 0; /* malformed. */ 440 | } 441 | 442 | /* Render an object to text. */ 443 | static char *print_object(cJSON *item,int depth,int fmt) 444 | { 445 | char **entries=0,**names=0; 446 | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 447 | cJSON *child=item->child; 448 | int numentries=0,fail=0; 449 | /* Count the number of entries. */ 450 | while (child) numentries++,child=child->next; 451 | /* Explicitly handle empty object case */ 452 | if (!numentries) 453 | { 454 | out=(char*)cJSON_malloc(fmt?depth+4:3); 455 | if (!out) return 0; 456 | ptr=out;*ptr++='{'; 457 | if (fmt) {*ptr++='\n';for (i=0;ichild;depth++;if (fmt) len+=depth; 471 | while (child) 472 | { 473 | names[i]=str=print_string_ptr(child->string); 474 | entries[i++]=ret=print_value(child,depth,fmt); 475 | if (str && ret) len+=(int)strlen(ret)+(int)strlen(str)+2+(fmt?2+depth:0); else fail=1; 476 | child=child->next; 477 | } 478 | 479 | /* Try to allocate the output string */ 480 | if (!fail) out=(char*)cJSON_malloc(len); 481 | if (!out) fail=1; 482 | 483 | /* Handle failure */ 484 | if (fail) 485 | { 486 | for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} 512 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} 513 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} 514 | 515 | /* Utility for array list handling. */ 516 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 517 | /* Utility for handling references. */ 518 | static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;} 519 | 520 | /* Add item to array/object. */ 521 | void cJSON_AddItemToArray(cJSON *array, cJSON *item) {cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}} 522 | void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);} 523 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 524 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 525 | 526 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 527 | if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;} 528 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 529 | cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;} 530 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 531 | 532 | /* Replace array/object items with new ones. */ 533 | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 534 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 535 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 536 | void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}} 537 | 538 | /* Create basic types: */ 539 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 540 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 541 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 542 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 543 | cJSON *cJSON_CreateNumber(double num) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int)num;}return item;} 544 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} 545 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 546 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 547 | 548 | /* Create Arrays: */ 549 | cJSON *cJSON_CreateIntArray(const int *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 550 | cJSON *cJSON_CreateFloatArray(const float *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 551 | cJSON *cJSON_CreateDoubleArray(const double *numbers,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 552 | cJSON *cJSON_CreateStringArray(const char **strings,int count) {int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && ichild=n;else suffix_object(p,n);p=n;}return a;} 553 | 554 | /* Duplication */ 555 | cJSON *cJSON_Duplicate(cJSON *item,int recurse) 556 | { 557 | cJSON *newitem,*cptr,*nptr=0,*newchild; 558 | /* Bail on bad ptr */ 559 | if (!item) return 0; 560 | /* Create new item */ 561 | newitem=cJSON_New_Item(); 562 | if (!newitem) return 0; 563 | /* Copy over all vars */ 564 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 565 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 566 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 567 | /* If non-recursive, then we're done! */ 568 | if (!recurse) return newitem; 569 | /* Walk the ->next chain for the child. */ 570 | cptr=item->child; 571 | while (cptr) 572 | { 573 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 574 | if (!newchild) {cJSON_Delete(newitem);return 0;} 575 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 576 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 577 | cptr=cptr->next; 578 | } 579 | return newitem; 580 | } 581 | 582 | void cJSON_Minify(char *json) 583 | { 584 | char *into=json; 585 | while (*json) 586 | { 587 | if (*json==' ') json++; 588 | else if (*json=='\t') json++; // Whitespace characters. 589 | else if (*json=='\r') json++; 590 | else if (*json=='\n') json++; 591 | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; // double-slash comments, to end of line. 592 | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} // multiline comments. 593 | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} // string literals, which are \" sensitive. 594 | else *into++=*json++; // All other characters. 595 | } 596 | *into=0; // and null-terminate. 597 | } -------------------------------------------------------------------------------- /cJSON/cJSON.h: -------------------------------------------------------------------------------- 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 | #ifndef cJSON__h 24 | #define cJSON__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | /* cJSON Types: */ 32 | #define cJSON_False 0 33 | #define cJSON_True 1 34 | #define cJSON_NULL 2 35 | #define cJSON_Number 3 36 | #define cJSON_String 4 37 | #define cJSON_Array 5 38 | #define cJSON_Object 6 39 | 40 | #define cJSON_IsReference 256 41 | 42 | /* The cJSON structure: */ 43 | typedef struct cJSON { 44 | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 45 | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 46 | 47 | int type; /* The type of the item, as above. */ 48 | 49 | char *valuestring; /* The item's string, if type==cJSON_String */ 50 | int valueint; /* The item's number, if type==cJSON_Number */ 51 | double valuedouble; /* The item's number, if type==cJSON_Number */ 52 | 53 | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 54 | } cJSON; 55 | 56 | typedef struct cJSON_Hooks { 57 | void *(*malloc_fn)(size_t sz); 58 | void (*free_fn)(void *ptr); 59 | } cJSON_Hooks; 60 | 61 | /* Supply malloc, realloc and free functions to cJSON */ 62 | extern void cJSON_InitHooks(cJSON_Hooks* hooks); 63 | 64 | 65 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 66 | extern cJSON *cJSON_Parse(const char *value); 67 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 68 | extern char *cJSON_Print(cJSON *item); 69 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 70 | extern char *cJSON_PrintUnformatted(cJSON *item); 71 | /* Delete a cJSON entity and all subentities. */ 72 | extern void cJSON_Delete(cJSON *c); 73 | 74 | /* Returns the number of items in an array (or object). */ 75 | extern int cJSON_GetArraySize(cJSON *array); 76 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 77 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); 78 | /* Get item "string" from object. Case insensitive. */ 79 | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); 80 | 81 | /* 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. */ 82 | extern const char *cJSON_GetErrorPtr(void); 83 | 84 | /* These calls create a cJSON item of the appropriate type. */ 85 | extern cJSON *cJSON_CreateNull(void); 86 | extern cJSON *cJSON_CreateTrue(void); 87 | extern cJSON *cJSON_CreateFalse(void); 88 | extern cJSON *cJSON_CreateBool(int b); 89 | extern cJSON *cJSON_CreateNumber(double num); 90 | extern cJSON *cJSON_CreateString(const char *string); 91 | extern cJSON *cJSON_CreateArray(void); 92 | extern cJSON *cJSON_CreateObject(void); 93 | 94 | /* These utilities create an Array of count items. */ 95 | extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); 96 | extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); 97 | extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); 98 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); 99 | 100 | /* Append item to the specified array/object. */ 101 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 102 | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); 103 | /* 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. */ 104 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 105 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); 106 | 107 | /* Remove/Detatch items from Arrays/Objects. */ 108 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); 109 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); 110 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); 111 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); 112 | 113 | /* Update array items. */ 114 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); 115 | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 116 | 117 | /* Duplicate a cJSON item */ 118 | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); 119 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 120 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 121 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 122 | 123 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 124 | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); 125 | 126 | extern void cJSON_Minify(char *json); 127 | 128 | /* Macros for creating things quickly. */ 129 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 130 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 131 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 132 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 133 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 134 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 135 | 136 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 137 | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /cobj.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 xphh 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 all 12 | 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 THE 20 | SOFTWARE. 21 | */ 22 | #define _CRT_SECURE_NO_DEPRECATE 23 | #include "cobj.h" 24 | #include "cJSON/cJSON.h" 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #ifdef WIN32 31 | #define strdup _strdup 32 | #endif 33 | 34 | /************************************************************************/ 35 | /* const string */ 36 | /************************************************************************/ 37 | C_API const_string_t const_string_new(const char *str) 38 | { 39 | const_string_t cs; 40 | cs.cstr = strdup(str); 41 | return cs; 42 | } 43 | 44 | C_API void const_string_clear(const_string_t cs) 45 | { 46 | if (cs.cstr) 47 | { 48 | free(cs.cstr); 49 | } 50 | } 51 | 52 | /************************************************************************/ 53 | /* free buffer */ 54 | /************************************************************************/ 55 | #define BLOCK_SIZE 1024 56 | #define CEIL(n) (((n) + BLOCK_SIZE - 1) / BLOCK_SIZE * BLOCK_SIZE) 57 | 58 | C_API void free_buffer_init(free_buffer_t *buf) 59 | { 60 | memset(buf, 0, sizeof(free_buffer_t)); 61 | } 62 | 63 | C_API void free_buffer_append(free_buffer_t *buf, void *data, size_t len) 64 | { 65 | size_t need_len = buf->length + len + 1; 66 | if (need_len > buf->size) 67 | { 68 | size_t newlen = buf->length + len; 69 | size_t newsize = CEIL(need_len); 70 | 71 | char *newptr = (char *)malloc(newsize); 72 | memcpy(newptr, buf->ptr, buf->length); 73 | memcpy(newptr + buf->length, data, len); 74 | 75 | free(buf->ptr); 76 | buf->ptr = newptr; 77 | buf->length = newlen; 78 | buf->size = newsize; 79 | } 80 | else 81 | { 82 | memcpy(buf->ptr + buf->length, data, len); 83 | buf->length += len; 84 | } 85 | 86 | buf->ptr[buf->length] = 0; 87 | 88 | buf->count++; 89 | } 90 | 91 | C_API void free_buffer_append_empty(free_buffer_t *buf, size_t len) 92 | { 93 | void *data = malloc(len); 94 | memset(data, 0, len); 95 | free_buffer_append(buf, data, len); 96 | free(data); 97 | } 98 | 99 | C_API void free_buffer_cleanup(free_buffer_t *buf) 100 | { 101 | if (buf->ptr) 102 | { 103 | free(buf->ptr); 104 | } 105 | buf->ptr = NULL; 106 | buf->length = 0; 107 | buf->size = 0; 108 | buf->count = 0; 109 | } 110 | 111 | /************************************************************************/ 112 | /* metainfo */ 113 | /************************************************************************/ 114 | C_API metainfo_t *metainfo_create(int obj_size) 115 | { 116 | metainfo_t *mi = (metainfo_t *)malloc(sizeof(metainfo_t)); 117 | memset(mi, 0, sizeof(metainfo_t)); 118 | mi->obj_size = obj_size; 119 | return mi; 120 | } 121 | 122 | C_API void metainfo_destroy(metainfo_t *mi) 123 | { 124 | LIST_CLEAR(mi->fs); 125 | free(mi); 126 | } 127 | 128 | C_API void metainfo_add_member(metainfo_t *mi, int pos, int type, const char *name, int islist) 129 | { 130 | field_t f; 131 | f.pos = pos; 132 | f.type = type; 133 | f.islist = islist; 134 | f.name = name; 135 | f.metainfo = NULL; 136 | LIST_ADD_OBJ(mi->fs, f); 137 | } 138 | 139 | C_API metainfo_t *metainfo_add_child(metainfo_t *mi, int pos, int obj_size, const char *name, int islist) 140 | { 141 | metainfo_t *child = metainfo_create(obj_size); 142 | field_t f; 143 | f.pos = pos; 144 | f.type = FIELD_TYPE_STRUCT; 145 | f.islist = islist; 146 | f.name = name; 147 | f.metainfo = child; 148 | LIST_ADD_OBJ(mi->fs, f); 149 | return child; 150 | } 151 | 152 | /************************************************************************/ 153 | /* C Object */ 154 | /************************************************************************/ 155 | C_API void *cobject_new(metainfo_t *mi) 156 | { 157 | void *ptr = malloc(mi->obj_size); 158 | memset(ptr, 0, mi->obj_size); 159 | return ptr; 160 | } 161 | 162 | C_API void cobject_init(void *obj, metainfo_t *mi) 163 | { 164 | memset(obj, 0, mi->obj_size); 165 | } 166 | 167 | C_API void cobject_clear(void *obj, metainfo_t *mi) 168 | { 169 | int i; 170 | 171 | for (i = 0; i < mi->fs.size; i++) 172 | { 173 | field_t *f = &mi->fs.array[i]; 174 | void *ptr = ((char *)obj + f->pos); 175 | 176 | if (f->islist) 177 | { 178 | free_buffer_t *fb = (free_buffer_t *)ptr; 179 | int k; 180 | 181 | if (f->type == FIELD_TYPE_CSTR) 182 | { 183 | for (k = 0; k < fb->count; k++) 184 | { 185 | CSTR *p = (CSTR *)(fb->ptr + k * sizeof(CSTR)); 186 | CS_CLEAR(*p); 187 | } 188 | } 189 | else if (f->type == FIELD_TYPE_STRUCT) 190 | { 191 | for (k = 0; k < fb->count; k++) 192 | { 193 | metainfo_t *mi = (metainfo_t *)f->metainfo; 194 | void *obj = fb->ptr + k * mi->obj_size; 195 | cobject_clear(obj, mi); 196 | } 197 | } 198 | 199 | LIST_CLEAR(*fb); 200 | } 201 | else 202 | { 203 | if (f->type == FIELD_TYPE_INT) 204 | { 205 | int *p = (int *)ptr; 206 | *p = 0; 207 | } 208 | else if (f->type == FIELD_TYPE_BOOL) 209 | { 210 | BOOL *p = (BOOL *)ptr; 211 | *p = 0; 212 | } 213 | else if (f->type == FIELD_TYPE_CSTR) 214 | { 215 | CSTR *p = (CSTR *)ptr; 216 | CS_CLEAR(*p); 217 | } 218 | else if (f->type == FIELD_TYPE_STRUCT) 219 | { 220 | metainfo_t *mi = (metainfo_t *)f->metainfo; 221 | void *obj = ptr; 222 | cobject_clear(obj, mi); 223 | } 224 | } 225 | } 226 | } 227 | 228 | C_API void cobject_delete(void *obj, metainfo_t *mi) 229 | { 230 | cobject_clear(obj, mi); 231 | free(obj); 232 | } 233 | 234 | static cJSON *_to_jsonobject(void *obj, metainfo_t *mi) 235 | { 236 | cJSON *root = cJSON_CreateObject(); 237 | int i; 238 | 239 | for (i = 0; i < mi->fs.size; i++) 240 | { 241 | field_t *f = &mi->fs.array[i]; 242 | void *ptr = ((char *)obj + f->pos); 243 | 244 | if (f->islist) 245 | { 246 | free_buffer_t *fb = (free_buffer_t *)ptr; 247 | cJSON *array = NULL; 248 | 249 | if (f->type == FIELD_TYPE_INT) 250 | { 251 | array = cJSON_CreateIntArray((int *)fb->ptr, fb->count); 252 | } 253 | else if (f->type == FIELD_TYPE_CSTR) 254 | { 255 | array = cJSON_CreateStringArray((const char **)fb->ptr, fb->count); 256 | } 257 | else if (f->type == FIELD_TYPE_STRUCT) 258 | { 259 | int k; 260 | array = cJSON_CreateArray(); 261 | for (k = 0; k < fb->count; k++) 262 | { 263 | metainfo_t *mi = (metainfo_t *)f->metainfo; 264 | void *obj = fb->ptr + k * mi->obj_size; 265 | cJSON *item = _to_jsonobject(obj, mi); 266 | cJSON_AddItemToArray(array, item); 267 | } 268 | } 269 | 270 | if (array) 271 | { 272 | cJSON_AddItemToObject(root, f->name, array); 273 | } 274 | } 275 | else 276 | { 277 | if (f->type == FIELD_TYPE_INT) 278 | { 279 | int *p = (int *)ptr; 280 | cJSON_AddNumberToObject(root, f->name, *p); 281 | } 282 | else if (f->type == FIELD_TYPE_BOOL) 283 | { 284 | BOOL *p = (BOOL *)ptr; 285 | if (*p) 286 | { 287 | cJSON_AddTrueToObject(root, f->name); 288 | } 289 | else 290 | { 291 | cJSON_AddFalseToObject(root, f->name); 292 | } 293 | } 294 | else if (f->type == FIELD_TYPE_CSTR) 295 | { 296 | CSTR *p = (CSTR *)ptr; 297 | if (p->cstr) 298 | { 299 | cJSON_AddStringToObject(root, f->name, p->cstr); 300 | } 301 | else 302 | { 303 | cJSON_AddStringToObject(root, f->name, ""); 304 | } 305 | } 306 | else if (f->type == FIELD_TYPE_STRUCT) 307 | { 308 | cJSON * child = _to_jsonobject(ptr, f->metainfo); 309 | cJSON_AddItemToObject(root, f->name, child); 310 | } 311 | } 312 | } 313 | 314 | return root; 315 | } 316 | 317 | C_API CSTR cobject_to_json(void *obj, metainfo_t *mi) 318 | { 319 | const_string_t cs = {NULL}; 320 | cJSON *json; 321 | 322 | if (!obj || !mi) 323 | { 324 | return cs; 325 | } 326 | 327 | json = _to_jsonobject(obj, mi); 328 | 329 | cs.cstr = cJSON_Print(json); 330 | 331 | cJSON_Delete(json); 332 | 333 | return cs; 334 | } 335 | 336 | static void _from_jsonobject(void *obj, metainfo_t *mi, cJSON *json) 337 | { 338 | int i; 339 | for (i = 0; i < mi->fs.size; i++) 340 | { 341 | field_t *f = &mi->fs.array[i]; 342 | void *ptr = ((char *)obj + f->pos); 343 | 344 | cJSON *item = cJSON_GetObjectItem(json, f->name); 345 | if (!item) 346 | { 347 | continue; 348 | } 349 | 350 | if (f->islist) 351 | { 352 | free_buffer_t *fb = (free_buffer_t *)ptr; 353 | 354 | if (item->type == cJSON_Array) 355 | { 356 | cJSON *array = item; 357 | int size = cJSON_GetArraySize(array); 358 | int k; 359 | for (k = 0; k < size; k++) 360 | { 361 | cJSON *item = cJSON_GetArrayItem(array, k); 362 | if (f->type == FIELD_TYPE_INT) 363 | { 364 | if (item->type == cJSON_Number) 365 | { 366 | LIST_ADD_INT(*fb, item->valueint); 367 | } 368 | } 369 | else if (f->type == FIELD_TYPE_CSTR) 370 | { 371 | if (item->type == cJSON_String) 372 | { 373 | LIST_ADD_STR(*fb, item->valuestring); 374 | } 375 | } 376 | else if (f->type == FIELD_TYPE_STRUCT) 377 | { 378 | if (item->type == cJSON_Object) 379 | { 380 | metainfo_t *mi = (metainfo_t *)f->metainfo; 381 | void *obj = cobject_new(mi); 382 | _from_jsonobject(obj, mi, item); 383 | free_buffer_append(fb, obj, mi->obj_size); 384 | free(obj); 385 | } 386 | } 387 | } 388 | } 389 | } 390 | else 391 | { 392 | if (f->type == FIELD_TYPE_INT) 393 | { 394 | int *p = (int *)ptr; 395 | if (item->type == cJSON_Number) 396 | { 397 | *p = item->valueint; 398 | } 399 | } 400 | else if (f->type == FIELD_TYPE_BOOL) 401 | { 402 | BOOL *p = (BOOL *)ptr; 403 | if (item->type == cJSON_True) 404 | { 405 | *p = 1; 406 | } 407 | else if (item->type == cJSON_False) 408 | { 409 | *p = 0; 410 | } 411 | } 412 | else if (f->type == FIELD_TYPE_CSTR) 413 | { 414 | CSTR *p = (CSTR *)ptr; 415 | if (item->type == cJSON_String) 416 | { 417 | *p = CS(item->valuestring); 418 | } 419 | } 420 | else if (f->type == FIELD_TYPE_STRUCT) 421 | { 422 | if (item->type == cJSON_Object) 423 | { 424 | metainfo_t *mi = (metainfo_t *)f->metainfo; 425 | void *obj = ptr; 426 | _from_jsonobject(obj, mi, item); 427 | } 428 | } 429 | } 430 | } 431 | } 432 | 433 | C_API void *cobject_from_json(metainfo_t *mi, const char *str) 434 | { 435 | void *obj = cobject_new(mi); 436 | cJSON *json; 437 | if (!mi || !str) 438 | { 439 | return NULL; 440 | } 441 | 442 | json = cJSON_Parse(str); 443 | if (json == NULL) 444 | { 445 | return NULL; 446 | } 447 | 448 | _from_jsonobject(obj, mi, json); 449 | 450 | cJSON_Delete(json); 451 | 452 | return obj; 453 | } 454 | -------------------------------------------------------------------------------- /cobj.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 xphh 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 all 12 | 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 THE 20 | SOFTWARE. 21 | */ 22 | #ifndef _GITHUB_XPHH_COBJ_H_ 23 | #define _GITHUB_XPHH_COBJ_H_ 24 | 25 | #include 26 | 27 | #ifdef __cplusplus 28 | #define C_API extern "C" 29 | #else 30 | #define C_API 31 | #endif 32 | 33 | /************************************************************************/ 34 | /* for boolean type */ 35 | /************************************************************************/ 36 | typedef int BOOL; 37 | 38 | /************************************************************************/ 39 | /* we use CSTR for string type */ 40 | /************************************************************************/ 41 | typedef struct 42 | { 43 | char *cstr; 44 | } const_string_t; 45 | 46 | C_API const_string_t const_string_new(const char *str); 47 | C_API void const_string_clear(const_string_t cs); 48 | 49 | #define CSTR const_string_t 50 | #define CS(str) const_string_new(str) 51 | #define CS_CLEAR(cs) const_string_clear(cs), (cs).cstr = NULL 52 | 53 | /************************************************************************/ 54 | /* free buffer which is easy to use */ 55 | /************************************************************************/ 56 | typedef struct 57 | { 58 | char *ptr; 59 | size_t length; 60 | size_t size; 61 | int count; 62 | } free_buffer_t; 63 | 64 | C_API void free_buffer_init(free_buffer_t *buf); 65 | C_API void free_buffer_append(free_buffer_t *buf, void *data, size_t len); 66 | C_API void free_buffer_append_empty(free_buffer_t *buf, size_t len); 67 | C_API void free_buffer_cleanup(free_buffer_t *buf); 68 | 69 | /************************************************************************/ 70 | /* self-define List type with generic type supported */ 71 | /************************************************************************/ 72 | #define DECLARE_LIST(TYPE) \ 73 | struct { \ 74 | TYPE *array; \ 75 | size_t _buffer_length; \ 76 | size_t _buffer_size; \ 77 | int size; \ 78 | } 79 | 80 | #define LIST_INIT(list) free_buffer_init((free_buffer_t *)&list) 81 | #define LIST_ADD(list, obj) free_buffer_append((free_buffer_t *)&list, &obj, sizeof(obj)) 82 | #define LIST_ADD_EMPTY(list, s) free_buffer_append_empty((free_buffer_t *)&list, sizeof(struct s)) 83 | #define LIST_CLEAR(list) free_buffer_cleanup((free_buffer_t *)&list) 84 | 85 | #define LIST_ADD_INT(list, s) { int i = s; free_buffer_append((free_buffer_t *)&list, &i, sizeof(i)); } 86 | #define LIST_ADD_BOOL(list, s) { BOOL b = s; free_buffer_append((free_buffer_t *)&list, &b, sizeof(b)); } 87 | #define LIST_ADD_STR(list, s) { CSTR cstr = CS(s); free_buffer_append((free_buffer_t *)&list, &cstr, sizeof(cstr)); } 88 | #define LIST_ADD_OBJ(list, s) LIST_ADD(list, s) 89 | 90 | /************************************************************************/ 91 | /* metainfo */ 92 | /************************************************************************/ 93 | enum 94 | { 95 | /* Note that now supported types as below */ 96 | FIELD_TYPE_INT = 0, 97 | FIELD_TYPE_BOOL, 98 | FIELD_TYPE_CSTR, 99 | FIELD_TYPE_STRUCT = 100, 100 | }; 101 | 102 | typedef struct 103 | { 104 | int pos; 105 | int type; 106 | int islist; 107 | const char *name; 108 | void *metainfo; 109 | } field_t; 110 | 111 | typedef struct 112 | { 113 | int obj_size; 114 | DECLARE_LIST(field_t) fs; 115 | } metainfo_t; 116 | 117 | C_API metainfo_t *metainfo_create(int obj_size); 118 | C_API void metainfo_destroy(metainfo_t *mi); 119 | C_API void metainfo_add_member(metainfo_t *mi, int pos, int type, const char *name, int islist); 120 | C_API metainfo_t *metainfo_add_child(metainfo_t *mi, int pos, int obj_size, const char *name, int islist); 121 | 122 | #define METAINFO(s) _metainfo_##s 123 | #define REGISTER_METAINFO(s) _register_metainfo_##s() 124 | #define DEFINE_METAINFO(s) metainfo_t *METAINFO(s); REGISTER_METAINFO(s) 125 | 126 | #define METAINFO_CREATE(s) METAINFO(s) = metainfo_create((int)sizeof(struct s)) 127 | #define METAINFO_DESTROY(s) metainfo_destroy(METAINFO(s)) 128 | 129 | #define METAINFO_ADD_MEMBER(s, t, n) metainfo_add_member(METAINFO(s), offsetof(struct s, n), t, #n, 0) 130 | #define METAINFO_ADD_MEMBER_LIST(s, t, n) metainfo_add_member(METAINFO(s), offsetof(struct s, n), t, #n, 1) 131 | #define METAINFO_ADD_CHILD(s, t, n) metainfo_add_child(METAINFO(s), offsetof(struct s, n), (int)sizeof(struct t), #n, 0) 132 | #define METAINFO_ADD_CHILD_LIST(s, t, n) metainfo_add_child(METAINFO(s), offsetof(struct s, n), (int)sizeof(struct t), #n, 1) 133 | 134 | #define METAINFO_CHILD_BEGIN(s, t, n) { metainfo_t *METAINFO(t) = METAINFO_ADD_CHILD(s, t, n); 135 | #define METAINFO_CHILD_LIST_BEGIN(s, t, n) { metainfo_t *METAINFO(t) = METAINFO_ADD_CHILD_LIST(s, t, n); 136 | #define METAINFO_CHILD_END() } 137 | 138 | /************************************************************************/ 139 | /* C Object <===> Json String */ 140 | /************************************************************************/ 141 | C_API void *cobject_new(metainfo_t *mi); 142 | #define OBJECT_NEW(s) (struct s*)cobject_new(METAINFO(s)) 143 | 144 | C_API void cobject_clear(void *obj, metainfo_t *mi); 145 | #define OBJECT_CLEAR(ptr, s) cobject_clear(ptr, METAINFO(s)) 146 | 147 | C_API void cobject_delete(void *obj, metainfo_t *mi); 148 | #define OBJECT_DELETE(ptr, s) cobject_delete(ptr, METAINFO(s)) 149 | 150 | C_API CSTR cobject_to_json(void *obj, metainfo_t *mi); 151 | #define OBJECT_TO_JSON(ptr, s) cobject_to_json(ptr, METAINFO(s)) 152 | 153 | C_API void *cobject_from_json(metainfo_t *mi, const char *str); 154 | #define OBJECT_FROM_JSON(s, str) cobject_from_json(METAINFO(s), str) 155 | 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014 xphh 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 all 12 | 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 THE 20 | SOFTWARE. 21 | */ 22 | #include "cobj.h" 23 | #include 24 | 25 | /* 26 | * struct defined for test 27 | */ 28 | struct YearRecord 29 | { 30 | int year; 31 | CSTR yearLabel; 32 | DECLARE_LIST(struct MonthRecord 33 | { 34 | int month; 35 | CSTR monthLabel; 36 | DECLARE_LIST(struct DayRecord 37 | { 38 | int day; 39 | CSTR dayLabel; 40 | BOOL mark; 41 | }) dayList; 42 | }) monthList; 43 | }; 44 | 45 | /* 46 | * you need to define metainfo for 'YearRecord' with 'YearRecord' together 47 | */ 48 | DEFINE_METAINFO(YearRecord) 49 | { 50 | METAINFO_CREATE(YearRecord); 51 | 52 | METAINFO_ADD_MEMBER(YearRecord, FIELD_TYPE_INT, year); 53 | METAINFO_ADD_MEMBER(YearRecord, FIELD_TYPE_CSTR, yearLabel); 54 | 55 | METAINFO_CHILD_LIST_BEGIN(YearRecord, MonthRecord, monthList); 56 | 57 | METAINFO_ADD_MEMBER(MonthRecord, FIELD_TYPE_INT, month); 58 | METAINFO_ADD_MEMBER(MonthRecord, FIELD_TYPE_CSTR, monthLabel); 59 | 60 | METAINFO_CHILD_LIST_BEGIN(MonthRecord, DayRecord, dayList); 61 | 62 | METAINFO_ADD_MEMBER(DayRecord, FIELD_TYPE_INT, day); 63 | METAINFO_ADD_MEMBER(DayRecord, FIELD_TYPE_CSTR, dayLabel); 64 | METAINFO_ADD_MEMBER(DayRecord, FIELD_TYPE_BOOL, mark); 65 | 66 | METAINFO_CHILD_END(); 67 | 68 | METAINFO_CHILD_END(); 69 | } 70 | 71 | int main() 72 | { 73 | /* 74 | * remember to register metainfo of 'YearRecord' in your implement code 75 | */ 76 | REGISTER_METAINFO(YearRecord); 77 | 78 | { 79 | CSTR json; 80 | struct YearRecord *rec = OBJECT_NEW(YearRecord); 81 | 82 | rec->year = 2014; 83 | rec->yearLabel = CS("Hangzhou, China"); // CSTR must be initialized with 'CS' macro 84 | 85 | { 86 | // you can add an empty object into list first 87 | LIST_ADD_EMPTY(rec->monthList, MonthRecord); 88 | rec->monthList.array[0].month = 11; 89 | rec->monthList.array[0].monthLabel = CS("Nov."); 90 | 91 | LIST_ADD_EMPTY(rec->monthList.array[0].dayList, DayRecord); 92 | LIST_ADD_EMPTY(rec->monthList.array[0].dayList, DayRecord); 93 | LIST_ADD_EMPTY(rec->monthList.array[0].dayList, DayRecord); 94 | rec->monthList.array[0].dayList.array[2].day = 4; 95 | rec->monthList.array[0].dayList.array[2].dayLabel = CS("Today nothing to do."); 96 | rec->monthList.array[0].dayList.array[2].mark = 1; 97 | } 98 | 99 | { 100 | // also object that is on stack can be add into list 101 | // make sure that the object must zero memory 102 | struct MonthRecord month_rec = {0}; 103 | month_rec.month = 12; 104 | month_rec.monthLabel = CS("next month"); 105 | LIST_ADD_OBJ(rec->monthList, month_rec); 106 | } 107 | 108 | // convert to json string 109 | json = OBJECT_TO_JSON(rec, YearRecord); 110 | printf(json.cstr); 111 | 112 | // clear object but not free 113 | OBJECT_CLEAR(rec, YearRecord); 114 | 115 | // delete 'rec' (free allocated memory), instead of 'free' function 116 | OBJECT_DELETE(rec, YearRecord); 117 | 118 | { 119 | // convert from json string 120 | struct YearRecord *rec2 = OBJECT_FROM_JSON(YearRecord, json.cstr); 121 | 122 | OBJECT_DELETE(rec2, YearRecord); 123 | } 124 | 125 | // the output json string is CSTR type, do not forget to free it! 126 | CS_CLEAR(json); 127 | } 128 | 129 | getchar(); 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /vc8prj/test.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 9.00 3 | # Visual Studio 2005 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{3C16942B-1449-4977-AD37-D492334C64A7}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Win32 = Debug|Win32 9 | Release|Win32 = Release|Win32 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {3C16942B-1449-4977-AD37-D492334C64A7}.Debug|Win32.ActiveCfg = Debug|Win32 13 | {3C16942B-1449-4977-AD37-D492334C64A7}.Debug|Win32.Build.0 = Debug|Win32 14 | {3C16942B-1449-4977-AD37-D492334C64A7}.Release|Win32.ActiveCfg = Release|Win32 15 | {3C16942B-1449-4977-AD37-D492334C64A7}.Release|Win32.Build.0 = Release|Win32 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /vc8prj/test.vcproj: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 25 | 28 | 31 | 34 | 37 | 40 | 54 | 57 | 60 | 63 | 70 | 73 | 76 | 79 | 82 | 85 | 88 | 91 | 94 | 95 | 103 | 106 | 109 | 112 | 115 | 118 | 129 | 132 | 135 | 138 | 147 | 150 | 153 | 156 | 159 | 162 | 165 | 168 | 171 | 172 | 173 | 174 | 175 | 176 | 179 | 182 | 183 | 186 | 187 | 188 | 191 | 194 | 195 | 198 | 199 | 200 | 203 | 204 | 205 | 206 | 207 | 208 | --------------------------------------------------------------------------------