├── LICENSE ├── README.md ├── cJSON ├── .DS_Store ├── LICENSE ├── README ├── cJSON.c ├── cJSON.h ├── test.c └── tests │ ├── test1 │ ├── test2 │ ├── test3 │ ├── test4 │ └── test5 ├── cJSONFiles.zip ├── cJSON_Create ├── bin │ └── Release │ │ └── cJSON_Create.exe ├── cJSON.c ├── cJSON.h ├── cJSON_Create.bmarks ├── cJSON_Create.cbp ├── cJSON_Create.depend ├── cJSON_Create.layout ├── create.c ├── create.h ├── doxygen │ └── doxyfile ├── main.c └── obj │ └── Release │ ├── cJSON.o │ ├── create.o │ └── main.o └── cJSON_Parse ├── a.exe ├── bin └── Release │ └── cJSON_Parse.exe ├── cJSON.c ├── cJSON.h ├── cJSON_Parse.bmarks ├── cJSON_Parse.cbp ├── cJSON_Parse.depend ├── cJSON_Parse.layout ├── json_str.h ├── main.c ├── obj └── Release │ ├── cJSON.o │ ├── main.o │ └── parse.o ├── parse.c ├── parse.h └── weather.json /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cJSON_Demo 2 | 3 | cJSON解析库的使用示例,包含简单和复杂JSON字符串的解析和构建。 4 | 5 | - 我的博客: [![](https://img.shields.io/badge/MyBlog-www.wangchaochao.top-orange.svg)](http://www.wangchaochao.top/) 6 | - 编程语言:![](https://img.shields.io/badge/language-C-brightgreen.svg?style=plastic) 7 | - Github仓库地址:[![](https://img.shields.io/badge/cJSON_Demo-yellow.svg?style=social&logo=github)](https://github.com/whik/cJSON_Demo) 8 | - Gitee仓库地址:[![](https://img.shields.io/badge/Gitee-cJSON_Demo-orange.svg)](https://gitee.com/whik/cJSON_Demo) 9 | 10 | 相关博客文章: 11 | 12 | - [使用cJSON库解析和构建JSON字符串](http://www.wangchaochao.top/2019/07/21/cJSON-Demo/) 13 | - [JSON简介](http://www.wangchaochao.top/2018/11/18/cJSON/) 14 | 15 | #### 关于cJSON库 16 | 17 | cJSON是一个基于C语言的JSON解析库,这个库非常简单,只有`cJSON.c`和`cJSON.h`两个文件,支持JSON的解析和构建,需要调用时,只需要`#include "cJSON.h"`就可以使用了。 18 | 19 | - 库源码下载地址:[cJSON download](https://sourceforge.net/projects/cjson/) 20 | - JSON官方网站:[json](http://www.json.org/json-zh.html) 21 | - 关于JSON:[JSON简介](http://www.wangchaochao.top/2018/11/18/cJSON/) 22 | 23 | 使用示例工程基于CodeBlocks开发环境。 24 | 25 | #### JSON的解析 26 | 27 | JSON的解析示例是在cJSON_Parse文件夹中。 28 | 示例的JSON字符串,包含在json_str.h中: 29 | 30 | - he_now_json:和风天气实况天气数据的JSON数据 31 | - seniverse_now_json:心知天气实况天气数据 32 | - seniverse_forcast_json:心知天气3天预报信息 33 | - AQI_json:空气质量AQI信息 34 | - bj_time_json:北京时间 35 | - oil_price_json:全国城市油价信息 36 | 37 | 解析函数: 38 | 39 | - Parse_BJTime_Json():解析北京时间,键的值是一个JSON对象 40 | - Parse_AQI_Json():解析空气质量AQI,数组嵌套对象 41 | - Parse_HeWeather_Now_Json():解析和风天气实时数据,一个数组嵌套多个对象 42 | - Parse_Seniverse_Now_Json():解析心知天气实时数据,一个数组嵌套多个对象 43 | - Parse_Seniverse_Forecast_Json():解析心知预报天气,数组内嵌套一个数组和多个对象 44 | - Parse_Oil_Price_Json():解析油价信息,一个数组内嵌套5个数组,每个数组包含5个字符串元素 45 | - void Parse_File_Json(void); 解析心知天气预报数据,JSON数据存放在一个文件中 46 | - char* textFileRead(char* filename); 读取文件内容 47 | - int get_file_line_number(char *filename); 获取文件总行数 48 | 49 | 50 | #### JSON的构建 51 | 52 | JSON的构建包含在cJSON_Create文件夹中。 53 | 54 | 构建函数: 55 | 56 | - Create_Simple_JSON():构建一个简单的json键值对 57 | 58 | ```json 59 | { 60 | "CSDN": "https://blog.csdn.net/whik1194", 61 | "cnblogs": "https://home.cnblogs.com/u/whik/", 62 | "Github": "https://github.com/whik/", 63 | "Blog": "http://www.wangchaochao.top/" 64 | } 65 | ``` 66 | 67 | 68 | - Create_BJTime_JSON():键的值是一个JSON对象 69 | 70 | ```json 71 | { 72 | "status": "success", 73 | "result": { 74 | "timestamp": "ok", 75 | "datetime_1": "2019-07-21 10:46:57", 76 | "datetime_2": "2019年07月21日 10时46分57秒", 77 | "week_1": "0", 78 | "week_2": "星期日", 79 | "week_3": "周日", 80 | "week_4": "Sunday" 81 | }, 82 | "Blog": "www.wangchaochao.top" 83 | } 84 | ``` 85 | 86 | 87 | - Create_Array_Str_JSON():JSON数组,元素是字符串 88 | 89 | ```json 90 | ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] 91 | ``` 92 | 93 | 94 | - Create_Array_JSON():键的值是一个数组,数组包含多个对象元素 95 | 96 | ```json 97 | { 98 | "status": "ok", 99 | "weather": [{ 100 | "date": "2019-07-21", 101 | "cond_txt": "多云", 102 | "cond_code": "101", 103 | "hum": "23", 104 | "tmp_H": "31", 105 | "tmp_L": "25" 106 | }, { 107 | "date": "2019-07-22", 108 | "cond_txt": "晴", 109 | "cond_code": "100", 110 | "hum": "20", 111 | "tmp_H": "33", 112 | "tmp_L": "26" 113 | }, { 114 | "date": "2019-07-23", 115 | "cond_txt": "阵雨", 116 | "cond_code": "107", 117 | "hum": "45", 118 | "tmp_H": "32", 119 | "tmp_L": "25" 120 | }], 121 | "update": "2019-07-21 11:00", 122 | "Blog": "www.wangchaochao.top" 123 | } 124 | ``` 125 | 126 | 127 | - Create_Array_Nest_JSON():数组内嵌套了5个数组,每个数组内有5个字符串元素 128 | 129 | ```json 130 | { 131 | "status": "ok", 132 | "msg": "全国各省份汽柴油价格信息", 133 | "update": "2019-07-21", 134 | "data": [ 135 | ["地区", "92号汽油", "95号汽油", "98号汽油", "0号柴油"], 136 | ["北京", "6.78", "7.21", "8.19", "6.45"], 137 | ["上海", "6.74", "7.17", "7.87", "6.39"], 138 | ["江苏", "6.75", "7.18", "8.06", "6.37"], 139 | ["天津", "6.77", "7.15", "8.07", "6.41"] 140 | ], 141 | "About": "wcc", 142 | "Blog": "www.wangchaochao.top" 143 | } 144 | ``` -------------------------------------------------------------------------------- /cJSON/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON/.DS_Store -------------------------------------------------------------------------------- /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 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "cJSON.h" 34 | 35 | static const char *ep; 36 | 37 | const char *cJSON_GetErrorPtr(void) {return ep;} 38 | 39 | static int cJSON_strcasecmp(const char *s1,const char *s2) 40 | { 41 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; 42 | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; 43 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 44 | } 45 | 46 | static void *(*cJSON_malloc)(size_t sz) = malloc; 47 | static void (*cJSON_free)(void *ptr) = free; 48 | 49 | static char* cJSON_strdup(const char* str) 50 | { 51 | size_t len; 52 | char* copy; 53 | 54 | len = strlen(str) + 1; 55 | if (!(copy = (char*)cJSON_malloc(len))) return 0; 56 | memcpy(copy,str,len); 57 | return copy; 58 | } 59 | 60 | void cJSON_InitHooks(cJSON_Hooks* hooks) 61 | { 62 | if (!hooks) { /* Reset hooks */ 63 | cJSON_malloc = malloc; 64 | cJSON_free = free; 65 | return; 66 | } 67 | 68 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 69 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 70 | } 71 | 72 | /* Internal constructor. */ 73 | static cJSON *cJSON_New_Item(void) 74 | { 75 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 76 | if (node) memset(node,0,sizeof(cJSON)); 77 | return node; 78 | } 79 | 80 | /* Delete a cJSON structure. */ 81 | void cJSON_Delete(cJSON *c) 82 | { 83 | cJSON *next; 84 | while (c) 85 | { 86 | next=c->next; 87 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 88 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 89 | if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); 90 | cJSON_free(c); 91 | c=next; 92 | } 93 | } 94 | 95 | /* Parse the input text to generate a number, and populate the result into item. */ 96 | static const char *parse_number(cJSON *item,const char *num) 97 | { 98 | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; 99 | 100 | if (*num=='-') sign=-1,num++; /* Has sign? */ 101 | if (*num=='0') num++; /* is zero */ 102 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 103 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ 104 | if (*num=='e' || *num=='E') /* Exponent? */ 105 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ 106 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ 107 | } 108 | 109 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 110 | 111 | item->valuedouble=n; 112 | item->valueint=(int)n; 113 | item->type=cJSON_Number; 114 | return num; 115 | } 116 | 117 | static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } 118 | 119 | typedef struct {char *buffer; int length; int offset; } printbuffer; 120 | 121 | static char* ensure(printbuffer *p,int needed) 122 | { 123 | char *newbuffer;int newsize; 124 | if (!p || !p->buffer) return 0; 125 | needed+=p->offset; 126 | if (needed<=p->length) return p->buffer+p->offset; 127 | 128 | newsize=pow2gt(needed); 129 | newbuffer=(char*)cJSON_malloc(newsize); 130 | if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} 131 | if (newbuffer) memcpy(newbuffer,p->buffer,p->length); 132 | cJSON_free(p->buffer); 133 | p->length=newsize; 134 | p->buffer=newbuffer; 135 | return newbuffer+p->offset; 136 | } 137 | 138 | static int update(printbuffer *p) 139 | { 140 | char *str; 141 | if (!p || !p->buffer) return 0; 142 | str=p->buffer+p->offset; 143 | return p->offset+strlen(str); 144 | } 145 | 146 | /* Render the number nicely from the given item into a string. */ 147 | static char *print_number(cJSON *item,printbuffer *p) 148 | { 149 | char *str=0; 150 | double d=item->valuedouble; 151 | if (d==0) 152 | { 153 | if (p) str=ensure(p,2); 154 | else str=(char*)cJSON_malloc(2); /* special case for 0. */ 155 | if (str) strcpy(str,"0"); 156 | } 157 | else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) 158 | { 159 | if (p) str=ensure(p,21); 160 | else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 161 | if (str) sprintf(str,"%d",item->valueint); 162 | } 163 | else 164 | { 165 | if (p) str=ensure(p,64); 166 | else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 167 | if (str) 168 | { 169 | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); 170 | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); 171 | else sprintf(str,"%f",d); 172 | } 173 | } 174 | return str; 175 | } 176 | 177 | static unsigned parse_hex4(const char *str) 178 | { 179 | unsigned h=0; 180 | 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; 181 | h=h<<4;str++; 182 | 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; 183 | h=h<<4;str++; 184 | 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; 185 | h=h<<4;str++; 186 | 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; 187 | return h; 188 | } 189 | 190 | /* Parse the input text into an unescaped cstring, and populate item. */ 191 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 192 | static const char *parse_string(cJSON *item,const char *str) 193 | { 194 | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; 195 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ 196 | 197 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ 198 | 199 | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 200 | if (!out) return 0; 201 | 202 | ptr=str+1;ptr2=out; 203 | while (*ptr!='\"' && *ptr) 204 | { 205 | if (*ptr!='\\') *ptr2++=*ptr++; 206 | else 207 | { 208 | ptr++; 209 | switch (*ptr) 210 | { 211 | case 'b': *ptr2++='\b'; break; 212 | case 'f': *ptr2++='\f'; break; 213 | case 'n': *ptr2++='\n'; break; 214 | case 'r': *ptr2++='\r'; break; 215 | case 't': *ptr2++='\t'; break; 216 | case 'u': /* transcode utf16 to utf8. */ 217 | uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ 218 | 219 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ 220 | 221 | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 222 | { 223 | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ 224 | uc2=parse_hex4(ptr+3);ptr+=6; 225 | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ 226 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 227 | } 228 | 229 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 230 | 231 | switch (len) { 232 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 233 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 234 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 235 | case 1: *--ptr2 =(uc | firstByteMark[len]); 236 | } 237 | ptr2+=len; 238 | break; 239 | default: *ptr2++=*ptr; break; 240 | } 241 | ptr++; 242 | } 243 | } 244 | *ptr2=0; 245 | if (*ptr=='\"') ptr++; 246 | item->valuestring=out; 247 | item->type=cJSON_String; 248 | return ptr; 249 | } 250 | 251 | /* Render the cstring provided to an escaped version that can be printed. */ 252 | static char *print_string_ptr(const char *str,printbuffer *p) 253 | { 254 | const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; 255 | 256 | for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; 257 | if (!flag) 258 | { 259 | len=ptr-str; 260 | if (p) out=ensure(p,len+3); 261 | else out=(char*)cJSON_malloc(len+3); 262 | if (!out) return 0; 263 | ptr2=out;*ptr2++='\"'; 264 | strcpy(ptr2,str); 265 | ptr2[len]='\"'; 266 | ptr2[len+1]=0; 267 | return out; 268 | } 269 | 270 | if (!str) 271 | { 272 | if (p) out=ensure(p,3); 273 | else out=(char*)cJSON_malloc(3); 274 | if (!out) return 0; 275 | strcpy(out,"\"\""); 276 | return out; 277 | } 278 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 279 | 280 | if (p) out=ensure(p,len+3); 281 | else out=(char*)cJSON_malloc(len+3); 282 | if (!out) return 0; 283 | 284 | ptr2=out;ptr=str; 285 | *ptr2++='\"'; 286 | while (*ptr) 287 | { 288 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 289 | else 290 | { 291 | *ptr2++='\\'; 292 | switch (token=*ptr++) 293 | { 294 | case '\\': *ptr2++='\\'; break; 295 | case '\"': *ptr2++='\"'; break; 296 | case '\b': *ptr2++='b'; break; 297 | case '\f': *ptr2++='f'; break; 298 | case '\n': *ptr2++='n'; break; 299 | case '\r': *ptr2++='r'; break; 300 | case '\t': *ptr2++='t'; break; 301 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 302 | } 303 | } 304 | } 305 | *ptr2++='\"';*ptr2++=0; 306 | return out; 307 | } 308 | /* Invote print_string_ptr (which is useful) on an item. */ 309 | static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} 310 | 311 | /* Predeclare these prototypes. */ 312 | static const char *parse_value(cJSON *item,const char *value); 313 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); 314 | static const char *parse_array(cJSON *item,const char *value); 315 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); 316 | static const char *parse_object(cJSON *item,const char *value); 317 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); 318 | 319 | /* Utility to jump whitespace and cr/lf */ 320 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 321 | 322 | /* Parse an object - create a new root, and populate. */ 323 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 324 | { 325 | const char *end=0; 326 | cJSON *c=cJSON_New_Item(); 327 | ep=0; 328 | if (!c) return 0; /* memory fail */ 329 | 330 | end=parse_value(c,skip(value)); 331 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 332 | 333 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 334 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} 335 | if (return_parse_end) *return_parse_end=end; 336 | return c; 337 | } 338 | /* Default options for cJSON_Parse */ 339 | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 340 | 341 | /* Render a cJSON item/entity/structure to text. */ 342 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} 343 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} 344 | 345 | char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) 346 | { 347 | printbuffer p; 348 | p.buffer=(char*)cJSON_malloc(prebuffer); 349 | p.length=prebuffer; 350 | p.offset=0; 351 | return print_value(item,0,fmt,&p); 352 | return p.buffer; 353 | } 354 | 355 | 356 | /* Parser core - when encountering text, process appropriately. */ 357 | static const char *parse_value(cJSON *item,const char *value) 358 | { 359 | if (!value) return 0; /* Fail on null. */ 360 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 361 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 362 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 363 | if (*value=='\"') { return parse_string(item,value); } 364 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 365 | if (*value=='[') { return parse_array(item,value); } 366 | if (*value=='{') { return parse_object(item,value); } 367 | 368 | ep=value;return 0; /* failure. */ 369 | } 370 | 371 | /* Render a value to text. */ 372 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) 373 | { 374 | char *out=0; 375 | if (!item) return 0; 376 | if (p) 377 | { 378 | switch ((item->type)&255) 379 | { 380 | case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} 381 | case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} 382 | case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} 383 | case cJSON_Number: out=print_number(item,p);break; 384 | case cJSON_String: out=print_string(item,p);break; 385 | case cJSON_Array: out=print_array(item,depth,fmt,p);break; 386 | case cJSON_Object: out=print_object(item,depth,fmt,p);break; 387 | } 388 | } 389 | else 390 | { 391 | switch ((item->type)&255) 392 | { 393 | case cJSON_NULL: out=cJSON_strdup("null"); break; 394 | case cJSON_False: out=cJSON_strdup("false");break; 395 | case cJSON_True: out=cJSON_strdup("true"); break; 396 | case cJSON_Number: out=print_number(item,0);break; 397 | case cJSON_String: out=print_string(item,0);break; 398 | case cJSON_Array: out=print_array(item,depth,fmt,0);break; 399 | case cJSON_Object: out=print_object(item,depth,fmt,0);break; 400 | } 401 | } 402 | return out; 403 | } 404 | 405 | /* Build an array from input text. */ 406 | static const char *parse_array(cJSON *item,const char *value) 407 | { 408 | cJSON *child; 409 | if (*value!='[') {ep=value;return 0;} /* not an array! */ 410 | 411 | item->type=cJSON_Array; 412 | value=skip(value+1); 413 | if (*value==']') return value+1; /* empty array. */ 414 | 415 | item->child=child=cJSON_New_Item(); 416 | if (!item->child) return 0; /* memory fail */ 417 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ 418 | if (!value) return 0; 419 | 420 | while (*value==',') 421 | { 422 | cJSON *new_item; 423 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 424 | child->next=new_item;new_item->prev=child;child=new_item; 425 | value=skip(parse_value(child,skip(value+1))); 426 | if (!value) return 0; /* memory fail */ 427 | } 428 | 429 | if (*value==']') return value+1; /* end of array */ 430 | ep=value;return 0; /* malformed. */ 431 | } 432 | 433 | /* Render an array to text */ 434 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) 435 | { 436 | char **entries; 437 | char *out=0,*ptr,*ret;int len=5; 438 | cJSON *child=item->child; 439 | int numentries=0,i=0,fail=0; 440 | size_t tmplen=0; 441 | 442 | /* How many entries in the array? */ 443 | while (child) numentries++,child=child->next; 444 | /* Explicitly handle numentries==0 */ 445 | if (!numentries) 446 | { 447 | if (p) out=ensure(p,3); 448 | else out=(char*)cJSON_malloc(3); 449 | if (out) strcpy(out,"[]"); 450 | return out; 451 | } 452 | 453 | if (p) 454 | { 455 | /* Compose the output array. */ 456 | i=p->offset; 457 | ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; 458 | child=item->child; 459 | while (child && !fail) 460 | { 461 | print_value(child,depth+1,fmt,p); 462 | p->offset=update(p); 463 | if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} 464 | child=child->next; 465 | } 466 | ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; 467 | out=(p->buffer)+i; 468 | } 469 | else 470 | { 471 | /* Allocate an array to hold the values for each */ 472 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 473 | if (!entries) return 0; 474 | memset(entries,0,numentries*sizeof(char*)); 475 | /* Retrieve all the results: */ 476 | child=item->child; 477 | while (child && !fail) 478 | { 479 | ret=print_value(child,depth+1,fmt,0); 480 | entries[i++]=ret; 481 | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 482 | child=child->next; 483 | } 484 | 485 | /* If we didn't fail, try to malloc the output string */ 486 | if (!fail) out=(char*)cJSON_malloc(len); 487 | /* If that fails, we fail. */ 488 | if (!out) fail=1; 489 | 490 | /* Handle failure. */ 491 | if (fail) 492 | { 493 | for (i=0;itype=cJSON_Object; 520 | value=skip(value+1); 521 | if (*value=='}') return value+1; /* empty array. */ 522 | 523 | item->child=child=cJSON_New_Item(); 524 | if (!item->child) return 0; 525 | value=skip(parse_string(child,skip(value))); 526 | if (!value) return 0; 527 | child->string=child->valuestring;child->valuestring=0; 528 | if (*value!=':') {ep=value;return 0;} /* fail! */ 529 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 530 | if (!value) return 0; 531 | 532 | while (*value==',') 533 | { 534 | cJSON *new_item; 535 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 536 | child->next=new_item;new_item->prev=child;child=new_item; 537 | value=skip(parse_string(child,skip(value+1))); 538 | if (!value) return 0; 539 | child->string=child->valuestring;child->valuestring=0; 540 | if (*value!=':') {ep=value;return 0;} /* fail! */ 541 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 542 | if (!value) return 0; 543 | } 544 | 545 | if (*value=='}') return value+1; /* end of array */ 546 | ep=value;return 0; /* malformed. */ 547 | } 548 | 549 | /* Render an object to text. */ 550 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) 551 | { 552 | char **entries=0,**names=0; 553 | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 554 | cJSON *child=item->child; 555 | int numentries=0,fail=0; 556 | size_t tmplen=0; 557 | /* Count the number of entries. */ 558 | while (child) numentries++,child=child->next; 559 | /* Explicitly handle empty object case */ 560 | if (!numentries) 561 | { 562 | if (p) out=ensure(p,fmt?depth+4:3); 563 | else out=(char*)cJSON_malloc(fmt?depth+4:3); 564 | if (!out) return 0; 565 | ptr=out;*ptr++='{'; 566 | if (fmt) {*ptr++='\n';for (i=0;ioffset; 574 | len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; 575 | *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; 576 | child=item->child;depth++; 577 | while (child) 578 | { 579 | if (fmt) 580 | { 581 | ptr=ensure(p,depth); if (!ptr) return 0; 582 | for (j=0;joffset+=depth; 584 | } 585 | print_string_ptr(child->string,p); 586 | p->offset=update(p); 587 | 588 | len=fmt?2:1; 589 | ptr=ensure(p,len); if (!ptr) return 0; 590 | *ptr++=':';if (fmt) *ptr++='\t'; 591 | p->offset+=len; 592 | 593 | print_value(child,depth,fmt,p); 594 | p->offset=update(p); 595 | 596 | len=(fmt?1:0)+(child->next?1:0); 597 | ptr=ensure(p,len+1); if (!ptr) return 0; 598 | if (child->next) *ptr++=','; 599 | if (fmt) *ptr++='\n';*ptr=0; 600 | p->offset+=len; 601 | child=child->next; 602 | } 603 | ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; 604 | if (fmt) for (i=0;ibuffer)+i; 607 | } 608 | else 609 | { 610 | /* Allocate space for the names and the objects */ 611 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 612 | if (!entries) return 0; 613 | names=(char**)cJSON_malloc(numentries*sizeof(char*)); 614 | if (!names) {cJSON_free(entries);return 0;} 615 | memset(entries,0,sizeof(char*)*numentries); 616 | memset(names,0,sizeof(char*)*numentries); 617 | 618 | /* Collect all the results into our arrays: */ 619 | child=item->child;depth++;if (fmt) len+=depth; 620 | while (child) 621 | { 622 | names[i]=str=print_string_ptr(child->string,0); 623 | entries[i++]=ret=print_value(child,depth,fmt,0); 624 | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; 625 | child=child->next; 626 | } 627 | 628 | /* Try to allocate the output string */ 629 | if (!fail) out=(char*)cJSON_malloc(len); 630 | if (!out) fail=1; 631 | 632 | /* Handle failure */ 633 | if (fail) 634 | { 635 | for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} 662 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} 663 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} 664 | 665 | /* Utility for array list handling. */ 666 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 667 | /* Utility for handling references. */ 668 | 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;} 669 | 670 | /* Add item to array/object. */ 671 | 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);}} 672 | 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);} 673 | void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} 674 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 675 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 676 | 677 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 678 | 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;} 679 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 680 | 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;} 681 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 682 | 683 | /* Replace array/object items with new ones. */ 684 | void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} 685 | newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} 686 | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 687 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 688 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 689 | 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);}} 690 | 691 | /* Create basic types: */ 692 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 693 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 694 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 695 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 696 | 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;} 697 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} 698 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 699 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 700 | 701 | /* Create Arrays: */ 702 | 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;} 703 | 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;} 704 | 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;} 705 | 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;} 706 | 707 | /* Duplication */ 708 | cJSON *cJSON_Duplicate(cJSON *item,int recurse) 709 | { 710 | cJSON *newitem,*cptr,*nptr=0,*newchild; 711 | /* Bail on bad ptr */ 712 | if (!item) return 0; 713 | /* Create new item */ 714 | newitem=cJSON_New_Item(); 715 | if (!newitem) return 0; 716 | /* Copy over all vars */ 717 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 718 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 719 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 720 | /* If non-recursive, then we're done! */ 721 | if (!recurse) return newitem; 722 | /* Walk the ->next chain for the child. */ 723 | cptr=item->child; 724 | while (cptr) 725 | { 726 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 727 | if (!newchild) {cJSON_Delete(newitem);return 0;} 728 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 729 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 730 | cptr=cptr->next; 731 | } 732 | return newitem; 733 | } 734 | 735 | void cJSON_Minify(char *json) 736 | { 737 | char *into=json; 738 | while (*json) 739 | { 740 | if (*json==' ') json++; 741 | else if (*json=='\t') json++; /* Whitespace characters. */ 742 | else if (*json=='\r') json++; 743 | else if (*json=='\n') json++; 744 | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ 745 | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ 746 | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ 747 | else *into++=*json++; /* All other characters. */ 748 | } 749 | *into=0; /* and null-terminate. */ 750 | } 751 | -------------------------------------------------------------------------------- /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 | #define cJSON_StringIsConst 512 42 | 43 | /* The cJSON structure: */ 44 | typedef struct cJSON { 45 | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 46 | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 47 | 48 | int type; /* The type of the item, as above. */ 49 | 50 | char *valuestring; /* The item's string, if type==cJSON_String */ 51 | int valueint; /* The item's number, if type==cJSON_Number */ 52 | double valuedouble; /* The item's number, if type==cJSON_Number */ 53 | 54 | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 55 | } cJSON; 56 | 57 | typedef struct cJSON_Hooks { 58 | void *(*malloc_fn)(size_t sz); 59 | void (*free_fn)(void *ptr); 60 | } cJSON_Hooks; 61 | 62 | /* Supply malloc, realloc and free functions to cJSON */ 63 | extern void cJSON_InitHooks(cJSON_Hooks* hooks); 64 | 65 | 66 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 67 | extern cJSON *cJSON_Parse(const char *value); 68 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 69 | extern char *cJSON_Print(cJSON *item); 70 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 71 | extern char *cJSON_PrintUnformatted(cJSON *item); 72 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 73 | extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); 74 | /* Delete a cJSON entity and all subentities. */ 75 | extern void cJSON_Delete(cJSON *c); 76 | 77 | /* Returns the number of items in an array (or object). */ 78 | extern int cJSON_GetArraySize(cJSON *array); 79 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 80 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); 81 | /* Get item "string" from object. Case insensitive. */ 82 | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); 83 | 84 | /* 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. */ 85 | extern const char *cJSON_GetErrorPtr(void); 86 | 87 | /* These calls create a cJSON item of the appropriate type. */ 88 | extern cJSON *cJSON_CreateNull(void); 89 | extern cJSON *cJSON_CreateTrue(void); 90 | extern cJSON *cJSON_CreateFalse(void); 91 | extern cJSON *cJSON_CreateBool(int b); 92 | extern cJSON *cJSON_CreateNumber(double num); 93 | extern cJSON *cJSON_CreateString(const char *string); 94 | extern cJSON *cJSON_CreateArray(void); 95 | extern cJSON *cJSON_CreateObject(void); 96 | 97 | /* These utilities create an Array of count items. */ 98 | extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); 99 | extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); 100 | extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); 101 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); 102 | 103 | /* Append item to the specified array/object. */ 104 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 105 | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); 106 | extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ 107 | /* 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. */ 108 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 109 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); 110 | 111 | /* Remove/Detatch items from Arrays/Objects. */ 112 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); 113 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); 114 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); 115 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); 116 | 117 | /* Update array items. */ 118 | extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ 119 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); 120 | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 121 | 122 | /* Duplicate a cJSON item */ 123 | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); 124 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 125 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 126 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 127 | 128 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 129 | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); 130 | 131 | extern void cJSON_Minify(char *json); 132 | 133 | /* Macros for creating things quickly. */ 134 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 135 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 136 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 137 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 138 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 139 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 140 | 141 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 142 | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 143 | #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /cJSON/test.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 | 23 | #include 24 | #include 25 | #include "cJSON.h" 26 | 27 | /* Parse text to JSON, then render back to text, and print! */ 28 | void doit(char *text) 29 | { 30 | char *out;cJSON *json; 31 | 32 | json=cJSON_Parse(text); 33 | if (!json) {printf("Error before: [%s]\n",cJSON_GetErrorPtr());} 34 | else 35 | { 36 | out=cJSON_Print(json); 37 | cJSON_Delete(json); 38 | printf("%s\n",out); 39 | free(out); 40 | } 41 | } 42 | 43 | /* Read a file, parse, render back, etc. */ 44 | void dofile(char *filename) 45 | { 46 | FILE *f;long len;char *data; 47 | 48 | f=fopen(filename,"rb");fseek(f,0,SEEK_END);len=ftell(f);fseek(f,0,SEEK_SET); 49 | data=(char*)malloc(len+1);fread(data,1,len,f);fclose(f); 50 | doit(data); 51 | free(data); 52 | } 53 | 54 | /* Used by some code below as an example datatype. */ 55 | struct record {const char *precision;double lat,lon;const char *address,*city,*state,*zip,*country; }; 56 | 57 | /* Create a bunch of objects as demonstration. */ 58 | void create_objects() 59 | { 60 | cJSON *root,*fmt,*img,*thm,*fld;char *out;int i; /* declare a few. */ 61 | /* Our "days of the week" array: */ 62 | const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}; 63 | /* Our matrix: */ 64 | int numbers[3][3]={{0,-1,0},{1,0,0},{0,0,1}}; 65 | /* Our "gallery" item: */ 66 | int ids[4]={116,943,234,38793}; 67 | /* Our array of "records": */ 68 | struct record fields[2]={ 69 | {"zip",37.7668,-1.223959e+2,"","SAN FRANCISCO","CA","94107","US"}, 70 | {"zip",37.371991,-1.22026e+2,"","SUNNYVALE","CA","94085","US"}}; 71 | 72 | /* Here we construct some JSON standards, from the JSON site. */ 73 | 74 | /* Our "Video" datatype: */ 75 | root=cJSON_CreateObject(); 76 | cJSON_AddItemToObject(root, "name", cJSON_CreateString("Jack (\"Bee\") Nimble")); 77 | cJSON_AddItemToObject(root, "format", fmt=cJSON_CreateObject()); 78 | cJSON_AddStringToObject(fmt,"type", "rect"); 79 | cJSON_AddNumberToObject(fmt,"width", 1920); 80 | cJSON_AddNumberToObject(fmt,"height", 1080); 81 | cJSON_AddFalseToObject (fmt,"interlace"); 82 | cJSON_AddNumberToObject(fmt,"frame rate", 24); 83 | 84 | out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); /* Print to text, Delete the cJSON, print it, release the string. */ 85 | 86 | /* Our "days of the week" array: */ 87 | root=cJSON_CreateStringArray(strings,7); 88 | 89 | out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); 90 | 91 | /* Our matrix: */ 92 | root=cJSON_CreateArray(); 93 | for (i=0;i<3;i++) cJSON_AddItemToArray(root,cJSON_CreateIntArray(numbers[i],3)); 94 | 95 | /* cJSON_ReplaceItemInArray(root,1,cJSON_CreateString("Replacement")); */ 96 | 97 | out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); 98 | 99 | 100 | /* Our "gallery" item: */ 101 | root=cJSON_CreateObject(); 102 | cJSON_AddItemToObject(root, "Image", img=cJSON_CreateObject()); 103 | cJSON_AddNumberToObject(img,"Width",800); 104 | cJSON_AddNumberToObject(img,"Height",600); 105 | cJSON_AddStringToObject(img,"Title","View from 15th Floor"); 106 | cJSON_AddItemToObject(img, "Thumbnail", thm=cJSON_CreateObject()); 107 | cJSON_AddStringToObject(thm, "Url", "http:/*www.example.com/image/481989943"); 108 | cJSON_AddNumberToObject(thm,"Height",125); 109 | cJSON_AddStringToObject(thm,"Width","100"); 110 | cJSON_AddItemToObject(img,"IDs", cJSON_CreateIntArray(ids,4)); 111 | 112 | out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); 113 | 114 | /* Our array of "records": */ 115 | 116 | root=cJSON_CreateArray(); 117 | for (i=0;i<2;i++) 118 | { 119 | cJSON_AddItemToArray(root,fld=cJSON_CreateObject()); 120 | cJSON_AddStringToObject(fld, "precision", fields[i].precision); 121 | cJSON_AddNumberToObject(fld, "Latitude", fields[i].lat); 122 | cJSON_AddNumberToObject(fld, "Longitude", fields[i].lon); 123 | cJSON_AddStringToObject(fld, "Address", fields[i].address); 124 | cJSON_AddStringToObject(fld, "City", fields[i].city); 125 | cJSON_AddStringToObject(fld, "State", fields[i].state); 126 | cJSON_AddStringToObject(fld, "Zip", fields[i].zip); 127 | cJSON_AddStringToObject(fld, "Country", fields[i].country); 128 | } 129 | 130 | /* cJSON_ReplaceItemInObject(cJSON_GetArrayItem(root,1),"City",cJSON_CreateIntArray(ids,4)); */ 131 | 132 | out=cJSON_Print(root); cJSON_Delete(root); printf("%s\n",out); free(out); 133 | 134 | } 135 | 136 | int main (int argc, const char * argv[]) { 137 | /* a bunch of json: */ 138 | char text1[]="{\n\"name\": \"Jack (\\\"Bee\\\") Nimble\", \n\"format\": {\"type\": \"rect\", \n\"width\": 1920, \n\"height\": 1080, \n\"interlace\": false,\"frame rate\": 24\n}\n}"; 139 | char text2[]="[\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"]"; 140 | char text3[]="[\n [0, -1, 0],\n [1, 0, 0],\n [0, 0, 1]\n ]\n"; 141 | 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 }"; 142 | 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 ]"; 143 | 144 | /* Process each json textblock by parsing, then rebuilding: */ 145 | doit(text1); 146 | doit(text2); 147 | doit(text3); 148 | doit(text4); 149 | doit(text5); 150 | 151 | /* Parse standard testfiles: */ 152 | /* dofile("../../tests/test1"); */ 153 | /* dofile("../../tests/test2"); */ 154 | /* dofile("../../tests/test3"); */ 155 | /* dofile("../../tests/test4"); */ 156 | /* dofile("../../tests/test5"); */ 157 | 158 | /* Now some samplecode for building objects concisely: */ 159 | create_objects(); 160 | 161 | return 0; 162 | } 163 | -------------------------------------------------------------------------------- /cJSON/tests/test1: -------------------------------------------------------------------------------- 1 | { 2 | "glossary": { 3 | "title": "example glossary", 4 | "GlossDiv": { 5 | "title": "S", 6 | "GlossList": { 7 | "GlossEntry": { 8 | "ID": "SGML", 9 | "SortAs": "SGML", 10 | "GlossTerm": "Standard Generalized Markup Language", 11 | "Acronym": "SGML", 12 | "Abbrev": "ISO 8879:1986", 13 | "GlossDef": { 14 | "para": "A meta-markup language, used to create markup languages such as DocBook.", 15 | "GlossSeeAlso": ["GML", "XML"] 16 | }, 17 | "GlossSee": "markup" 18 | } 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /cJSON/tests/test2: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "id": "file", 3 | "value": "File", 4 | "popup": { 5 | "menuitem": [ 6 | {"value": "New", "onclick": "CreateNewDoc()"}, 7 | {"value": "Open", "onclick": "OpenDoc()"}, 8 | {"value": "Close", "onclick": "CloseDoc()"} 9 | ] 10 | } 11 | }} 12 | -------------------------------------------------------------------------------- /cJSON/tests/test3: -------------------------------------------------------------------------------- 1 | {"widget": { 2 | "debug": "on", 3 | "window": { 4 | "title": "Sample Konfabulator Widget", 5 | "name": "main_window", 6 | "width": 500, 7 | "height": 500 8 | }, 9 | "image": { 10 | "src": "Images/Sun.png", 11 | "name": "sun1", 12 | "hOffset": 250, 13 | "vOffset": 250, 14 | "alignment": "center" 15 | }, 16 | "text": { 17 | "data": "Click Here", 18 | "size": 36, 19 | "style": "bold", 20 | "name": "text1", 21 | "hOffset": 250, 22 | "vOffset": 100, 23 | "alignment": "center", 24 | "onMouseUp": "sun1.opacity = (sun1.opacity / 100) * 90;" 25 | } 26 | }} -------------------------------------------------------------------------------- /cJSON/tests/test4: -------------------------------------------------------------------------------- 1 | {"web-app": { 2 | "servlet": [ 3 | { 4 | "servlet-name": "cofaxCDS", 5 | "servlet-class": "org.cofax.cds.CDSServlet", 6 | "init-param": { 7 | "configGlossary:installationAt": "Philadelphia, PA", 8 | "configGlossary:adminEmail": "ksm@pobox.com", 9 | "configGlossary:poweredBy": "Cofax", 10 | "configGlossary:poweredByIcon": "/images/cofax.gif", 11 | "configGlossary:staticPath": "/content/static", 12 | "templateProcessorClass": "org.cofax.WysiwygTemplate", 13 | "templateLoaderClass": "org.cofax.FilesTemplateLoader", 14 | "templatePath": "templates", 15 | "templateOverridePath": "", 16 | "defaultListTemplate": "listTemplate.htm", 17 | "defaultFileTemplate": "articleTemplate.htm", 18 | "useJSP": false, 19 | "jspListTemplate": "listTemplate.jsp", 20 | "jspFileTemplate": "articleTemplate.jsp", 21 | "cachePackageTagsTrack": 200, 22 | "cachePackageTagsStore": 200, 23 | "cachePackageTagsRefresh": 60, 24 | "cacheTemplatesTrack": 100, 25 | "cacheTemplatesStore": 50, 26 | "cacheTemplatesRefresh": 15, 27 | "cachePagesTrack": 200, 28 | "cachePagesStore": 100, 29 | "cachePagesRefresh": 10, 30 | "cachePagesDirtyRead": 10, 31 | "searchEngineListTemplate": "forSearchEnginesList.htm", 32 | "searchEngineFileTemplate": "forSearchEngines.htm", 33 | "searchEngineRobotsDb": "WEB-INF/robots.db", 34 | "useDataStore": true, 35 | "dataStoreClass": "org.cofax.SqlDataStore", 36 | "redirectionClass": "org.cofax.SqlRedirection", 37 | "dataStoreName": "cofax", 38 | "dataStoreDriver": "com.microsoft.jdbc.sqlserver.SQLServerDriver", 39 | "dataStoreUrl": "jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon", 40 | "dataStoreUser": "sa", 41 | "dataStorePassword": "dataStoreTestQuery", 42 | "dataStoreTestQuery": "SET NOCOUNT ON;select test='test';", 43 | "dataStoreLogFile": "/usr/local/tomcat/logs/datastore.log", 44 | "dataStoreInitConns": 10, 45 | "dataStoreMaxConns": 100, 46 | "dataStoreConnUsageLimit": 100, 47 | "dataStoreLogLevel": "debug", 48 | "maxUrlLength": 500}}, 49 | { 50 | "servlet-name": "cofaxEmail", 51 | "servlet-class": "org.cofax.cds.EmailServlet", 52 | "init-param": { 53 | "mailHost": "mail1", 54 | "mailHostOverride": "mail2"}}, 55 | { 56 | "servlet-name": "cofaxAdmin", 57 | "servlet-class": "org.cofax.cds.AdminServlet"}, 58 | 59 | { 60 | "servlet-name": "fileServlet", 61 | "servlet-class": "org.cofax.cds.FileServlet"}, 62 | { 63 | "servlet-name": "cofaxTools", 64 | "servlet-class": "org.cofax.cms.CofaxToolsServlet", 65 | "init-param": { 66 | "templatePath": "toolstemplates/", 67 | "log": 1, 68 | "logLocation": "/usr/local/tomcat/logs/CofaxTools.log", 69 | "logMaxSize": "", 70 | "dataLog": 1, 71 | "dataLogLocation": "/usr/local/tomcat/logs/dataLog.log", 72 | "dataLogMaxSize": "", 73 | "removePageCache": "/content/admin/remove?cache=pages&id=", 74 | "removeTemplateCache": "/content/admin/remove?cache=templates&id=", 75 | "fileTransferFolder": "/usr/local/tomcat/webapps/content/fileTransferFolder", 76 | "lookInContext": 1, 77 | "adminGroupID": 4, 78 | "betaServer": true}}], 79 | "servlet-mapping": { 80 | "cofaxCDS": "/", 81 | "cofaxEmail": "/cofaxutil/aemail/*", 82 | "cofaxAdmin": "/admin/*", 83 | "fileServlet": "/static/*", 84 | "cofaxTools": "/tools/*"}, 85 | 86 | "taglib": { 87 | "taglib-uri": "cofax.tld", 88 | "taglib-location": "/WEB-INF/tlds/cofax.tld"}}} -------------------------------------------------------------------------------- /cJSON/tests/test5: -------------------------------------------------------------------------------- 1 | {"menu": { 2 | "header": "SVG Viewer", 3 | "items": [ 4 | {"id": "Open"}, 5 | {"id": "OpenNew", "label": "Open New"}, 6 | null, 7 | {"id": "ZoomIn", "label": "Zoom In"}, 8 | {"id": "ZoomOut", "label": "Zoom Out"}, 9 | {"id": "OriginalView", "label": "Original View"}, 10 | null, 11 | {"id": "Quality"}, 12 | {"id": "Pause"}, 13 | {"id": "Mute"}, 14 | null, 15 | {"id": "Find", "label": "Find..."}, 16 | {"id": "FindAgain", "label": "Find Again"}, 17 | {"id": "Copy"}, 18 | {"id": "CopyAgain", "label": "Copy Again"}, 19 | {"id": "CopySVG", "label": "Copy SVG"}, 20 | {"id": "ViewSVG", "label": "View SVG"}, 21 | {"id": "ViewSource", "label": "View Source"}, 22 | {"id": "SaveAs", "label": "Save As"}, 23 | null, 24 | {"id": "Help"}, 25 | {"id": "About", "label": "About Adobe CVG Viewer..."} 26 | ] 27 | }} 28 | -------------------------------------------------------------------------------- /cJSONFiles.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSONFiles.zip -------------------------------------------------------------------------------- /cJSON_Create/bin/Release/cJSON_Create.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Create/bin/Release/cJSON_Create.exe -------------------------------------------------------------------------------- /cJSON_Create/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 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "cJSON.h" 34 | 35 | static const char *ep; 36 | 37 | const char *cJSON_GetErrorPtr(void) {return ep;} 38 | 39 | static int cJSON_strcasecmp(const char *s1,const char *s2) 40 | { 41 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; 42 | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; 43 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 44 | } 45 | 46 | static void *(*cJSON_malloc)(size_t sz) = malloc; 47 | static void (*cJSON_free)(void *ptr) = free; 48 | 49 | static char* cJSON_strdup(const char* str) 50 | { 51 | size_t len; 52 | char* copy; 53 | 54 | len = strlen(str) + 1; 55 | if (!(copy = (char*)cJSON_malloc(len))) return 0; 56 | memcpy(copy,str,len); 57 | return copy; 58 | } 59 | 60 | void cJSON_InitHooks(cJSON_Hooks* hooks) 61 | { 62 | if (!hooks) { /* Reset hooks */ 63 | cJSON_malloc = malloc; 64 | cJSON_free = free; 65 | return; 66 | } 67 | 68 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 69 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 70 | } 71 | 72 | /* Internal constructor. */ 73 | static cJSON *cJSON_New_Item(void) 74 | { 75 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 76 | if (node) memset(node,0,sizeof(cJSON)); 77 | return node; 78 | } 79 | 80 | /* Delete a cJSON structure. */ 81 | void cJSON_Delete(cJSON *c) 82 | { 83 | cJSON *next; 84 | while (c) 85 | { 86 | next=c->next; 87 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 88 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 89 | if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); 90 | cJSON_free(c); 91 | c=next; 92 | } 93 | } 94 | 95 | /* Parse the input text to generate a number, and populate the result into item. */ 96 | static const char *parse_number(cJSON *item,const char *num) 97 | { 98 | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; 99 | 100 | if (*num=='-') sign=-1,num++; /* Has sign? */ 101 | if (*num=='0') num++; /* is zero */ 102 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 103 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ 104 | if (*num=='e' || *num=='E') /* Exponent? */ 105 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ 106 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ 107 | } 108 | 109 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 110 | 111 | item->valuedouble=n; 112 | item->valueint=(int)n; 113 | item->type=cJSON_Number; 114 | return num; 115 | } 116 | 117 | static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } 118 | 119 | typedef struct {char *buffer; int length; int offset; } printbuffer; 120 | 121 | static char* ensure(printbuffer *p,int needed) 122 | { 123 | char *newbuffer;int newsize; 124 | if (!p || !p->buffer) return 0; 125 | needed+=p->offset; 126 | if (needed<=p->length) return p->buffer+p->offset; 127 | 128 | newsize=pow2gt(needed); 129 | newbuffer=(char*)cJSON_malloc(newsize); 130 | if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} 131 | if (newbuffer) memcpy(newbuffer,p->buffer,p->length); 132 | cJSON_free(p->buffer); 133 | p->length=newsize; 134 | p->buffer=newbuffer; 135 | return newbuffer+p->offset; 136 | } 137 | 138 | static int update(printbuffer *p) 139 | { 140 | char *str; 141 | if (!p || !p->buffer) return 0; 142 | str=p->buffer+p->offset; 143 | return p->offset+strlen(str); 144 | } 145 | 146 | /* Render the number nicely from the given item into a string. */ 147 | static char *print_number(cJSON *item,printbuffer *p) 148 | { 149 | char *str=0; 150 | double d=item->valuedouble; 151 | if (d==0) 152 | { 153 | if (p) str=ensure(p,2); 154 | else str=(char*)cJSON_malloc(2); /* special case for 0. */ 155 | if (str) strcpy(str,"0"); 156 | } 157 | else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) 158 | { 159 | if (p) str=ensure(p,21); 160 | else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 161 | if (str) sprintf(str,"%d",item->valueint); 162 | } 163 | else 164 | { 165 | if (p) str=ensure(p,64); 166 | else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 167 | if (str) 168 | { 169 | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); 170 | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); 171 | else sprintf(str,"%f",d); 172 | } 173 | } 174 | return str; 175 | } 176 | 177 | static unsigned parse_hex4(const char *str) 178 | { 179 | unsigned h=0; 180 | 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; 181 | h=h<<4;str++; 182 | 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; 183 | h=h<<4;str++; 184 | 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; 185 | h=h<<4;str++; 186 | 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; 187 | return h; 188 | } 189 | 190 | /* Parse the input text into an unescaped cstring, and populate item. */ 191 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 192 | static const char *parse_string(cJSON *item,const char *str) 193 | { 194 | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; 195 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ 196 | 197 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ 198 | 199 | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 200 | if (!out) return 0; 201 | 202 | ptr=str+1;ptr2=out; 203 | while (*ptr!='\"' && *ptr) 204 | { 205 | if (*ptr!='\\') *ptr2++=*ptr++; 206 | else 207 | { 208 | ptr++; 209 | switch (*ptr) 210 | { 211 | case 'b': *ptr2++='\b'; break; 212 | case 'f': *ptr2++='\f'; break; 213 | case 'n': *ptr2++='\n'; break; 214 | case 'r': *ptr2++='\r'; break; 215 | case 't': *ptr2++='\t'; break; 216 | case 'u': /* transcode utf16 to utf8. */ 217 | uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ 218 | 219 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ 220 | 221 | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 222 | { 223 | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ 224 | uc2=parse_hex4(ptr+3);ptr+=6; 225 | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ 226 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 227 | } 228 | 229 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 230 | 231 | switch (len) { 232 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 233 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 234 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 235 | case 1: *--ptr2 =(uc | firstByteMark[len]); 236 | } 237 | ptr2+=len; 238 | break; 239 | default: *ptr2++=*ptr; break; 240 | } 241 | ptr++; 242 | } 243 | } 244 | *ptr2=0; 245 | if (*ptr=='\"') ptr++; 246 | item->valuestring=out; 247 | item->type=cJSON_String; 248 | return ptr; 249 | } 250 | 251 | /* Render the cstring provided to an escaped version that can be printed. */ 252 | static char *print_string_ptr(const char *str,printbuffer *p) 253 | { 254 | const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; 255 | 256 | for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; 257 | if (!flag) 258 | { 259 | len=ptr-str; 260 | if (p) out=ensure(p,len+3); 261 | else out=(char*)cJSON_malloc(len+3); 262 | if (!out) return 0; 263 | ptr2=out;*ptr2++='\"'; 264 | strcpy(ptr2,str); 265 | ptr2[len]='\"'; 266 | ptr2[len+1]=0; 267 | return out; 268 | } 269 | 270 | if (!str) 271 | { 272 | if (p) out=ensure(p,3); 273 | else out=(char*)cJSON_malloc(3); 274 | if (!out) return 0; 275 | strcpy(out,"\"\""); 276 | return out; 277 | } 278 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 279 | 280 | if (p) out=ensure(p,len+3); 281 | else out=(char*)cJSON_malloc(len+3); 282 | if (!out) return 0; 283 | 284 | ptr2=out;ptr=str; 285 | *ptr2++='\"'; 286 | while (*ptr) 287 | { 288 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 289 | else 290 | { 291 | *ptr2++='\\'; 292 | switch (token=*ptr++) 293 | { 294 | case '\\': *ptr2++='\\'; break; 295 | case '\"': *ptr2++='\"'; break; 296 | case '\b': *ptr2++='b'; break; 297 | case '\f': *ptr2++='f'; break; 298 | case '\n': *ptr2++='n'; break; 299 | case '\r': *ptr2++='r'; break; 300 | case '\t': *ptr2++='t'; break; 301 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 302 | } 303 | } 304 | } 305 | *ptr2++='\"';*ptr2++=0; 306 | return out; 307 | } 308 | /* Invote print_string_ptr (which is useful) on an item. */ 309 | static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} 310 | 311 | /* Predeclare these prototypes. */ 312 | static const char *parse_value(cJSON *item,const char *value); 313 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); 314 | static const char *parse_array(cJSON *item,const char *value); 315 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); 316 | static const char *parse_object(cJSON *item,const char *value); 317 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); 318 | 319 | /* Utility to jump whitespace and cr/lf */ 320 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 321 | 322 | /* Parse an object - create a new root, and populate. */ 323 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 324 | { 325 | const char *end=0; 326 | cJSON *c=cJSON_New_Item(); 327 | ep=0; 328 | if (!c) return 0; /* memory fail */ 329 | 330 | end=parse_value(c,skip(value)); 331 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 332 | 333 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 334 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} 335 | if (return_parse_end) *return_parse_end=end; 336 | return c; 337 | } 338 | /* Default options for cJSON_Parse */ 339 | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 340 | 341 | /* Render a cJSON item/entity/structure to text. */ 342 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} 343 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} 344 | 345 | char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) 346 | { 347 | printbuffer p; 348 | p.buffer=(char*)cJSON_malloc(prebuffer); 349 | p.length=prebuffer; 350 | p.offset=0; 351 | return print_value(item,0,fmt,&p); 352 | return p.buffer; 353 | } 354 | 355 | 356 | /* Parser core - when encountering text, process appropriately. */ 357 | static const char *parse_value(cJSON *item,const char *value) 358 | { 359 | if (!value) return 0; /* Fail on null. */ 360 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 361 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 362 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 363 | if (*value=='\"') { return parse_string(item,value); } 364 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 365 | if (*value=='[') { return parse_array(item,value); } 366 | if (*value=='{') { return parse_object(item,value); } 367 | 368 | ep=value;return 0; /* failure. */ 369 | } 370 | 371 | /* Render a value to text. */ 372 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) 373 | { 374 | char *out=0; 375 | if (!item) return 0; 376 | if (p) 377 | { 378 | switch ((item->type)&255) 379 | { 380 | case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} 381 | case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} 382 | case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} 383 | case cJSON_Number: out=print_number(item,p);break; 384 | case cJSON_String: out=print_string(item,p);break; 385 | case cJSON_Array: out=print_array(item,depth,fmt,p);break; 386 | case cJSON_Object: out=print_object(item,depth,fmt,p);break; 387 | } 388 | } 389 | else 390 | { 391 | switch ((item->type)&255) 392 | { 393 | case cJSON_NULL: out=cJSON_strdup("null"); break; 394 | case cJSON_False: out=cJSON_strdup("false");break; 395 | case cJSON_True: out=cJSON_strdup("true"); break; 396 | case cJSON_Number: out=print_number(item,0);break; 397 | case cJSON_String: out=print_string(item,0);break; 398 | case cJSON_Array: out=print_array(item,depth,fmt,0);break; 399 | case cJSON_Object: out=print_object(item,depth,fmt,0);break; 400 | } 401 | } 402 | return out; 403 | } 404 | 405 | /* Build an array from input text. */ 406 | static const char *parse_array(cJSON *item,const char *value) 407 | { 408 | cJSON *child; 409 | if (*value!='[') {ep=value;return 0;} /* not an array! */ 410 | 411 | item->type=cJSON_Array; 412 | value=skip(value+1); 413 | if (*value==']') return value+1; /* empty array. */ 414 | 415 | item->child=child=cJSON_New_Item(); 416 | if (!item->child) return 0; /* memory fail */ 417 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ 418 | if (!value) return 0; 419 | 420 | while (*value==',') 421 | { 422 | cJSON *new_item; 423 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 424 | child->next=new_item;new_item->prev=child;child=new_item; 425 | value=skip(parse_value(child,skip(value+1))); 426 | if (!value) return 0; /* memory fail */ 427 | } 428 | 429 | if (*value==']') return value+1; /* end of array */ 430 | ep=value;return 0; /* malformed. */ 431 | } 432 | 433 | /* Render an array to text */ 434 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) 435 | { 436 | char **entries; 437 | char *out=0,*ptr,*ret;int len=5; 438 | cJSON *child=item->child; 439 | int numentries=0,i=0,fail=0; 440 | size_t tmplen=0; 441 | 442 | /* How many entries in the array? */ 443 | while (child) numentries++,child=child->next; 444 | /* Explicitly handle numentries==0 */ 445 | if (!numentries) 446 | { 447 | if (p) out=ensure(p,3); 448 | else out=(char*)cJSON_malloc(3); 449 | if (out) strcpy(out,"[]"); 450 | return out; 451 | } 452 | 453 | if (p) 454 | { 455 | /* Compose the output array. */ 456 | i=p->offset; 457 | ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; 458 | child=item->child; 459 | while (child && !fail) 460 | { 461 | print_value(child,depth+1,fmt,p); 462 | p->offset=update(p); 463 | if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} 464 | child=child->next; 465 | } 466 | ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; 467 | out=(p->buffer)+i; 468 | } 469 | else 470 | { 471 | /* Allocate an array to hold the values for each */ 472 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 473 | if (!entries) return 0; 474 | memset(entries,0,numentries*sizeof(char*)); 475 | /* Retrieve all the results: */ 476 | child=item->child; 477 | while (child && !fail) 478 | { 479 | ret=print_value(child,depth+1,fmt,0); 480 | entries[i++]=ret; 481 | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 482 | child=child->next; 483 | } 484 | 485 | /* If we didn't fail, try to malloc the output string */ 486 | if (!fail) out=(char*)cJSON_malloc(len); 487 | /* If that fails, we fail. */ 488 | if (!out) fail=1; 489 | 490 | /* Handle failure. */ 491 | if (fail) 492 | { 493 | for (i=0;itype=cJSON_Object; 520 | value=skip(value+1); 521 | if (*value=='}') return value+1; /* empty array. */ 522 | 523 | item->child=child=cJSON_New_Item(); 524 | if (!item->child) return 0; 525 | value=skip(parse_string(child,skip(value))); 526 | if (!value) return 0; 527 | child->string=child->valuestring;child->valuestring=0; 528 | if (*value!=':') {ep=value;return 0;} /* fail! */ 529 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 530 | if (!value) return 0; 531 | 532 | while (*value==',') 533 | { 534 | cJSON *new_item; 535 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 536 | child->next=new_item;new_item->prev=child;child=new_item; 537 | value=skip(parse_string(child,skip(value+1))); 538 | if (!value) return 0; 539 | child->string=child->valuestring;child->valuestring=0; 540 | if (*value!=':') {ep=value;return 0;} /* fail! */ 541 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 542 | if (!value) return 0; 543 | } 544 | 545 | if (*value=='}') return value+1; /* end of array */ 546 | ep=value;return 0; /* malformed. */ 547 | } 548 | 549 | /* Render an object to text. */ 550 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) 551 | { 552 | char **entries=0,**names=0; 553 | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 554 | cJSON *child=item->child; 555 | int numentries=0,fail=0; 556 | size_t tmplen=0; 557 | /* Count the number of entries. */ 558 | while (child) numentries++,child=child->next; 559 | /* Explicitly handle empty object case */ 560 | if (!numentries) 561 | { 562 | if (p) out=ensure(p,fmt?depth+4:3); 563 | else out=(char*)cJSON_malloc(fmt?depth+4:3); 564 | if (!out) return 0; 565 | ptr=out;*ptr++='{'; 566 | if (fmt) {*ptr++='\n';for (i=0;ioffset; 574 | len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; 575 | *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; 576 | child=item->child;depth++; 577 | while (child) 578 | { 579 | if (fmt) 580 | { 581 | ptr=ensure(p,depth); if (!ptr) return 0; 582 | for (j=0;joffset+=depth; 584 | } 585 | print_string_ptr(child->string,p); 586 | p->offset=update(p); 587 | 588 | len=fmt?2:1; 589 | ptr=ensure(p,len); if (!ptr) return 0; 590 | *ptr++=':';if (fmt) *ptr++='\t'; 591 | p->offset+=len; 592 | 593 | print_value(child,depth,fmt,p); 594 | p->offset=update(p); 595 | 596 | len=(fmt?1:0)+(child->next?1:0); 597 | ptr=ensure(p,len+1); if (!ptr) return 0; 598 | if (child->next) *ptr++=','; 599 | if (fmt) *ptr++='\n';*ptr=0; 600 | p->offset+=len; 601 | child=child->next; 602 | } 603 | ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; 604 | if (fmt) for (i=0;ibuffer)+i; 607 | } 608 | else 609 | { 610 | /* Allocate space for the names and the objects */ 611 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 612 | if (!entries) return 0; 613 | names=(char**)cJSON_malloc(numentries*sizeof(char*)); 614 | if (!names) {cJSON_free(entries);return 0;} 615 | memset(entries,0,sizeof(char*)*numentries); 616 | memset(names,0,sizeof(char*)*numentries); 617 | 618 | /* Collect all the results into our arrays: */ 619 | child=item->child;depth++;if (fmt) len+=depth; 620 | while (child) 621 | { 622 | names[i]=str=print_string_ptr(child->string,0); 623 | entries[i++]=ret=print_value(child,depth,fmt,0); 624 | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; 625 | child=child->next; 626 | } 627 | 628 | /* Try to allocate the output string */ 629 | if (!fail) out=(char*)cJSON_malloc(len); 630 | if (!out) fail=1; 631 | 632 | /* Handle failure */ 633 | if (fail) 634 | { 635 | for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} 662 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} 663 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} 664 | 665 | /* Utility for array list handling. */ 666 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 667 | /* Utility for handling references. */ 668 | 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;} 669 | 670 | /* Add item to array/object. */ 671 | 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);}} 672 | 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);} 673 | void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} 674 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 675 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 676 | 677 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 678 | 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;} 679 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 680 | 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;} 681 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 682 | 683 | /* Replace array/object items with new ones. */ 684 | void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} 685 | newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} 686 | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 687 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 688 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 689 | 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);}} 690 | 691 | /* Create basic types: */ 692 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 693 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 694 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 695 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 696 | 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;} 697 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} 698 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 699 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 700 | 701 | /* Create Arrays: */ 702 | 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;} 703 | 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;} 704 | 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;} 705 | 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;} 706 | 707 | /* Duplication */ 708 | cJSON *cJSON_Duplicate(cJSON *item,int recurse) 709 | { 710 | cJSON *newitem,*cptr,*nptr=0,*newchild; 711 | /* Bail on bad ptr */ 712 | if (!item) return 0; 713 | /* Create new item */ 714 | newitem=cJSON_New_Item(); 715 | if (!newitem) return 0; 716 | /* Copy over all vars */ 717 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 718 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 719 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 720 | /* If non-recursive, then we're done! */ 721 | if (!recurse) return newitem; 722 | /* Walk the ->next chain for the child. */ 723 | cptr=item->child; 724 | while (cptr) 725 | { 726 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 727 | if (!newchild) {cJSON_Delete(newitem);return 0;} 728 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 729 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 730 | cptr=cptr->next; 731 | } 732 | return newitem; 733 | } 734 | 735 | void cJSON_Minify(char *json) 736 | { 737 | char *into=json; 738 | while (*json) 739 | { 740 | if (*json==' ') json++; 741 | else if (*json=='\t') json++; /* Whitespace characters. */ 742 | else if (*json=='\r') json++; 743 | else if (*json=='\n') json++; 744 | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ 745 | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ 746 | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ 747 | else *into++=*json++; /* All other characters. */ 748 | } 749 | *into=0; /* and null-terminate. */ 750 | } 751 | -------------------------------------------------------------------------------- /cJSON_Create/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 | #define cJSON_StringIsConst 512 42 | 43 | /* The cJSON structure: */ 44 | typedef struct cJSON { 45 | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 46 | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 47 | 48 | int type; /* The type of the item, as above. */ 49 | 50 | char *valuestring; /* The item's string, if type==cJSON_String */ 51 | int valueint; /* The item's number, if type==cJSON_Number */ 52 | double valuedouble; /* The item's number, if type==cJSON_Number */ 53 | 54 | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 55 | } cJSON; 56 | 57 | typedef struct cJSON_Hooks { 58 | void *(*malloc_fn)(size_t sz); 59 | void (*free_fn)(void *ptr); 60 | } cJSON_Hooks; 61 | 62 | /* Supply malloc, realloc and free functions to cJSON */ 63 | extern void cJSON_InitHooks(cJSON_Hooks* hooks); 64 | 65 | 66 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 67 | extern cJSON *cJSON_Parse(const char *value); 68 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 69 | extern char *cJSON_Print(cJSON *item); 70 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 71 | extern char *cJSON_PrintUnformatted(cJSON *item); 72 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 73 | extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); 74 | /* Delete a cJSON entity and all subentities. */ 75 | extern void cJSON_Delete(cJSON *c); 76 | 77 | /* Returns the number of items in an array (or object). */ 78 | extern int cJSON_GetArraySize(cJSON *array); 79 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 80 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); 81 | /* Get item "string" from object. Case insensitive. */ 82 | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); 83 | 84 | /* 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. */ 85 | extern const char *cJSON_GetErrorPtr(void); 86 | 87 | /* These calls create a cJSON item of the appropriate type. */ 88 | extern cJSON *cJSON_CreateNull(void); 89 | extern cJSON *cJSON_CreateTrue(void); 90 | extern cJSON *cJSON_CreateFalse(void); 91 | extern cJSON *cJSON_CreateBool(int b); 92 | extern cJSON *cJSON_CreateNumber(double num); 93 | extern cJSON *cJSON_CreateString(const char *string); 94 | extern cJSON *cJSON_CreateArray(void); 95 | extern cJSON *cJSON_CreateObject(void); 96 | 97 | /* These utilities create an Array of count items. */ 98 | extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); 99 | extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); 100 | extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); 101 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); 102 | 103 | /* Append item to the specified array/object. */ 104 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 105 | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); 106 | extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ 107 | /* 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. */ 108 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 109 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); 110 | 111 | /* Remove/Detatch items from Arrays/Objects. */ 112 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); 113 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); 114 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); 115 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); 116 | 117 | /* Update array items. */ 118 | extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ 119 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); 120 | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 121 | 122 | /* Duplicate a cJSON item */ 123 | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); 124 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 125 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 126 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 127 | 128 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 129 | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); 130 | 131 | extern void cJSON_Minify(char *json); 132 | 133 | /* Macros for creating things quickly. */ 134 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 135 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 136 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 137 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 138 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 139 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 140 | 141 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 142 | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 143 | #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /cJSON_Create/cJSON_Create.bmarks: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /cJSON_Create/cJSON_Create.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /cJSON_Create/cJSON_Create.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1423824890 source:e:\git_project\json_lib_demo\cjson_create\cjson.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | "cJSON.h" 11 | 12 | 1423824802 e:\git_project\json_lib_demo\cjson_create\cjson.h 13 | 14 | 1563693716 source:e:\git_project\json_lib_demo\cjson_create\create.c 15 | "create.h" 16 | "cJSON.h" 17 | "json_str.h" 18 | "stdio.h" 19 | 20 | 1563693337 e:\git_project\json_lib_demo\cjson_create\create.h 21 | 22 | 23 | 24 | 1563600238 e:\git_project\json_lib_demo\cjson_create\json_str.h 25 | 26 | 1563693564 source:e:\git_project\json_lib_demo\cjson_create\main.c 27 | "create.h" 28 | "stdio.h" 29 | 30 | -------------------------------------------------------------------------------- /cJSON_Create/cJSON_Create.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /cJSON_Create/create.c: -------------------------------------------------------------------------------- 1 | #include "create.h" 2 | #include "cJSON.h" 3 | #include "json_str.h" 4 | #include "stdio.h" 5 | 6 | void Create_Simple_JSON(void) 7 | { 8 | /* 9 | { 10 | "CSDN": "https://blog.csdn.net/whik1194", 11 | "cnblogs": "https://home.cnblogs.com/u/whik/", 12 | "Github": "https://github.com/whik/", 13 | "Blog": "http://www.wangchaochao.top/" 14 | } 15 | */ 16 | cJSON *root; 17 | 18 | root = cJSON_CreateObject();//创建一个json对象 19 | 20 | cJSON_AddItemToObject(root, "CSDN", cJSON_CreateString("https://blog.csdn.net/whik1194")); 21 | cJSON_AddItemToObject(root, "cnblogs", cJSON_CreateString("https://home.cnblogs.com/u/whik/")); 22 | cJSON_AddItemToObject(root, "Github", cJSON_CreateString("https://github.com/whik/")); 23 | cJSON_AddStringToObject(root, "Blog", "http://www.wangchaochao.top/"); 24 | 25 | printf("构建的JSON:\n%s\n", cJSON_Print(root)); 26 | cJSON_Delete(root); 27 | } 28 | 29 | void Create_BJTime_JSON(void) 30 | { 31 | /* 32 | { 33 | "status": "success", 34 | "result": { 35 | "timestamp": "ok", 36 | "datetime_1": "2019-07-21 10:46:57", 37 | "datetime_2": "2019年07月21日 10时46分57秒", 38 | "week_1": "0", 39 | "week_2": "星期日", 40 | "week_3": "周日", 41 | "week_4": "Sunday" 42 | }, 43 | "Blog": "www.wangchaochao.top" 44 | } 45 | */ 46 | cJSON *root; 47 | cJSON *result; 48 | 49 | root = cJSON_CreateObject();//创建一个json对象 50 | 51 | result = cJSON_CreateObject(); 52 | //result构建 53 | 54 | cJSON_AddItemToObject(result, "timestamp", cJSON_CreateString("ok")); 55 | //等效于下面 56 | // cJSON_AddStringToObject(result, "timestamp", "ok"); 57 | 58 | cJSON_AddItemToObject(result, "datetime_1", cJSON_CreateString("2019-07-21 10:46:57")); 59 | cJSON_AddItemToObject(result, "datetime_2", cJSON_CreateString("2019年07月21日 10时46分57秒")); 60 | cJSON_AddItemToObject(result, "week_1", cJSON_CreateString("0")); 61 | cJSON_AddItemToObject(result, "week_2", cJSON_CreateString("星期日")); 62 | cJSON_AddItemToObject(result, "week_3", cJSON_CreateString("周日")); 63 | cJSON_AddItemToObject(result, "week_4", cJSON_CreateString("Sunday")); 64 | 65 | //等效于cJSON_AddNumberToObject(root, "ok", 1); 66 | 67 | cJSON_AddItemToObject(root, "status", cJSON_CreateString("success")); 68 | cJSON_AddItemToObject(root, "result", result); 69 | cJSON_AddStringToObject(root, "Blog", "www.wangchaochao.top"); 70 | 71 | printf("构建的JSON:\n%s\n", cJSON_Print(root)); 72 | cJSON_Delete(root); 73 | } 74 | 75 | void Create_Array_Str_JSON(void) 76 | { 77 | /* 78 | ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"] 79 | */ 80 | cJSON *root; 81 | const char *strings[7]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"}; 82 | 83 | root=cJSON_CreateStringArray(strings,7); 84 | 85 | printf("%s\n",cJSON_Print(root)); 86 | cJSON_Delete(root); 87 | } 88 | 89 | void Create_Array_JSON(void) 90 | { 91 | cJSON *root; 92 | cJSON *forceast; 93 | cJSON *day1, *day2, *day3; //数组 94 | 95 | day1 = cJSON_CreateObject(); 96 | day2 = cJSON_CreateObject(); 97 | day3 = cJSON_CreateObject(); 98 | 99 | cJSON_AddStringToObject(day1, "date", "2019-07-21"); //日期 100 | cJSON_AddStringToObject(day1, "cond_txt", "多云"); //天气状况 101 | cJSON_AddStringToObject(day1, "cond_code", "101"); //天气代码 102 | cJSON_AddStringToObject(day1, "hum", "23"); //湿度 103 | cJSON_AddStringToObject(day1, "tmp_H", "31"); //最高温度 104 | cJSON_AddStringToObject(day1, "tmp_L", "25"); //最低温度 105 | 106 | cJSON_AddStringToObject(day2, "date", "2019-07-22"); 107 | cJSON_AddStringToObject(day2, "cond_txt", "晴"); 108 | cJSON_AddStringToObject(day2, "cond_code", "100"); 109 | cJSON_AddStringToObject(day2, "hum", "20"); 110 | cJSON_AddStringToObject(day2, "tmp_H", "33"); 111 | cJSON_AddStringToObject(day2, "tmp_L", "26"); 112 | 113 | cJSON_AddStringToObject(day3, "date", "2019-07-23"); 114 | cJSON_AddStringToObject(day3, "cond_txt", "阵雨"); 115 | cJSON_AddStringToObject(day3, "cond_code", "107"); 116 | cJSON_AddStringToObject(day3, "hum", "45"); 117 | cJSON_AddStringToObject(day3, "tmp_H", "32"); 118 | cJSON_AddStringToObject(day3, "tmp_L", "25"); 119 | 120 | forceast = cJSON_CreateArray(); 121 | //注意顺序,索引依次递增 122 | cJSON_AddItemToArray(forceast, day1); //元素0 123 | cJSON_AddItemToArray(forceast, day2); //元素1 124 | cJSON_AddItemToArray(forceast, day3); //元素2 125 | 126 | root = cJSON_CreateObject(); //创建一个json对象 127 | 128 | cJSON_AddStringToObject(root, "status", "ok"); 129 | cJSON_AddItemToObject(root, "weather", forceast); 130 | cJSON_AddStringToObject(root, "update", "2019-07-21 11:00"); 131 | cJSON_AddStringToObject(root, "Blog", "www.wangchaochao.top"); 132 | //等效于:cJSON_AddItemToObject(root, "update", cJSON_CreateString("2019-07-21 11:00"); 133 | 134 | printf("构建的JSON:\n%s\n", cJSON_Print(root)); 135 | cJSON_Delete(root); 136 | } 137 | /* 138 | { 139 | "status": "ok", 140 | "weather": [{ 141 | "date": "2019-07-21", 142 | "cond_txt": "多云", 143 | "cond_code": "101", 144 | "hum": "23", 145 | "tmp_H": "31", 146 | "tmp_L": "25" 147 | }, { 148 | "date": "2019-07-22", 149 | "cond_txt": "晴", 150 | "cond_code": "100", 151 | "hum": "20", 152 | "tmp_H": "33", 153 | "tmp_L": "26" 154 | }, { 155 | "date": "2019-07-23", 156 | "cond_txt": "阵雨", 157 | "cond_code": "107", 158 | "hum": "45", 159 | "tmp_H": "32", 160 | "tmp_L": "25" 161 | }], 162 | "update": "2019-07-21 11:00", 163 | "Blog": "www.wangchaochao.top" 164 | } 165 | */ 166 | 167 | //构建包含多个数组的JSON字符串 168 | void Create_Array_Nest_JSON(void) 169 | { 170 | struct oil_stu{ 171 | char *city; //城市名称 172 | char *oil_92_price; //92号汽油价格 173 | char *oil_95_price; 174 | char *oil_98_price; 175 | char *oil_0_price; 176 | }; 177 | 178 | cJSON *root; 179 | cJSON *data; //包含多个数组 180 | cJSON *table, *data_bj, *data_sh, *data_js, *data_tj; 181 | 182 | const char *bj_str[5] = {"北京", "6.78", "7.21", "8.19", "6.45"}; 183 | const char *sh_str[5] = {"上海", "6.74", "7.17", "7.87", "6.39"}; 184 | const char *js_str[5] = {"江苏", "6.75", "7.18", "8.06", "6.37"}; 185 | const char *tj_str[5] = {"天津", "6.77", "7.15", "8.07", "6.41"}; 186 | const char *talbe_str[5] = {"地区", "92号汽油", "95号汽油", "98号汽油", "0号柴油"}; 187 | 188 | data_bj = cJSON_CreateStringArray(bj_str, 5); //只包含5个字符串的数组 189 | data_sh = cJSON_CreateStringArray(sh_str, 5); 190 | data_js = cJSON_CreateStringArray(js_str, 5); 191 | data_tj = cJSON_CreateStringArray(tj_str, 5); 192 | table = cJSON_CreateStringArray(talbe_str, 5); 193 | 194 | data = cJSON_CreateArray(); 195 | cJSON_AddItemToArray(data, table); 196 | cJSON_AddItemToArray(data, data_bj); 197 | cJSON_AddItemToArray(data, data_sh); 198 | cJSON_AddItemToArray(data, data_js); 199 | cJSON_AddItemToArray(data, data_tj); 200 | 201 | root = cJSON_CreateObject(); 202 | 203 | cJSON_AddStringToObject(root, "status", "ok"); 204 | cJSON_AddStringToObject(root, "msg", "2019-07-21 11:00"); 205 | cJSON_AddStringToObject(root, "update", "2019-07-21 11:00"); 206 | cJSON_AddItemToObject(root, "data", data); 207 | cJSON_AddStringToObject(root, "About", "wcc"); 208 | cJSON_AddStringToObject(root, "Blog", "www.wangchaochao.top"); 209 | 210 | printf("构建的JSON:\n%s\n", cJSON_Print(root)); 211 | cJSON_Delete(root); 212 | } 213 | /* 214 | { 215 | "status": "ok", 216 | "msg": "全国各省份汽柴油价格信息", 217 | "update": "2019-07-21", 218 | "data": [ 219 | ["地区", "92号汽油", "95号汽油", "98号汽油", "0号柴油"], 220 | ["北京", "6.78", "7.21", "8.19", "6.45"], 221 | ["上海", "6.74", "7.17", "7.87", "6.39"], 222 | ["江苏", "6.75", "7.18", "8.06", "6.37"], 223 | ["天津", "6.77", "7.15", "8.07", "6.41"] 224 | ], 225 | "About": "wcc", 226 | "Blog": "www.wangchaochao.top" 227 | } 228 | */ 229 | -------------------------------------------------------------------------------- /cJSON_Create/create.h: -------------------------------------------------------------------------------- 1 | #ifndef __CREATE_H__ 2 | #define __CREATH_H__ 3 | 4 | #include 5 | #include 6 | 7 | void Create_Simple_JSON(void); 8 | void Create_BJTime_JSON(void); 9 | void Create_Array_JSON(void); 10 | void Create_Array_Nest_JSON(void); 11 | void Create_Array_Str_JSON(void); 12 | 13 | 14 | #endif // __CREATE_H__ 15 | -------------------------------------------------------------------------------- /cJSON_Create/doxygen/doxyfile: -------------------------------------------------------------------------------- 1 | #****************************************************************************** 2 | # Base configuration for doxygen, generated by DoxyBlocks. 3 | # You may change these defaults to suit your purposes. 4 | #****************************************************************************** 5 | 6 | # Doxyfile 1.7.3 7 | 8 | #--------------------------------------------------------------------------- 9 | # Project related configuration options 10 | #--------------------------------------------------------------------------- 11 | DOXYFILE_ENCODING = UTF-8 12 | PROJECT_NAME = cJSON_Create 13 | PROJECT_NUMBER = 14 | PROJECT_BRIEF = 15 | PROJECT_LOGO = 16 | OUTPUT_DIRECTORY = 17 | CREATE_SUBDIRS = NO 18 | OUTPUT_LANGUAGE = English 19 | BRIEF_MEMBER_DESC = YES 20 | REPEAT_BRIEF = YES 21 | ABBREVIATE_BRIEF = 22 | ALWAYS_DETAILED_SEC = NO 23 | INLINE_INHERITED_MEMB = NO 24 | FULL_PATH_NAMES = NO 25 | STRIP_FROM_PATH = 26 | STRIP_FROM_INC_PATH = 27 | SHORT_NAMES = NO 28 | JAVADOC_AUTOBRIEF = NO 29 | QT_AUTOBRIEF = NO 30 | MULTILINE_CPP_IS_BRIEF = NO 31 | INHERIT_DOCS = YES 32 | SEPARATE_MEMBER_PAGES = NO 33 | TAB_SIZE = 8 34 | ALIASES = 35 | OPTIMIZE_OUTPUT_FOR_C = NO 36 | OPTIMIZE_OUTPUT_JAVA = NO 37 | OPTIMIZE_FOR_FORTRAN = NO 38 | OPTIMIZE_OUTPUT_VHDL = NO 39 | EXTENSION_MAPPING = 40 | BUILTIN_STL_SUPPORT = NO 41 | CPP_CLI_SUPPORT = NO 42 | SIP_SUPPORT = NO 43 | IDL_PROPERTY_SUPPORT = YES 44 | DISTRIBUTE_GROUP_DOC = NO 45 | SUBGROUPING = YES 46 | TYPEDEF_HIDES_STRUCT = NO 47 | SYMBOL_CACHE_SIZE = 0 48 | #--------------------------------------------------------------------------- 49 | # Build related configuration options 50 | #--------------------------------------------------------------------------- 51 | EXTRACT_ALL = NO 52 | EXTRACT_PRIVATE = NO 53 | EXTRACT_STATIC = NO 54 | EXTRACT_LOCAL_CLASSES = YES 55 | EXTRACT_LOCAL_METHODS = NO 56 | EXTRACT_ANON_NSPACES = NO 57 | HIDE_UNDOC_MEMBERS = NO 58 | HIDE_UNDOC_CLASSES = NO 59 | HIDE_FRIEND_COMPOUNDS = NO 60 | HIDE_IN_BODY_DOCS = NO 61 | INTERNAL_DOCS = NO 62 | CASE_SENSE_NAMES = NO 63 | HIDE_SCOPE_NAMES = NO 64 | SHOW_INCLUDE_FILES = YES 65 | FORCE_LOCAL_INCLUDES = NO 66 | INLINE_INFO = YES 67 | SORT_MEMBER_DOCS = YES 68 | SORT_BRIEF_DOCS = NO 69 | SORT_MEMBERS_CTORS_1ST = NO 70 | SORT_GROUP_NAMES = NO 71 | SORT_BY_SCOPE_NAME = NO 72 | STRICT_PROTO_MATCHING = NO 73 | GENERATE_TODOLIST = YES 74 | GENERATE_TESTLIST = YES 75 | GENERATE_BUGLIST = YES 76 | GENERATE_DEPRECATEDLIST= YES 77 | ENABLED_SECTIONS = 78 | MAX_INITIALIZER_LINES = 30 79 | SHOW_USED_FILES = YES 80 | SHOW_DIRECTORIES = NO 81 | SHOW_FILES = YES 82 | SHOW_NAMESPACES = YES 83 | FILE_VERSION_FILTER = 84 | LAYOUT_FILE = 85 | #--------------------------------------------------------------------------- 86 | # configuration options related to warning and progress messages 87 | #--------------------------------------------------------------------------- 88 | QUIET = NO 89 | WARNINGS = YES 90 | WARN_IF_UNDOCUMENTED = NO 91 | WARN_IF_DOC_ERROR = YES 92 | WARN_NO_PARAMDOC = YES 93 | WARN_FORMAT = "$file:$line: $text" 94 | WARN_LOGFILE = "E:\Git_Project\JSON_Lib_Demo\cJSON_Create\doxygen\doxygen.log" 95 | #--------------------------------------------------------------------------- 96 | # configuration options related to the input files 97 | #--------------------------------------------------------------------------- 98 | INPUT = \ 99 | "..\json_str.h" \ 100 | "..\cJSON.c" \ 101 | "..\cJSON.h" \ 102 | "..\create.c" \ 103 | "..\create.h" \ 104 | "..\main.c" 105 | INPUT_ENCODING = UTF-8 106 | FILE_PATTERNS = 107 | RECURSIVE = NO 108 | EXCLUDE = 109 | EXCLUDE_SYMLINKS = NO 110 | EXCLUDE_PATTERNS = 111 | EXCLUDE_SYMBOLS = 112 | EXAMPLE_PATH = 113 | EXAMPLE_PATTERNS = 114 | EXAMPLE_RECURSIVE = NO 115 | IMAGE_PATH = 116 | INPUT_FILTER = 117 | FILTER_PATTERNS = 118 | FILTER_SOURCE_FILES = NO 119 | FILTER_SOURCE_PATTERNS = 120 | #--------------------------------------------------------------------------- 121 | # configuration options related to source browsing 122 | #--------------------------------------------------------------------------- 123 | SOURCE_BROWSER = NO 124 | INLINE_SOURCES = NO 125 | STRIP_CODE_COMMENTS = YES 126 | REFERENCED_BY_RELATION = NO 127 | REFERENCES_RELATION = NO 128 | REFERENCES_LINK_SOURCE = YES 129 | USE_HTAGS = NO 130 | VERBATIM_HEADERS = YES 131 | #--------------------------------------------------------------------------- 132 | # configuration options related to the alphabetical class index 133 | #--------------------------------------------------------------------------- 134 | ALPHABETICAL_INDEX = YES 135 | COLS_IN_ALPHA_INDEX = 5 136 | IGNORE_PREFIX = 137 | #--------------------------------------------------------------------------- 138 | # configuration options related to the HTML output 139 | #--------------------------------------------------------------------------- 140 | GENERATE_HTML = YES 141 | HTML_OUTPUT = html 142 | HTML_FILE_EXTENSION = .html 143 | HTML_HEADER = 144 | HTML_FOOTER = 145 | HTML_STYLESHEET = 146 | HTML_COLORSTYLE_HUE = 220 147 | HTML_COLORSTYLE_SAT = 100 148 | HTML_COLORSTYLE_GAMMA = 80 149 | HTML_TIMESTAMP = YES 150 | HTML_ALIGN_MEMBERS = YES 151 | HTML_DYNAMIC_SECTIONS = NO 152 | GENERATE_DOCSET = NO 153 | DOCSET_FEEDNAME = "Doxygen generated docs" 154 | DOCSET_BUNDLE_ID = org.doxygen.Project 155 | DOCSET_PUBLISHER_ID = org.doxygen.Publisher 156 | DOCSET_PUBLISHER_NAME = Publisher 157 | GENERATE_HTMLHELP = NO 158 | CHM_FILE = "../cJSON_Create.chm" 159 | HHC_LOCATION = 160 | GENERATE_CHI = NO 161 | CHM_INDEX_ENCODING = 162 | BINARY_TOC = NO 163 | TOC_EXPAND = NO 164 | GENERATE_QHP = NO 165 | QCH_FILE = 166 | QHP_NAMESPACE = org.doxygen.Project 167 | QHP_VIRTUAL_FOLDER = doc 168 | QHP_CUST_FILTER_NAME = 169 | QHP_CUST_FILTER_ATTRS = 170 | QHP_SECT_FILTER_ATTRS = 171 | QHG_LOCATION = 172 | GENERATE_ECLIPSEHELP = NO 173 | ECLIPSE_DOC_ID = org.doxygen.Project 174 | DISABLE_INDEX = NO 175 | ENUM_VALUES_PER_LINE = 4 176 | GENERATE_TREEVIEW = YES 177 | USE_INLINE_TREES = NO 178 | TREEVIEW_WIDTH = 250 179 | EXT_LINKS_IN_WINDOW = NO 180 | FORMULA_FONTSIZE = 10 181 | FORMULA_TRANSPARENT = YES 182 | USE_MATHJAX = NO 183 | MATHJAX_RELPATH = http://www.mathjax.org/mathjax 184 | SEARCHENGINE = YES 185 | SERVER_BASED_SEARCH = NO 186 | #--------------------------------------------------------------------------- 187 | # configuration options related to the LaTeX output 188 | #--------------------------------------------------------------------------- 189 | GENERATE_LATEX = NO 190 | LATEX_OUTPUT = latex 191 | LATEX_CMD_NAME = latex 192 | MAKEINDEX_CMD_NAME = makeindex 193 | COMPACT_LATEX = NO 194 | PAPER_TYPE = a4 195 | EXTRA_PACKAGES = 196 | LATEX_HEADER = 197 | PDF_HYPERLINKS = YES 198 | USE_PDFLATEX = YES 199 | LATEX_BATCHMODE = NO 200 | LATEX_HIDE_INDICES = NO 201 | LATEX_SOURCE_CODE = NO 202 | #--------------------------------------------------------------------------- 203 | # configuration options related to the RTF output 204 | #--------------------------------------------------------------------------- 205 | GENERATE_RTF = NO 206 | RTF_OUTPUT = rtf 207 | COMPACT_RTF = NO 208 | RTF_HYPERLINKS = NO 209 | RTF_STYLESHEET_FILE = 210 | RTF_EXTENSIONS_FILE = 211 | #--------------------------------------------------------------------------- 212 | # configuration options related to the man page output 213 | #--------------------------------------------------------------------------- 214 | GENERATE_MAN = NO 215 | MAN_OUTPUT = man 216 | MAN_EXTENSION = .3 217 | MAN_LINKS = NO 218 | #--------------------------------------------------------------------------- 219 | # configuration options related to the XML output 220 | #--------------------------------------------------------------------------- 221 | GENERATE_XML = NO 222 | XML_OUTPUT = xml 223 | XML_SCHEMA = 224 | XML_DTD = 225 | XML_PROGRAMLISTING = YES 226 | #--------------------------------------------------------------------------- 227 | # configuration options for the AutoGen Definitions output 228 | #--------------------------------------------------------------------------- 229 | GENERATE_AUTOGEN_DEF = NO 230 | #--------------------------------------------------------------------------- 231 | # configuration options related to the Perl module output 232 | #--------------------------------------------------------------------------- 233 | GENERATE_PERLMOD = NO 234 | PERLMOD_LATEX = NO 235 | PERLMOD_PRETTY = YES 236 | PERLMOD_MAKEVAR_PREFIX = 237 | #--------------------------------------------------------------------------- 238 | # Configuration options related to the preprocessor 239 | #--------------------------------------------------------------------------- 240 | ENABLE_PREPROCESSING = YES 241 | MACRO_EXPANSION = YES 242 | EXPAND_ONLY_PREDEF = YES 243 | SEARCH_INCLUDES = YES 244 | INCLUDE_PATH = 245 | INCLUDE_FILE_PATTERNS = 246 | PREDEFINED = WXUNUSED()= 247 | EXPAND_AS_DEFINED = 248 | SKIP_FUNCTION_MACROS = YES 249 | #--------------------------------------------------------------------------- 250 | # Configuration::additions related to external references 251 | #--------------------------------------------------------------------------- 252 | TAGFILES = 253 | GENERATE_TAGFILE = 254 | ALLEXTERNALS = NO 255 | EXTERNAL_GROUPS = YES 256 | PERL_PATH = /usr/bin/perl 257 | #--------------------------------------------------------------------------- 258 | # Configuration options related to the dot tool 259 | #--------------------------------------------------------------------------- 260 | CLASS_DIAGRAMS = NO 261 | MSCGEN_PATH = 262 | HIDE_UNDOC_RELATIONS = YES 263 | HAVE_DOT = NO 264 | DOT_NUM_THREADS = 0 265 | DOT_FONTNAME = Helvetica 266 | DOT_FONTSIZE = 10 267 | DOT_FONTPATH = 268 | CLASS_GRAPH = YES 269 | COLLABORATION_GRAPH = YES 270 | GROUP_GRAPHS = YES 271 | UML_LOOK = NO 272 | TEMPLATE_RELATIONS = NO 273 | INCLUDE_GRAPH = YES 274 | INCLUDED_BY_GRAPH = YES 275 | CALL_GRAPH = YES 276 | CALLER_GRAPH = NO 277 | GRAPHICAL_HIERARCHY = YES 278 | DIRECTORY_GRAPH = YES 279 | DOT_IMAGE_FORMAT = png 280 | DOT_PATH = 281 | DOTFILE_DIRS = 282 | MSCFILE_DIRS = 283 | DOT_GRAPH_MAX_NODES = 50 284 | MAX_DOT_GRAPH_DEPTH = 0 285 | DOT_TRANSPARENT = NO 286 | DOT_MULTI_TARGETS = NO 287 | GENERATE_LEGEND = YES 288 | DOT_CLEANUP = YES 289 | 290 | -------------------------------------------------------------------------------- /cJSON_Create/main.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Create/main.c -------------------------------------------------------------------------------- /cJSON_Create/obj/Release/cJSON.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Create/obj/Release/cJSON.o -------------------------------------------------------------------------------- /cJSON_Create/obj/Release/create.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Create/obj/Release/create.o -------------------------------------------------------------------------------- /cJSON_Create/obj/Release/main.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Create/obj/Release/main.o -------------------------------------------------------------------------------- /cJSON_Parse/a.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Parse/a.exe -------------------------------------------------------------------------------- /cJSON_Parse/bin/Release/cJSON_Parse.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Parse/bin/Release/cJSON_Parse.exe -------------------------------------------------------------------------------- /cJSON_Parse/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 | 23 | /* cJSON */ 24 | /* JSON parser in C. */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "cJSON.h" 34 | 35 | static const char *ep; 36 | 37 | const char *cJSON_GetErrorPtr(void) {return ep;} 38 | 39 | static int cJSON_strcasecmp(const char *s1,const char *s2) 40 | { 41 | if (!s1) return (s1==s2)?0:1;if (!s2) return 1; 42 | for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; 43 | return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); 44 | } 45 | 46 | static void *(*cJSON_malloc)(size_t sz) = malloc; 47 | static void (*cJSON_free)(void *ptr) = free; 48 | 49 | static char* cJSON_strdup(const char* str) 50 | { 51 | size_t len; 52 | char* copy; 53 | 54 | len = strlen(str) + 1; 55 | if (!(copy = (char*)cJSON_malloc(len))) return 0; 56 | memcpy(copy,str,len); 57 | return copy; 58 | } 59 | 60 | void cJSON_InitHooks(cJSON_Hooks* hooks) 61 | { 62 | if (!hooks) { /* Reset hooks */ 63 | cJSON_malloc = malloc; 64 | cJSON_free = free; 65 | return; 66 | } 67 | 68 | cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc; 69 | cJSON_free = (hooks->free_fn)?hooks->free_fn:free; 70 | } 71 | 72 | /* Internal constructor. */ 73 | static cJSON *cJSON_New_Item(void) 74 | { 75 | cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON)); 76 | if (node) memset(node,0,sizeof(cJSON)); 77 | return node; 78 | } 79 | 80 | /* Delete a cJSON structure. */ 81 | void cJSON_Delete(cJSON *c) 82 | { 83 | cJSON *next; 84 | while (c) 85 | { 86 | next=c->next; 87 | if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child); 88 | if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring); 89 | if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string); 90 | cJSON_free(c); 91 | c=next; 92 | } 93 | } 94 | 95 | /* Parse the input text to generate a number, and populate the result into item. */ 96 | static const char *parse_number(cJSON *item,const char *num) 97 | { 98 | double n=0,sign=1,scale=0;int subscale=0,signsubscale=1; 99 | 100 | if (*num=='-') sign=-1,num++; /* Has sign? */ 101 | if (*num=='0') num++; /* is zero */ 102 | if (*num>='1' && *num<='9') do n=(n*10.0)+(*num++ -'0'); while (*num>='0' && *num<='9'); /* Number? */ 103 | if (*num=='.' && num[1]>='0' && num[1]<='9') {num++; do n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');} /* Fractional part? */ 104 | if (*num=='e' || *num=='E') /* Exponent? */ 105 | { num++;if (*num=='+') num++; else if (*num=='-') signsubscale=-1,num++; /* With sign? */ 106 | while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0'); /* Number? */ 107 | } 108 | 109 | n=sign*n*pow(10.0,(scale+subscale*signsubscale)); /* number = +/- number.fraction * 10^+/- exponent */ 110 | 111 | item->valuedouble=n; 112 | item->valueint=(int)n; 113 | item->type=cJSON_Number; 114 | return num; 115 | } 116 | 117 | static int pow2gt (int x) { --x; x|=x>>1; x|=x>>2; x|=x>>4; x|=x>>8; x|=x>>16; return x+1; } 118 | 119 | typedef struct {char *buffer; int length; int offset; } printbuffer; 120 | 121 | static char* ensure(printbuffer *p,int needed) 122 | { 123 | char *newbuffer;int newsize; 124 | if (!p || !p->buffer) return 0; 125 | needed+=p->offset; 126 | if (needed<=p->length) return p->buffer+p->offset; 127 | 128 | newsize=pow2gt(needed); 129 | newbuffer=(char*)cJSON_malloc(newsize); 130 | if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;} 131 | if (newbuffer) memcpy(newbuffer,p->buffer,p->length); 132 | cJSON_free(p->buffer); 133 | p->length=newsize; 134 | p->buffer=newbuffer; 135 | return newbuffer+p->offset; 136 | } 137 | 138 | static int update(printbuffer *p) 139 | { 140 | char *str; 141 | if (!p || !p->buffer) return 0; 142 | str=p->buffer+p->offset; 143 | return p->offset+strlen(str); 144 | } 145 | 146 | /* Render the number nicely from the given item into a string. */ 147 | static char *print_number(cJSON *item,printbuffer *p) 148 | { 149 | char *str=0; 150 | double d=item->valuedouble; 151 | if (d==0) 152 | { 153 | if (p) str=ensure(p,2); 154 | else str=(char*)cJSON_malloc(2); /* special case for 0. */ 155 | if (str) strcpy(str,"0"); 156 | } 157 | else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=INT_MAX && d>=INT_MIN) 158 | { 159 | if (p) str=ensure(p,21); 160 | else str=(char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ 161 | if (str) sprintf(str,"%d",item->valueint); 162 | } 163 | else 164 | { 165 | if (p) str=ensure(p,64); 166 | else str=(char*)cJSON_malloc(64); /* This is a nice tradeoff. */ 167 | if (str) 168 | { 169 | if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)sprintf(str,"%.0f",d); 170 | else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9) sprintf(str,"%e",d); 171 | else sprintf(str,"%f",d); 172 | } 173 | } 174 | return str; 175 | } 176 | 177 | static unsigned parse_hex4(const char *str) 178 | { 179 | unsigned h=0; 180 | 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; 181 | h=h<<4;str++; 182 | 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; 183 | h=h<<4;str++; 184 | 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; 185 | h=h<<4;str++; 186 | 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; 187 | return h; 188 | } 189 | 190 | /* Parse the input text into an unescaped cstring, and populate item. */ 191 | static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; 192 | static const char *parse_string(cJSON *item,const char *str) 193 | { 194 | const char *ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2; 195 | if (*str!='\"') {ep=str;return 0;} /* not a string! */ 196 | 197 | while (*ptr!='\"' && *ptr && ++len) if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */ 198 | 199 | out=(char*)cJSON_malloc(len+1); /* This is how long we need for the string, roughly. */ 200 | if (!out) return 0; 201 | 202 | ptr=str+1;ptr2=out; 203 | while (*ptr!='\"' && *ptr) 204 | { 205 | if (*ptr!='\\') *ptr2++=*ptr++; 206 | else 207 | { 208 | ptr++; 209 | switch (*ptr) 210 | { 211 | case 'b': *ptr2++='\b'; break; 212 | case 'f': *ptr2++='\f'; break; 213 | case 'n': *ptr2++='\n'; break; 214 | case 'r': *ptr2++='\r'; break; 215 | case 't': *ptr2++='\t'; break; 216 | case 'u': /* transcode utf16 to utf8. */ 217 | uc=parse_hex4(ptr+1);ptr+=4; /* get the unicode char. */ 218 | 219 | if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; /* check for invalid. */ 220 | 221 | if (uc>=0xD800 && uc<=0xDBFF) /* UTF16 surrogate pairs. */ 222 | { 223 | if (ptr[1]!='\\' || ptr[2]!='u') break; /* missing second-half of surrogate. */ 224 | uc2=parse_hex4(ptr+3);ptr+=6; 225 | if (uc2<0xDC00 || uc2>0xDFFF) break; /* invalid second-half of surrogate. */ 226 | uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); 227 | } 228 | 229 | len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len; 230 | 231 | switch (len) { 232 | case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 233 | case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 234 | case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; 235 | case 1: *--ptr2 =(uc | firstByteMark[len]); 236 | } 237 | ptr2+=len; 238 | break; 239 | default: *ptr2++=*ptr; break; 240 | } 241 | ptr++; 242 | } 243 | } 244 | *ptr2=0; 245 | if (*ptr=='\"') ptr++; 246 | item->valuestring=out; 247 | item->type=cJSON_String; 248 | return ptr; 249 | } 250 | 251 | /* Render the cstring provided to an escaped version that can be printed. */ 252 | static char *print_string_ptr(const char *str,printbuffer *p) 253 | { 254 | const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token; 255 | 256 | for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0; 257 | if (!flag) 258 | { 259 | len=ptr-str; 260 | if (p) out=ensure(p,len+3); 261 | else out=(char*)cJSON_malloc(len+3); 262 | if (!out) return 0; 263 | ptr2=out;*ptr2++='\"'; 264 | strcpy(ptr2,str); 265 | ptr2[len]='\"'; 266 | ptr2[len+1]=0; 267 | return out; 268 | } 269 | 270 | if (!str) 271 | { 272 | if (p) out=ensure(p,3); 273 | else out=(char*)cJSON_malloc(3); 274 | if (!out) return 0; 275 | strcpy(out,"\"\""); 276 | return out; 277 | } 278 | ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;} 279 | 280 | if (p) out=ensure(p,len+3); 281 | else out=(char*)cJSON_malloc(len+3); 282 | if (!out) return 0; 283 | 284 | ptr2=out;ptr=str; 285 | *ptr2++='\"'; 286 | while (*ptr) 287 | { 288 | if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++; 289 | else 290 | { 291 | *ptr2++='\\'; 292 | switch (token=*ptr++) 293 | { 294 | case '\\': *ptr2++='\\'; break; 295 | case '\"': *ptr2++='\"'; break; 296 | case '\b': *ptr2++='b'; break; 297 | case '\f': *ptr2++='f'; break; 298 | case '\n': *ptr2++='n'; break; 299 | case '\r': *ptr2++='r'; break; 300 | case '\t': *ptr2++='t'; break; 301 | default: sprintf(ptr2,"u%04x",token);ptr2+=5; break; /* escape and print */ 302 | } 303 | } 304 | } 305 | *ptr2++='\"';*ptr2++=0; 306 | return out; 307 | } 308 | /* Invote print_string_ptr (which is useful) on an item. */ 309 | static char *print_string(cJSON *item,printbuffer *p) {return print_string_ptr(item->valuestring,p);} 310 | 311 | /* Predeclare these prototypes. */ 312 | static const char *parse_value(cJSON *item,const char *value); 313 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p); 314 | static const char *parse_array(cJSON *item,const char *value); 315 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p); 316 | static const char *parse_object(cJSON *item,const char *value); 317 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p); 318 | 319 | /* Utility to jump whitespace and cr/lf */ 320 | static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;} 321 | 322 | /* Parse an object - create a new root, and populate. */ 323 | cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated) 324 | { 325 | const char *end=0; 326 | cJSON *c=cJSON_New_Item(); 327 | ep=0; 328 | if (!c) return 0; /* memory fail */ 329 | 330 | end=parse_value(c,skip(value)); 331 | if (!end) {cJSON_Delete(c);return 0;} /* parse failure. ep is set. */ 332 | 333 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 334 | if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);ep=end;return 0;}} 335 | if (return_parse_end) *return_parse_end=end; 336 | return c; 337 | } 338 | /* Default options for cJSON_Parse */ 339 | cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);} 340 | 341 | /* Render a cJSON item/entity/structure to text. */ 342 | char *cJSON_Print(cJSON *item) {return print_value(item,0,1,0);} 343 | char *cJSON_PrintUnformatted(cJSON *item) {return print_value(item,0,0,0);} 344 | 345 | char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt) 346 | { 347 | printbuffer p; 348 | p.buffer=(char*)cJSON_malloc(prebuffer); 349 | p.length=prebuffer; 350 | p.offset=0; 351 | return print_value(item,0,fmt,&p); 352 | return p.buffer; 353 | } 354 | 355 | 356 | /* Parser core - when encountering text, process appropriately. */ 357 | static const char *parse_value(cJSON *item,const char *value) 358 | { 359 | if (!value) return 0; /* Fail on null. */ 360 | if (!strncmp(value,"null",4)) { item->type=cJSON_NULL; return value+4; } 361 | if (!strncmp(value,"false",5)) { item->type=cJSON_False; return value+5; } 362 | if (!strncmp(value,"true",4)) { item->type=cJSON_True; item->valueint=1; return value+4; } 363 | if (*value=='\"') { return parse_string(item,value); } 364 | if (*value=='-' || (*value>='0' && *value<='9')) { return parse_number(item,value); } 365 | if (*value=='[') { return parse_array(item,value); } 366 | if (*value=='{') { return parse_object(item,value); } 367 | 368 | ep=value;return 0; /* failure. */ 369 | } 370 | 371 | /* Render a value to text. */ 372 | static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p) 373 | { 374 | char *out=0; 375 | if (!item) return 0; 376 | if (p) 377 | { 378 | switch ((item->type)&255) 379 | { 380 | case cJSON_NULL: {out=ensure(p,5); if (out) strcpy(out,"null"); break;} 381 | case cJSON_False: {out=ensure(p,6); if (out) strcpy(out,"false"); break;} 382 | case cJSON_True: {out=ensure(p,5); if (out) strcpy(out,"true"); break;} 383 | case cJSON_Number: out=print_number(item,p);break; 384 | case cJSON_String: out=print_string(item,p);break; 385 | case cJSON_Array: out=print_array(item,depth,fmt,p);break; 386 | case cJSON_Object: out=print_object(item,depth,fmt,p);break; 387 | } 388 | } 389 | else 390 | { 391 | switch ((item->type)&255) 392 | { 393 | case cJSON_NULL: out=cJSON_strdup("null"); break; 394 | case cJSON_False: out=cJSON_strdup("false");break; 395 | case cJSON_True: out=cJSON_strdup("true"); break; 396 | case cJSON_Number: out=print_number(item,0);break; 397 | case cJSON_String: out=print_string(item,0);break; 398 | case cJSON_Array: out=print_array(item,depth,fmt,0);break; 399 | case cJSON_Object: out=print_object(item,depth,fmt,0);break; 400 | } 401 | } 402 | return out; 403 | } 404 | 405 | /* Build an array from input text. */ 406 | static const char *parse_array(cJSON *item,const char *value) 407 | { 408 | cJSON *child; 409 | if (*value!='[') {ep=value;return 0;} /* not an array! */ 410 | 411 | item->type=cJSON_Array; 412 | value=skip(value+1); 413 | if (*value==']') return value+1; /* empty array. */ 414 | 415 | item->child=child=cJSON_New_Item(); 416 | if (!item->child) return 0; /* memory fail */ 417 | value=skip(parse_value(child,skip(value))); /* skip any spacing, get the value. */ 418 | if (!value) return 0; 419 | 420 | while (*value==',') 421 | { 422 | cJSON *new_item; 423 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 424 | child->next=new_item;new_item->prev=child;child=new_item; 425 | value=skip(parse_value(child,skip(value+1))); 426 | if (!value) return 0; /* memory fail */ 427 | } 428 | 429 | if (*value==']') return value+1; /* end of array */ 430 | ep=value;return 0; /* malformed. */ 431 | } 432 | 433 | /* Render an array to text */ 434 | static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p) 435 | { 436 | char **entries; 437 | char *out=0,*ptr,*ret;int len=5; 438 | cJSON *child=item->child; 439 | int numentries=0,i=0,fail=0; 440 | size_t tmplen=0; 441 | 442 | /* How many entries in the array? */ 443 | while (child) numentries++,child=child->next; 444 | /* Explicitly handle numentries==0 */ 445 | if (!numentries) 446 | { 447 | if (p) out=ensure(p,3); 448 | else out=(char*)cJSON_malloc(3); 449 | if (out) strcpy(out,"[]"); 450 | return out; 451 | } 452 | 453 | if (p) 454 | { 455 | /* Compose the output array. */ 456 | i=p->offset; 457 | ptr=ensure(p,1);if (!ptr) return 0; *ptr='['; p->offset++; 458 | child=item->child; 459 | while (child && !fail) 460 | { 461 | print_value(child,depth+1,fmt,p); 462 | p->offset=update(p); 463 | if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;} 464 | child=child->next; 465 | } 466 | ptr=ensure(p,2);if (!ptr) return 0; *ptr++=']';*ptr=0; 467 | out=(p->buffer)+i; 468 | } 469 | else 470 | { 471 | /* Allocate an array to hold the values for each */ 472 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 473 | if (!entries) return 0; 474 | memset(entries,0,numentries*sizeof(char*)); 475 | /* Retrieve all the results: */ 476 | child=item->child; 477 | while (child && !fail) 478 | { 479 | ret=print_value(child,depth+1,fmt,0); 480 | entries[i++]=ret; 481 | if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1; 482 | child=child->next; 483 | } 484 | 485 | /* If we didn't fail, try to malloc the output string */ 486 | if (!fail) out=(char*)cJSON_malloc(len); 487 | /* If that fails, we fail. */ 488 | if (!out) fail=1; 489 | 490 | /* Handle failure. */ 491 | if (fail) 492 | { 493 | for (i=0;itype=cJSON_Object; 520 | value=skip(value+1); 521 | if (*value=='}') return value+1; /* empty array. */ 522 | 523 | item->child=child=cJSON_New_Item(); 524 | if (!item->child) return 0; 525 | value=skip(parse_string(child,skip(value))); 526 | if (!value) return 0; 527 | child->string=child->valuestring;child->valuestring=0; 528 | if (*value!=':') {ep=value;return 0;} /* fail! */ 529 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 530 | if (!value) return 0; 531 | 532 | while (*value==',') 533 | { 534 | cJSON *new_item; 535 | if (!(new_item=cJSON_New_Item())) return 0; /* memory fail */ 536 | child->next=new_item;new_item->prev=child;child=new_item; 537 | value=skip(parse_string(child,skip(value+1))); 538 | if (!value) return 0; 539 | child->string=child->valuestring;child->valuestring=0; 540 | if (*value!=':') {ep=value;return 0;} /* fail! */ 541 | value=skip(parse_value(child,skip(value+1))); /* skip any spacing, get the value. */ 542 | if (!value) return 0; 543 | } 544 | 545 | if (*value=='}') return value+1; /* end of array */ 546 | ep=value;return 0; /* malformed. */ 547 | } 548 | 549 | /* Render an object to text. */ 550 | static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p) 551 | { 552 | char **entries=0,**names=0; 553 | char *out=0,*ptr,*ret,*str;int len=7,i=0,j; 554 | cJSON *child=item->child; 555 | int numentries=0,fail=0; 556 | size_t tmplen=0; 557 | /* Count the number of entries. */ 558 | while (child) numentries++,child=child->next; 559 | /* Explicitly handle empty object case */ 560 | if (!numentries) 561 | { 562 | if (p) out=ensure(p,fmt?depth+4:3); 563 | else out=(char*)cJSON_malloc(fmt?depth+4:3); 564 | if (!out) return 0; 565 | ptr=out;*ptr++='{'; 566 | if (fmt) {*ptr++='\n';for (i=0;ioffset; 574 | len=fmt?2:1; ptr=ensure(p,len+1); if (!ptr) return 0; 575 | *ptr++='{'; if (fmt) *ptr++='\n'; *ptr=0; p->offset+=len; 576 | child=item->child;depth++; 577 | while (child) 578 | { 579 | if (fmt) 580 | { 581 | ptr=ensure(p,depth); if (!ptr) return 0; 582 | for (j=0;joffset+=depth; 584 | } 585 | print_string_ptr(child->string,p); 586 | p->offset=update(p); 587 | 588 | len=fmt?2:1; 589 | ptr=ensure(p,len); if (!ptr) return 0; 590 | *ptr++=':';if (fmt) *ptr++='\t'; 591 | p->offset+=len; 592 | 593 | print_value(child,depth,fmt,p); 594 | p->offset=update(p); 595 | 596 | len=(fmt?1:0)+(child->next?1:0); 597 | ptr=ensure(p,len+1); if (!ptr) return 0; 598 | if (child->next) *ptr++=','; 599 | if (fmt) *ptr++='\n';*ptr=0; 600 | p->offset+=len; 601 | child=child->next; 602 | } 603 | ptr=ensure(p,fmt?(depth+1):2); if (!ptr) return 0; 604 | if (fmt) for (i=0;ibuffer)+i; 607 | } 608 | else 609 | { 610 | /* Allocate space for the names and the objects */ 611 | entries=(char**)cJSON_malloc(numentries*sizeof(char*)); 612 | if (!entries) return 0; 613 | names=(char**)cJSON_malloc(numentries*sizeof(char*)); 614 | if (!names) {cJSON_free(entries);return 0;} 615 | memset(entries,0,sizeof(char*)*numentries); 616 | memset(names,0,sizeof(char*)*numentries); 617 | 618 | /* Collect all the results into our arrays: */ 619 | child=item->child;depth++;if (fmt) len+=depth; 620 | while (child) 621 | { 622 | names[i]=str=print_string_ptr(child->string,0); 623 | entries[i++]=ret=print_value(child,depth,fmt,0); 624 | if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1; 625 | child=child->next; 626 | } 627 | 628 | /* Try to allocate the output string */ 629 | if (!fail) out=(char*)cJSON_malloc(len); 630 | if (!out) fail=1; 631 | 632 | /* Handle failure */ 633 | if (fail) 634 | { 635 | for (i=0;ichild;int i=0;while(c)i++,c=c->next;return i;} 662 | cJSON *cJSON_GetArrayItem(cJSON *array,int item) {cJSON *c=array->child; while (c && item>0) item--,c=c->next; return c;} 663 | cJSON *cJSON_GetObjectItem(cJSON *object,const char *string) {cJSON *c=object->child; while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;} 664 | 665 | /* Utility for array list handling. */ 666 | static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;} 667 | /* Utility for handling references. */ 668 | 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;} 669 | 670 | /* Add item to array/object. */ 671 | 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);}} 672 | 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);} 673 | void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item) {if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);} 674 | void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) {cJSON_AddItemToArray(array,create_reference(item));} 675 | void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item) {cJSON_AddItemToObject(object,string,create_reference(item));} 676 | 677 | cJSON *cJSON_DetachItemFromArray(cJSON *array,int which) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0; 678 | 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;} 679 | void cJSON_DeleteItemFromArray(cJSON *array,int which) {cJSON_Delete(cJSON_DetachItemFromArray(array,which));} 680 | 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;} 681 | void cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));} 682 | 683 | /* Replace array/object items with new ones. */ 684 | void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;} 685 | newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;} 686 | void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem) {cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return; 687 | newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem; 688 | if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);} 689 | 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);}} 690 | 691 | /* Create basic types: */ 692 | cJSON *cJSON_CreateNull(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;} 693 | cJSON *cJSON_CreateTrue(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;} 694 | cJSON *cJSON_CreateFalse(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;} 695 | cJSON *cJSON_CreateBool(int b) {cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;} 696 | 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;} 697 | cJSON *cJSON_CreateString(const char *string) {cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);}return item;} 698 | cJSON *cJSON_CreateArray(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;} 699 | cJSON *cJSON_CreateObject(void) {cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;} 700 | 701 | /* Create Arrays: */ 702 | 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;} 703 | 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;} 704 | 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;} 705 | 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;} 706 | 707 | /* Duplication */ 708 | cJSON *cJSON_Duplicate(cJSON *item,int recurse) 709 | { 710 | cJSON *newitem,*cptr,*nptr=0,*newchild; 711 | /* Bail on bad ptr */ 712 | if (!item) return 0; 713 | /* Create new item */ 714 | newitem=cJSON_New_Item(); 715 | if (!newitem) return 0; 716 | /* Copy over all vars */ 717 | newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble; 718 | if (item->valuestring) {newitem->valuestring=cJSON_strdup(item->valuestring); if (!newitem->valuestring) {cJSON_Delete(newitem);return 0;}} 719 | if (item->string) {newitem->string=cJSON_strdup(item->string); if (!newitem->string) {cJSON_Delete(newitem);return 0;}} 720 | /* If non-recursive, then we're done! */ 721 | if (!recurse) return newitem; 722 | /* Walk the ->next chain for the child. */ 723 | cptr=item->child; 724 | while (cptr) 725 | { 726 | newchild=cJSON_Duplicate(cptr,1); /* Duplicate (with recurse) each item in the ->next chain */ 727 | if (!newchild) {cJSON_Delete(newitem);return 0;} 728 | if (nptr) {nptr->next=newchild,newchild->prev=nptr;nptr=newchild;} /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 729 | else {newitem->child=newchild;nptr=newchild;} /* Set newitem->child and move to it */ 730 | cptr=cptr->next; 731 | } 732 | return newitem; 733 | } 734 | 735 | void cJSON_Minify(char *json) 736 | { 737 | char *into=json; 738 | while (*json) 739 | { 740 | if (*json==' ') json++; 741 | else if (*json=='\t') json++; /* Whitespace characters. */ 742 | else if (*json=='\r') json++; 743 | else if (*json=='\n') json++; 744 | else if (*json=='/' && json[1]=='/') while (*json && *json!='\n') json++; /* double-slash comments, to end of line. */ 745 | else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;} /* multiline comments. */ 746 | else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */ 747 | else *into++=*json++; /* All other characters. */ 748 | } 749 | *into=0; /* and null-terminate. */ 750 | } 751 | -------------------------------------------------------------------------------- /cJSON_Parse/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 | #define cJSON_StringIsConst 512 42 | 43 | /* The cJSON structure: */ 44 | typedef struct cJSON { 45 | struct cJSON *next,*prev; /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 46 | struct cJSON *child; /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 47 | 48 | int type; /* The type of the item, as above. */ 49 | 50 | char *valuestring; /* The item's string, if type==cJSON_String */ 51 | int valueint; /* The item's number, if type==cJSON_Number */ 52 | double valuedouble; /* The item's number, if type==cJSON_Number */ 53 | 54 | char *string; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 55 | } cJSON; 56 | 57 | typedef struct cJSON_Hooks { 58 | void *(*malloc_fn)(size_t sz); 59 | void (*free_fn)(void *ptr); 60 | } cJSON_Hooks; 61 | 62 | /* Supply malloc, realloc and free functions to cJSON */ 63 | extern void cJSON_InitHooks(cJSON_Hooks* hooks); 64 | 65 | 66 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ 67 | extern cJSON *cJSON_Parse(const char *value); 68 | /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ 69 | extern char *cJSON_Print(cJSON *item); 70 | /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ 71 | extern char *cJSON_PrintUnformatted(cJSON *item); 72 | /* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ 73 | extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt); 74 | /* Delete a cJSON entity and all subentities. */ 75 | extern void cJSON_Delete(cJSON *c); 76 | 77 | /* Returns the number of items in an array (or object). */ 78 | extern int cJSON_GetArraySize(cJSON *array); 79 | /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ 80 | extern cJSON *cJSON_GetArrayItem(cJSON *array,int item); 81 | /* Get item "string" from object. Case insensitive. */ 82 | extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string); 83 | 84 | /* 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. */ 85 | extern const char *cJSON_GetErrorPtr(void); 86 | 87 | /* These calls create a cJSON item of the appropriate type. */ 88 | extern cJSON *cJSON_CreateNull(void); 89 | extern cJSON *cJSON_CreateTrue(void); 90 | extern cJSON *cJSON_CreateFalse(void); 91 | extern cJSON *cJSON_CreateBool(int b); 92 | extern cJSON *cJSON_CreateNumber(double num); 93 | extern cJSON *cJSON_CreateString(const char *string); 94 | extern cJSON *cJSON_CreateArray(void); 95 | extern cJSON *cJSON_CreateObject(void); 96 | 97 | /* These utilities create an Array of count items. */ 98 | extern cJSON *cJSON_CreateIntArray(const int *numbers,int count); 99 | extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count); 100 | extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count); 101 | extern cJSON *cJSON_CreateStringArray(const char **strings,int count); 102 | 103 | /* Append item to the specified array/object. */ 104 | extern void cJSON_AddItemToArray(cJSON *array, cJSON *item); 105 | extern void cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item); 106 | extern void cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item); /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */ 107 | /* 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. */ 108 | extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 109 | extern void cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item); 110 | 111 | /* Remove/Detatch items from Arrays/Objects. */ 112 | extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which); 113 | extern void cJSON_DeleteItemFromArray(cJSON *array,int which); 114 | extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string); 115 | extern void cJSON_DeleteItemFromObject(cJSON *object,const char *string); 116 | 117 | /* Update array items. */ 118 | extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem); /* Shifts pre-existing items to the right. */ 119 | extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem); 120 | extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 121 | 122 | /* Duplicate a cJSON item */ 123 | extern cJSON *cJSON_Duplicate(cJSON *item,int recurse); 124 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 125 | need to be released. With recurse!=0, it will duplicate any children connected to the item. 126 | The item->next and ->prev pointers are always zero on return from Duplicate. */ 127 | 128 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 129 | extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated); 130 | 131 | extern void cJSON_Minify(char *json); 132 | 133 | /* Macros for creating things quickly. */ 134 | #define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) 135 | #define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) 136 | #define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) 137 | #define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) 138 | #define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) 139 | #define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) 140 | 141 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 142 | #define cJSON_SetIntValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 143 | #define cJSON_SetNumberValue(object,val) ((object)?(object)->valueint=(object)->valuedouble=(val):(val)) 144 | 145 | #ifdef __cplusplus 146 | } 147 | #endif 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /cJSON_Parse/cJSON_Parse.bmarks: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /cJSON_Parse/cJSON_Parse.cbp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 43 | 44 | -------------------------------------------------------------------------------- /cJSON_Parse/cJSON_Parse.depend: -------------------------------------------------------------------------------- 1 | # depslib dependency file v1.0 2 | 1423824890 source:e:\git_project\json_lib_demo\cjson_parse\cjson.c 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | "cJSON.h" 11 | 12 | 1423824802 e:\git_project\json_lib_demo\cjson_parse\cjson.h 13 | 14 | 1563692701 source:e:\git_project\json_lib_demo\cjson_parse\main.c 15 | "stdio.h" 16 | 17 | 1563692728 source:e:\git_project\json_lib_demo\cjson_parse\parse.c 18 | "cJSON.h" 19 | "json_str.h" 20 | "stdio.h" 21 | 22 | 1563604345 e:\git_project\json_lib_demo\cjson_parse\parse.h 23 | 24 | 25 | 26 | 1563692526 e:\git_project\json_lib_demo\cjson_parse\json_str.h 27 | 28 | 1423824890 source:e:\git_project\json_lib_demo\cjson_demo\cjson_parse\cjson.c 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | "cJSON.h" 37 | 38 | 1423824802 e:\git_project\json_lib_demo\cjson_demo\cjson_parse\cjson.h 39 | 40 | 1563876879 source:e:\git_project\json_lib_demo\cjson_demo\cjson_parse\main.c 41 | "stdio.h" 42 | 43 | 1563880188 source:e:\git_project\json_lib_demo\cjson_demo\cjson_parse\parse.c 44 | "cJSON.h" 45 | "json_str.h" 46 | "stdio.h" 47 | "stdlib.h" 48 | 49 | 1563692526 e:\git_project\json_lib_demo\cjson_demo\cjson_parse\json_str.h 50 | 51 | -------------------------------------------------------------------------------- /cJSON_Parse/cJSON_Parse.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /cJSON_Parse/json_str.h: -------------------------------------------------------------------------------- 1 | #ifndef JSON_STR_H 2 | #define JSON_STR_H 3 | 4 | /* json数据解析,示例字符串 */ 5 | 6 | /*和风天气实况数据*/ 7 | char he_now_json[] = "{\"HeWeather6\":[{\"basic\":{\"cid\":\"CN101010700\",\"location\":\"昌平\",\"parent_city\":\"北京\",\"admin_area\":\"北京\",\"cnty\":\"中国\",\"lat\":\"40.21808624\",\"lon\":\"116.23590851\",\"tz\":\"+8.00\"},\"update\":{\"loc\":\"2019-07-20 10:21\",\"utc\":\"2019-07-20 02:21\"},\"status\":\"ok\",\"now\":{\"cloud\":\"96\",\"cond_code\":\"104\",\"cond_txt\":\"阴\",\"fl\":\"28\",\"hum\":\"86\",\"pcpn\":\"0.0\",\"pres\":\"995\",\"tmp\":\"25\",\"vis\":\"4\",\"wind_deg\":\"100\",\"wind_dir\":\"东风\",\"wind_sc\":\"1\",\"wind_spd\":\"4\"}}]}"; 8 | 9 | /*心知天气实况数据*/ 10 | char const seniverse_now_json[] = "{\"results\":[{\"location\":{\"id\":\"WX4FBXXFKE4F\",\"name\":\"北京\",\"country\":\"CN\",\"path\":\"北京,北京,中国\",\"timezone\":\"Asia/Shanghai\",\"timezone_offset\":\"+08:00\"},\"now\":{\"text\":\"晴\",\"code\":\"1\",\"temperature\":\"-7\"},\"last_update\":\"2018-12-06T22:05:00+08:00\"}]}"; 11 | /*心知天气3天预报*/ 12 | char const seniverse_forcast_json[] = "{\"results\":[{\"location\":{\"id\":\"WS10730EM8EV\",\"name\":\"深圳\",\"country\":\"CN\",\"path\":\"深圳,深圳,广东,中国\",\"timezone\":\"Asia/Shanghai\",\"timezone_offset\":\"+08:00\"},\"daily\":[{\"date\":\"2018-12-06\",\"text_day\":\"阴\",\"code_day\":\"9\",\"text_night\":\"阴\",\"code_night\":\"9\",\"high\":\"25\",\"low\":\"16\",\"precip\":\"\",\"wind_direction\":\"无持续风向\",\"wind_direction_degree\":\"\",\"wind_speed\":\"10\",\"wind_scale\":\"2\"},{\"date\":\"2018-12-07\",\"text_day\":\"阴\",\"code_day\":\"9\",\"text_night\":\"小雨\",\"code_night\":\"13\",\"high\":\"20\",\"low\":\"15\",\"precip\":\"\",\"wind_direction\":\"北\",\"wind_direction_degree\":\"0\",\"wind_speed\":\"15\",\"wind_scale\":\"3\"},{\"date\":\"2018-12-08\",\"text_day\":\"小雨\",\"code_day\":\"13\",\"text_night\":\"小雨\",\"code_night\":\"13\",\"high\":\"17\",\"low\":\"12\",\"precip\":\"\",\"wind_direction\":\"东北\",\"wind_direction_degree\":\"45\",\"wind_speed\":\"15\",\"wind_scale\":\"3\"}],\"last_update\":\"2018-12-06T18:00:00+08:00\"}]}"; 13 | 14 | /*空气质量,AQI,数据接口:http://api.help.bj.cn/apis/aqi/?id=101060101*/ 15 | char const AQI_json[] = "{\"status\": \"0\",\"citye\":\"changchun\",\"city\":\"长春\",\"citycode\":\"101060101\",\"aqi\":\"50\",\"data\": [{\"add\": \"长春\",\"aqi\": \"50\",\"pm25\": \"22\",\"per\": \"优\",\"lv\": \"1\"},{\"add\": \"食品厂\",\"aqi\": \"54\",\"pm25\": \"18\",\"per\": \"良\",\"lv\": \"2\"},{\"add\": \"客车厂\",\"aqi\": \"52\",\"pm25\": \"20\",\"per\": \"良\",\"lv\": \"2\"},{\"add\": \"邮电学院\",\"aqi\": \"35\",\"pm25\": \"24\",\"per\": \"优\",\"lv\": \"1\"},{\"add\": \"劳动公园\",\"aqi\": \"45\",\"pm25\": \"19\",\"per\": \"优\",\"lv\": \"1\"},{\"add\": \"园林处\",\"aqi\": \"45\",\"pm25\": \"21\",\"per\": \"优\",\"lv\": \"1\"},{\"add\": \"净月潭\",\"aqi\": \"46\",\"pm25\": \"30\",\"per\": \"优\",\"lv\": \"1\"},{\"add\": \"甩湾子\",\"aqi\": \"51\",\"pm25\": \"24\",\"per\": \"良\",\"lv\": \"2\"},{\"add\": \"经开区环卫处\",\"aqi\": \"48\",\"pm25\": \"25\",\"per\": \"优\",\"lv\": \"1\"},{\"add\": \"高新区管委会\",\"aqi\": \"51\",\"pm25\": \"16\",\"per\": \"良\",\"lv\": \"2\"},{\"add\": \"岱山公园\",\"aqi\": \"49\",\"pm25\": \"19\",\"per\": \"优\",\"lv\": \"1\"}]}"; 16 | 17 | /*北京时间同步,数据接口:http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json */ 18 | char const bj_time_json[] = "{\"success\":\"1\",\"result\":{\"timestamp\":\"1542456793\",\"datetime_1\":\"2018-11-17 20:13:13\",\"datetime_2\":\"2018年11月17日 20时13分13秒\",\"week_1\":\"6\",\"week_2\":\"星期六\",\"week_3\":\"周六\",\"week_4\":\"Saturday\"}}"; 19 | 20 | char const oil_price_json[] = "{\"status\":\"0\",\"msg\": \"全国各省份汽柴油价格信息\",\"update\": \"2019-07-21\",\"data\": [[\"地区\", \"92号\", \"95号\", \"98号\", \"0号柴油\"],[\"北京\", \"6.78\", \"7.21\", \"8.19\", \"6.45\"],[\"上海\", \"6.74\", \"7.17\", \"7.87\", \"6.39\"],[\"江苏\", \"6.75\", \"7.18\", \"8.06\", \"6.37\"],[\"天津\", \"6.77\", \"7.15\", \"8.07\", \"6.41\"]],\"About\": \"wcc\",\"Home\": \"www.wangchaochao.top\"}"; 21 | 22 | #endif // JSON_STR_H 23 | -------------------------------------------------------------------------------- /cJSON_Parse/main.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" 2 | #include "stdio.h" 3 | 4 | int main() 5 | { 6 | 7 | // Parse_BJTime_Json(); //解析北京时间,键的值是一个JSON对象 8 | // Parse_AQI_Json(); //解析空气质量AQI,数组嵌套对象 9 | // Parse_HeWeather_Now_Json(); //解析和风天气实时数据,一个数组嵌套多个对象 10 | // Parse_Seniverse_Now_Json(); //解析心知天气实时数据,一个数组嵌套多个对象 11 | // Parse_Seniverse_Forecast_Json(); //解析心知预报天气,数组内嵌套一个数组和多个对象 12 | // Parse_Oil_Price_Json(); //解析油价信息,一个数组内嵌套5个数组,每个数组包含5个字符串元素 13 | Parse_File_Json(); 14 | 15 | printf("\n"); 16 | return 0; 17 | 18 | } 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /cJSON_Parse/obj/Release/cJSON.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Parse/obj/Release/cJSON.o -------------------------------------------------------------------------------- /cJSON_Parse/obj/Release/main.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Parse/obj/Release/main.o -------------------------------------------------------------------------------- /cJSON_Parse/obj/Release/parse.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/whik/cJSON_Demo/8914365ce24bbb3d6cea81575870ddae6427f0f1/cJSON_Parse/obj/Release/parse.o -------------------------------------------------------------------------------- /cJSON_Parse/parse.c: -------------------------------------------------------------------------------- 1 | #include "parse.h" //包含示例字符串 2 | #include "cJSON.h" 3 | #include "json_str.h" 4 | #include "stdio.h" 5 | #include "stdlib.h" 6 | 7 | #define LOG(fmt,args...) printf(fmt,##args) 8 | 9 | void Parse_HeWeather_Now_Json(void) 10 | { 11 | cJSON *root; 12 | cJSON *basic, *update, *status, *now; 13 | char *str_tmp; 14 | 15 | root = cJSON_Parse(he_now_json); 16 | if(root) 17 | { 18 | LOG("JSON格式正确\n"); 19 | LOG("JSON数据:\n%s\n", cJSON_Print(root)); 20 | root = cJSON_GetObjectItem(root, "HeWeather6");//获取HeWeather6对应的值 21 | root = cJSON_GetArrayItem(root, 0); 22 | /*basic键,城市的基本信息*/ 23 | LOG("basic键信息:\n"); 24 | basic = cJSON_GetObjectItem(root,"basic"); 25 | str_tmp = cJSON_GetObjectItem(basic, "cid") ->valuestring; 26 | LOG("cid: %s\n",str_tmp); 27 | str_tmp = cJSON_GetObjectItem(basic, "location") ->valuestring; 28 | LOG("location: %s\n",str_tmp); 29 | str_tmp = cJSON_GetObjectItem(basic, "parent_city") ->valuestring; 30 | LOG("parent_city: %s\n",str_tmp); 31 | str_tmp = cJSON_GetObjectItem(basic, "admin_area") ->valuestring; 32 | LOG("admin_area: %s\n",str_tmp); 33 | str_tmp = cJSON_GetObjectItem(basic, "cnty") ->valuestring; 34 | LOG("cnty: %s\n",str_tmp); 35 | 36 | str_tmp = cJSON_GetObjectItem(basic, "lat") ->valuestring; //纬度 37 | LOG("lat: %s\n",str_tmp); 38 | str_tmp = cJSON_GetObjectItem(basic, "lon") ->valuestring; //经度 39 | LOG("lon: %s\n",str_tmp); 40 | str_tmp = cJSON_GetObjectItem(basic, "tz") ->valuestring; //时区 41 | LOG("tz: %s\n\n",str_tmp); 42 | 43 | /*update键,更新时间*/ 44 | LOG("update键信息:\n"); 45 | 46 | update = cJSON_GetObjectItem(root,"update"); 47 | str_tmp = cJSON_GetObjectItem(update, "loc") ->valuestring; //按当地时间 48 | LOG("loc: %s\n",str_tmp); 49 | str_tmp = cJSON_GetObjectItem(update, "utc") ->valuestring; //按UTC时间 50 | LOG("utc: %s\n\n",str_tmp); 51 | 52 | /*status键,解析状态*/ 53 | LOG("status键信息:\n"); 54 | str_tmp = cJSON_GetObjectItem(root,"status")->valuestring; //获取解析状态字符串 55 | LOG("status: %s\n\n",str_tmp); 56 | 57 | /*now键,实时天气*/ 58 | LOG("now键信息:\n"); 59 | now = cJSON_GetObjectItem(root,"now"); 60 | str_tmp = cJSON_GetObjectItem(now, "cloud")->valuestring; 61 | LOG("cloud: %s\n", str_tmp); 62 | str_tmp = cJSON_GetObjectItem(now, "cond_txt")->valuestring; 63 | LOG("cond_txt: %s\n", str_tmp); 64 | str_tmp = cJSON_GetObjectItem(now, "tmp")->valuestring; 65 | LOG("tmp: %s\n", str_tmp); 66 | str_tmp = cJSON_GetObjectItem(now, "wind_dir")->valuestring; 67 | LOG("wind_dir: %s\n", str_tmp); 68 | str_tmp = cJSON_GetObjectItem(now, "wind_sc")->valuestring; // 69 | LOG("wind_sc: %s\n\n", str_tmp); 70 | } 71 | else 72 | { 73 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 74 | } 75 | cJSON_Delete(root); //调用cJSON_Print时才需要 76 | 77 | } 78 | 79 | void Parse_Seniverse_Now_Json(void) 80 | { 81 | cJSON *root; 82 | cJSON *location, *now, *last_update; 83 | char *str_tmp; 84 | 85 | root = cJSON_Parse(seniverse_now_json); 86 | if(root) 87 | { 88 | LOG("JSON格式正确\n"); 89 | LOG("JSON字符:%s\n", cJSON_Print(root)); 90 | root = cJSON_GetObjectItem(root, "results"); 91 | root = cJSON_GetArrayItem(root, 0); 92 | 93 | /*location键,城市信息*/ 94 | LOG("location键信息:\n"); 95 | location = cJSON_GetObjectItem(root, "location"); 96 | str_tmp = cJSON_GetObjectItem(location, "id")->valuestring; 97 | LOG("id: %s\n", str_tmp); 98 | str_tmp = cJSON_GetObjectItem(location, "name")->valuestring; 99 | LOG("name: %s\n", str_tmp); 100 | str_tmp = cJSON_GetObjectItem(location, "country")->valuestring; 101 | LOG("country: %s\n", str_tmp); 102 | str_tmp = cJSON_GetObjectItem(location, "path")->valuestring; 103 | LOG("path: %s\n", str_tmp); 104 | str_tmp = cJSON_GetObjectItem(location, "timezone")->valuestring; 105 | LOG("timezone: %s\n", str_tmp); 106 | str_tmp = cJSON_GetObjectItem(location, "timezone_offset")->valuestring; 107 | LOG("timezone_offset: %s\n\n", str_tmp); 108 | 109 | /*now键,实时天气*/ 110 | LOG("now键信息:\n"); 111 | now = cJSON_GetObjectItem(root, "now"); 112 | str_tmp = cJSON_GetObjectItem(now, "text")->valuestring; 113 | LOG("text: %s\n", str_tmp); 114 | str_tmp = cJSON_GetObjectItem(now, "code")->valuestring; 115 | LOG("code: %s\n", str_tmp); 116 | str_tmp = cJSON_GetObjectItem(now, "temperature")->valuestring; 117 | LOG("temperature: %s\n", str_tmp); 118 | /*last_update键,更新时间*/ 119 | str_tmp = cJSON_GetObjectItem(root, "last_update")->valuestring; 120 | LOG("\nlast_update: %s\n", str_tmp); 121 | } 122 | else 123 | { 124 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 125 | } 126 | 127 | cJSON_Delete(root); //调用cJSON_Print时才需要 128 | } 129 | 130 | void Parse_Seniverse_Forecast_Json(void) 131 | { 132 | cJSON *root; 133 | cJSON *location, *daily, *day; 134 | char *str_tmp; 135 | int num = 0; 136 | 137 | root = cJSON_Parse(seniverse_forcast_json); 138 | if(root) 139 | { 140 | LOG("JSON格式正确\n"); 141 | LOG("JSON数据:%s \n", cJSON_Print(root)); 142 | /*results键*/ 143 | root = cJSON_GetObjectItem(root, "results"); 144 | root = cJSON_GetArrayItem(root, 0); 145 | 146 | /*location键,城市信息*/ 147 | LOG("location键信息: \n"); 148 | location = cJSON_GetObjectItem(root, "location"); 149 | str_tmp = cJSON_GetObjectItem(location, "id")->valuestring; 150 | LOG("id: %s\n", str_tmp); 151 | str_tmp = cJSON_GetObjectItem(location, "name")->valuestring; 152 | LOG("name: %s\n", str_tmp); 153 | str_tmp = cJSON_GetObjectItem(location, "country")->valuestring; 154 | LOG("country: %s\n", str_tmp); 155 | str_tmp = cJSON_GetObjectItem(location, "path")->valuestring; 156 | LOG("path: %s\n\n", str_tmp); 157 | 158 | /*daily键,预报信息*/ 159 | LOG("daily键信息: \n"); 160 | daily = cJSON_GetObjectItem(root, "daily"); 161 | //预报3天的天气 162 | for(num = 0; num <= 2; num++) 163 | { 164 | day = cJSON_GetArrayItem(daily, num); //当日天气,第0个元素 165 | str_tmp = cJSON_GetObjectItem(day, "date")->valuestring; //白天天气 166 | LOG("date: %s\n", str_tmp); 167 | str_tmp = cJSON_GetObjectItem(day, "text_day")->valuestring; //白天天气 168 | LOG("text_day: %s\n", str_tmp); 169 | str_tmp = cJSON_GetObjectItem(day, "low")->valuestring; //白天天气 170 | LOG("low: %s\n", str_tmp); 171 | str_tmp = cJSON_GetObjectItem(day, "high")->valuestring; //白天天气 172 | LOG("high: %s\n", str_tmp); 173 | str_tmp = cJSON_GetObjectItem(day, "wind_direction")->valuestring; //白天天气 174 | LOG("wind_direction: %s\n", str_tmp); 175 | str_tmp = cJSON_GetObjectItem(day, "wind_scale")->valuestring; //白天天气 176 | LOG("wind_scale: %s\n\n", str_tmp); 177 | } 178 | } 179 | else 180 | { 181 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 182 | } 183 | cJSON_Delete(root); 184 | } 185 | 186 | void Parse_AQI_Json(void) 187 | { 188 | cJSON *root, *data; 189 | char *str_tmp; 190 | 191 | root = cJSON_Parse(AQI_json); 192 | if(root) 193 | { 194 | LOG("JSON格式正确"); 195 | LOG("JSON字符串: \n%s\n", cJSON_Print(root)); 196 | str_tmp = cJSON_GetObjectItem(root, "city")->valuestring; 197 | LOG("city: %s \n", str_tmp); 198 | str_tmp = cJSON_GetObjectItem(root, "aqi")->valuestring; 199 | LOG("aqi: %s \n", str_tmp); 200 | str_tmp = cJSON_GetObjectItem(root, "citycode")->valuestring; 201 | LOG("citycode: %s\n\n", str_tmp); 202 | 203 | data = cJSON_GetObjectItem(root, "data"); 204 | data = cJSON_GetArrayItem(data, 3); //邮电学院 205 | str_tmp = cJSON_GetObjectItem(data, "add")->valuestring; 206 | LOG("add: %s \n", str_tmp); 207 | str_tmp = cJSON_GetObjectItem(data, "aqi")->valuestring; 208 | LOG("aqi: %s \n", str_tmp); 209 | str_tmp = cJSON_GetObjectItem(data, "pm25")->valuestring; 210 | LOG("pm25: %s \n", str_tmp); 211 | str_tmp = cJSON_GetObjectItem(data, "per")->valuestring; 212 | LOG("per: %s \n", str_tmp); 213 | str_tmp = cJSON_GetObjectItem(data, "lv")->valuestring; 214 | LOG("lv: %s \n", str_tmp); 215 | } 216 | else 217 | { 218 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 219 | } 220 | cJSON_Delete(root); 221 | } 222 | //解析 223 | void Parse_BJTime_Json(void) 224 | { 225 | cJSON *root, *result; 226 | char *str_tmp; 227 | 228 | root = cJSON_Parse(bj_time_json); 229 | if(root) 230 | { 231 | LOG("JSON格式正确\n"); 232 | LOG("JSON字符串:\n%s\n", cJSON_Print(root)); 233 | 234 | /*success键,状态信息*/ 235 | str_tmp = cJSON_GetObjectItem(root, "success")->valuestring; 236 | LOG("success: %s\n", str_tmp); 237 | 238 | /*result键,时间信息*/ 239 | result = cJSON_GetObjectItem(root, "result"); 240 | str_tmp = cJSON_GetObjectItem(result, "timestamp")->valuestring; 241 | LOG("timestatmp: %s\n", str_tmp); 242 | str_tmp = cJSON_GetObjectItem(result, "datetime_1")->valuestring; 243 | LOG("datetime_1: %s\n", str_tmp); 244 | str_tmp = cJSON_GetObjectItem(result, "datetime_2")->valuestring; 245 | LOG("datetime_2: %s\n", str_tmp); 246 | str_tmp = cJSON_GetObjectItem(result, "week_1")->valuestring; 247 | LOG("week_1: %s\n", str_tmp); 248 | str_tmp = cJSON_GetObjectItem(result, "week_2")->valuestring; 249 | LOG("week_2: %s\n", str_tmp); 250 | str_tmp = cJSON_GetObjectItem(result, "week_3")->valuestring; 251 | LOG("week_3: %s\n", str_tmp); 252 | str_tmp = cJSON_GetObjectItem(result, "week_4")->valuestring; 253 | LOG("week_4: %s\n", str_tmp); 254 | } 255 | else 256 | { 257 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 258 | } 259 | cJSON_Delete(root); 260 | } 261 | 262 | //解析数组嵌套的JSON字符串 263 | void Parse_Oil_Price_Json(void) 264 | { 265 | cJSON *root, *data; 266 | cJSON *tmp; 267 | 268 | char *str_tmp; 269 | int dat_idx = 0, city_idx = 0; 270 | 271 | root = cJSON_Parse(oil_price_json); 272 | if(root) 273 | { 274 | LOG("JSON格式正确\n"); 275 | LOG("JSON字符串:\n%s\n", cJSON_Print(root)); 276 | 277 | str_tmp = cJSON_GetObjectItem(root, "status")->valuestring; 278 | LOG("status: %s\n", str_tmp); //数据状态 279 | str_tmp = cJSON_GetObjectItem(root, "msg")->valuestring; 280 | LOG("msg: %s\n", str_tmp); //数据状态 281 | str_tmp = cJSON_GetObjectItem(root, "update")->valuestring; 282 | LOG("update: %s\n\n", str_tmp); //数据状态 283 | 284 | /*data键,城市油价信息*/ 285 | data = cJSON_GetObjectItem(root, "data"); //是一个数组, 包含5个元素,每个元素也是数组,是一个包含了5个元素的数组 286 | 287 | for(dat_idx = 0; dat_idx <= 4; dat_idx++) 288 | { 289 | tmp = cJSON_GetArrayItem(data, dat_idx); //索引信息,地区,92、95、98、0 290 | for(city_idx = 0; city_idx <= 4; city_idx++) 291 | { 292 | str_tmp = cJSON_GetArrayItem(tmp, city_idx)->valuestring; //第一个数组的 第0个元素 293 | LOG("%s ", str_tmp); 294 | } 295 | LOG("\n"); 296 | } 297 | 298 | /* 299 | tmp = cJSON_GetArrayItem(data, 4); //索引信息,地区,92、95、98、0 300 | str_tmp = cJSON_GetArrayItem(tmp, 0)->valuestring; //第一个数组的 第0个元素 301 | LOG("%s ", str_tmp); 302 | str_tmp = cJSON_GetArrayItem(tmp, 1)->valuestring; //第一个数组的 第0个元素 303 | LOG("%s ", str_tmp); 304 | str_tmp = cJSON_GetArrayItem(tmp, 2)->valuestring; //第一个数组的 第0个元素 305 | LOG("%s ", str_tmp); 306 | str_tmp = cJSON_GetArrayItem(tmp, 3)->valuestring; //第一个数组的 第0个元素 307 | LOG("%s ", str_tmp); 308 | str_tmp = cJSON_GetArrayItem(tmp, 4)->valuestring; //第一个数组的 第0个元素 309 | LOG("%s ", str_tmp); 310 | */ 311 | str_tmp = cJSON_GetObjectItem(root, "About")->valuestring; 312 | LOG("\nAbout: %s\n", str_tmp); //数据状态 313 | str_tmp = cJSON_GetObjectItem(root, "Home")->valuestring; 314 | LOG("Home: %s\n", str_tmp); //数据状态 315 | } 316 | else 317 | { 318 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 319 | } 320 | cJSON_Delete(root); 321 | } 322 | 323 | void Parse_File_Json(void) 324 | { 325 | 326 | cJSON *root; 327 | cJSON *location, *daily, *day; 328 | char *str_tmp; 329 | int num = 0; 330 | char *filename = "weather.json"; 331 | 332 | root = cJSON_Parse(seniverse_forcast_json); 333 | if(root) 334 | { 335 | LOG("JSON格式正确\n"); 336 | // LOG("JSON数据:%s \n", cJSON_Print(root)); 337 | /*results键*/ 338 | root = cJSON_GetObjectItem(root, "results"); 339 | root = cJSON_GetArrayItem(root, 0); 340 | 341 | /*location键,城市信息*/ 342 | LOG("location键信息: \n"); 343 | location = cJSON_GetObjectItem(root, "location"); 344 | str_tmp = cJSON_GetObjectItem(location, "id")->valuestring; 345 | LOG("id: %s\n", str_tmp); 346 | str_tmp = cJSON_GetObjectItem(location, "name")->valuestring; 347 | LOG("name: %s\n", str_tmp); 348 | str_tmp = cJSON_GetObjectItem(location, "country")->valuestring; 349 | LOG("country: %s\n", str_tmp); 350 | str_tmp = cJSON_GetObjectItem(location, "path")->valuestring; 351 | LOG("path: %s\n\n", str_tmp); 352 | 353 | /*daily键,预报信息*/ 354 | LOG("daily键信息: \n"); 355 | daily = cJSON_GetObjectItem(root, "daily"); 356 | //预报3天的天气 357 | for(num = 0; num <= 2; num++) 358 | { 359 | day = cJSON_GetArrayItem(daily, num); //当日天气,第0个元素 360 | str_tmp = cJSON_GetObjectItem(day, "date")->valuestring; //白天天气 361 | LOG("date: %s\n", str_tmp); 362 | str_tmp = cJSON_GetObjectItem(day, "text_day")->valuestring; //白天天气 363 | LOG("text_day: %s\n", str_tmp); 364 | str_tmp = cJSON_GetObjectItem(day, "low")->valuestring; //白天天气 365 | LOG("low: %s\n", str_tmp); 366 | str_tmp = cJSON_GetObjectItem(day, "high")->valuestring; //白天天气 367 | LOG("high: %s\n", str_tmp); 368 | str_tmp = cJSON_GetObjectItem(day, "wind_direction")->valuestring; //白天天气 369 | LOG("wind_direction: %s\n", str_tmp); 370 | str_tmp = cJSON_GetObjectItem(day, "wind_scale")->valuestring; //白天天气 371 | LOG("wind_scale: %s\n\n", str_tmp); 372 | } 373 | } 374 | else 375 | { 376 | LOG("Error before:\n[%s]\n",cJSON_GetErrorPtr()); 377 | } 378 | // cJSON_Delete(root); 379 | } 380 | 381 | int get_file_line_number(char *filename) 382 | { 383 | FILE *fp; 384 | char flag; 385 | int line_cnt = 1; 386 | 387 | if((fp = fopen(filename,"r")) == NULL) //文件打开失败 388 | return -1; 389 | while(!feof(fp)) //获取文件行数 390 | { 391 | flag = fgetc(fp); 392 | if(flag == '\n') 393 | line_cnt++; //172行 394 | } 395 | // LOG("%d \n", line_cnt); //输出最大行数 396 | if(fclose(fp) != 0) //文件关闭失败 397 | return -1; 398 | else 399 | return line_cnt; 400 | } 401 | 402 | //读取文件内容 403 | char* textFileRead(char* filename) 404 | { 405 | FILE *fp=NULL; 406 | int flen=0; 407 | char *p; 408 | if ((fp=fopen(filename,"rb"))==NULL) 409 | { 410 | // printf("\nfile open error\n"); 411 | return 0; 412 | } 413 | fseek(fp,0L,SEEK_END); //定位到文件末尾 414 | flen=ftell(fp); //得到文件大小 415 | p=(char*)malloc(flen+1); //根据文件大小动态分配内存空间 416 | if (p==NULL) 417 | { 418 | fclose(fp); 419 | return 0; 420 | } 421 | fseek(fp,0L,SEEK_SET); //定义到文件头 422 | fread(p,flen,1,fp); //一次性读取全部文件内容 423 | p[flen]='\0'; //字符串结束标志 424 | // printf("%s\n",p); 425 | fclose(fp); 426 | // free(p); 427 | return p; 428 | } 429 | 430 | -------------------------------------------------------------------------------- /cJSON_Parse/parse.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSE_H 2 | #define PARSE_H 3 | 4 | #include 5 | #include 6 | 7 | void Parse_HeWeather_Now_Json(void); 8 | void Parse_Seniverse_Now_Json(void); 9 | void Parse_Seniverse_Forecast_Json(void); 10 | void Parse_AQI_Json(void); 11 | void Parse_BJTime_Json(void); 12 | void Parse_Oil_Price_Json(void); 13 | void Parse_File_Json(void); 14 | char* textFileRead(char* filename); 15 | int get_file_line_number(char *filename); 16 | 17 | 18 | #endif // PARSE_H 19 | -------------------------------------------------------------------------------- /cJSON_Parse/weather.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [{ 3 | "location": { 4 | "id": "WS10730EM8EV", 5 | "name": "深圳", 6 | "country": "CN", 7 | "path": "深圳,深圳,广东,中国", 8 | "timezone": "Asia/Shanghai", 9 | "timezone_offset": "+08:00" 10 | }, 11 | "daily": [{ 12 | "date": "2018-12-06", 13 | "text_day": "阴", 14 | "code_day": "9", 15 | "text_night": "阴", 16 | "code_night": "9", 17 | "high": "25", 18 | "low": "16", 19 | "precip": "", 20 | "wind_direction": "无持续风向", 21 | "wind_direction_degree": "", 22 | "wind_speed": "10", 23 | "wind_scale": "2" 24 | }, { 25 | "date": "2018-12-07", 26 | "text_day": "阴", 27 | "code_day": "9", 28 | "text_night": "小雨", 29 | "code_night": "13", 30 | "high": "20", 31 | "low": "15", 32 | "precip": "", 33 | "wind_direction": "北", 34 | "wind_direction_degree": "0", 35 | "wind_speed": "15", 36 | "wind_scale": "3" 37 | }, { 38 | "date": "2018-12-08", 39 | "text_day": "小雨", 40 | "code_day": "13", 41 | "text_night": "小雨", 42 | "code_night": "13", 43 | "high": "17", 44 | "low": "12", 45 | "precip": "", 46 | "wind_direction": "东北", 47 | "wind_direction_degree": "45", 48 | "wind_speed": "15", 49 | "wind_scale": "3" 50 | }], 51 | "last_update": "2018-12-06T18:00:00+08:00" 52 | }] 53 | } --------------------------------------------------------------------------------