├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTORS.md ├── LICENSE ├── README.md ├── README_ZH.md ├── SConscript ├── cJSON.c ├── cJSON.h ├── cJSON_Utils.c ├── cJSON_Utils.h └── cJSON_util.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | 45 | # Kernel Module Compile Results 46 | *.mod* 47 | *.cmd 48 | .tmp_versions/ 49 | modules.order 50 | Module.symvers 51 | Mkfile.old 52 | dkms.conf 53 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 1.7.17 (Dec 26, 2023) 2 | ====== 3 | Fixes: 4 | ------ 5 | * Fix null reference in cJSON_SetValuestring(CVE-2023-50472), see #809 6 | * Fix null reference in cJSON_InsertItemInArray(CVE-2023-50471), see #809 and #810 7 | 8 | 1.7.16 (Jul 5, 2023) 9 | ====== 10 | Features: 11 | ------ 12 | * Add an option for ENABLE_CJSON_VERSION_SO in CMakeLists.txt, see #534 13 | * Add cmake_policy to CMakeLists.txt, see #163 14 | * Add cJSON_SetBoolValue, see #639 15 | * Add meson documentation, see #761 16 | 17 | Fixes: 18 | ------ 19 | * Fix memory leak in merge_patch, see #611 20 | * Fix conflicting target names 'uninstall', see #617 21 | * Bump cmake version to 3.0 and use new version syntax, see #587 22 | * Print int without decimal places, see #630 23 | * Fix 'cjson_utils-static' target not exist, see #625 24 | * Add allocate check for replace_item_in_object, see #675 25 | * Fix a null pointer crash in cJSON_ReplaceItemViaPointer, see #726 26 | 27 | 1.7.15 (Aug 25, 2021) 28 | ====== 29 | Fixes: 30 | ------ 31 | * Fix potential core dumped for strrchr, see [#546](https://github.com/DaveGamble/cJSON/pull/546) 32 | * Fix null pointer crash in cJSON_CreateXxArray, see [#538](https://github.com/DaveGamble/cJSON/pull/538) 33 | * Fix several null pointer problems on allocation failure, see [#526](https://github.com/DaveGamble/cJSON/pull/526) 34 | * Fix a possible dereference of null pointer, see [#519](https://github.com/DaveGamble/cJSON/pull/519) 35 | * Fix windows build failure about defining nan, see [#518](https://github.com/DaveGamble/cJSON/pull/518) 36 | 37 | 1.7.14 (Sep 3, 2020) 38 | ====== 39 | Fixes: 40 | ------ 41 | * optimize the way to find tail node, see [#503](https://github.com/DaveGamble/cJSON/pull/503) 42 | * Fix WError error on macosx because NAN is a float. Thanks @sappo, see [#484](https://github.com/DaveGamble/cJSON/pull/484) 43 | * Fix some bugs in detach and replace. Thanks @miaoerduo, see [#456](https://github.com/DaveGamble/cJSON/pull/456) 44 | 45 | 1.7.13 (Apr 2, 2020) 46 | ====== 47 | Features: 48 | --------- 49 | * add new API of cJSON_ParseWithLength without breaking changes. Thanks @caglarivriz, see [#358](https://github.com/DaveGamble/cJSON/pull/358) 50 | * add new API of cJSON_GetNumberValue. Thanks @Intuition, see[#385](https://github.com/DaveGamble/cJSON/pull/385) 51 | * add uninstall target function for CMake. See [#402](https://github.com/DaveGamble/cJSON/pull/402) 52 | * Improve performance of adding item to array. Thanks @xiaomianhehe, see [#430](https://github.com/DaveGamble/cJSON/pull/430), [#448](https://github.com/DaveGamble/cJSON/pull/448) 53 | * add new API of cJSON_SetValuestring, for changing the valuestring safely. See [#451](https://github.com/DaveGamble/cJSON/pull/451) 54 | * add return value for cJSON_AddItemTo... and cJSON_ReplaceItem... (check if the operation successful). See [#453](https://github.com/DaveGamble/cJSON/pull/453) 55 | 56 | Fixes: 57 | ------ 58 | * Fix clang -Wfloat-equal warning. Thanks @paulmalovanyi, see [#368](https://github.com/DaveGamble/cJSON/pull/368) 59 | * Fix make failed in mac os. See [#405](https://github.com/DaveGamble/cJSON/pull/405) 60 | * Fix memory leak in cJSONUtils_FindPointerFromObjectTo. Thanks @andywolk for reporting, see [#414](https://github.com/DaveGamble/cJSON/issues/414) 61 | * Fix bug in encode_string_as_pointer. Thanks @AIChangJiang for reporting, see [#439](https://github.com/DaveGamble/cJSON/issues/439) 62 | 63 | 1.7.12 (May 17, 2019) 64 | ====== 65 | Fixes: 66 | ------ 67 | * Fix infinite loop in `cJSON_Minify` (potential Denial of Service). Thanks @Alanscut for reporting, see [#354](https://github.com/DaveGamble/cJSON/issues/354) 68 | * Fix link error for Visual Studio. Thanks @tan-wei, see [#352](https://github.com/DaveGamble/cJSON/pull/352). 69 | * Undefine `true` and `false` for `cJSON_Utils` before redefining them. Thanks @raiden00pl, see [#347](https://github.com/DaveGamble/cJSON/pull/347). 70 | 71 | 1.7.11 (Apr 15, 2019) 72 | ====== 73 | Fixes: 74 | ------ 75 | * Fix a bug where cJSON_Minify could overflow it's buffer, both reading and writing. This is a security issue, see [#338](https://github.com/DaveGamble/cJSON/issues/338). Big thanks @bigric3 for reporting. 76 | * Unset `true` and `false` macros before setting them if they exist. See [#339](https://github.com/DaveGamble/cJSON/issues/339), thanks @raiden00pl for reporting 77 | 78 | 1.7.10 (Dec 21, 2018) 79 | ====== 80 | Fixes: 81 | ------ 82 | * Fix package config file for `libcjson`. Thanks @shiluotang for reporting [#321](https://github.com/DaveGamble/cJSON/issues/321) 83 | * Correctly split lists in `cJSON_Utils`'s merge sort. Thanks @andysCaplin for the fix [#322](https://github.com/DaveGamble/cJSON/issues/322) 84 | 85 | 1.7.9 (Dec 16, 2018) 86 | ===== 87 | Fixes: 88 | ------ 89 | * Fix a bug where `cJSON_GetObjectItemCaseSensitive` would pass a nullpointer to `strcmp` when called on an array, see [#315](https://github.com/DaveGamble/cJSON/issues/315). Thanks @yuweol for reporting. 90 | * Fix error in `cJSON_Utils` where the case sensitivity was not respected, see [#317](https://github.com/DaveGamble/cJSON/pull/317). Thanks @yuta-oxo for fixing. 91 | * Fix some warnings detected by the Visual Studio Static Analyzer, see [#307](https://github.com/DaveGamble/cJSON/pull/307). Thanks @bnason-nf 92 | 93 | 1.7.8 (Sep 22, 2018) 94 | ====== 95 | Fixes: 96 | ------ 97 | * cJSON now works with the `__stdcall` calling convention on Windows, see [#295](https://github.com/DaveGamble/cJSON/pull/295), thanks @zhindes for contributing 98 | 99 | 1.7.7 (May 22, 2018) 100 | ===== 101 | Fixes: 102 | ------ 103 | * Fix a memory leak when realloc fails, see [#267](https://github.com/DaveGamble/cJSON/issues/267), thanks @AlfieDeng for reporting 104 | * Fix a typo in the header file, see [#266](https://github.com/DaveGamble/cJSON/pull/266), thanks @zhaozhixu 105 | 106 | 1.7.6 (Apr 13, 2018) 107 | ===== 108 | Fixes: 109 | ------ 110 | * Add `SONAME` to the ELF files built by the Makefile, see [#252](https://github.com/DaveGamble/cJSON/issues/252), thanks @YanhaoMo for reporting 111 | * Add include guards and `extern "C"` to `cJSON_Utils.h`, see [#256](https://github.com/DaveGamble/cJSON/issues/256), thanks @daschfg for reporting 112 | 113 | Other changes: 114 | * Mark the Makefile as deprecated in the README. 115 | 116 | 1.7.5 (Mar 23, 2018) 117 | ===== 118 | Fixes: 119 | ------ 120 | * Fix a bug in the JSON Patch implementation of `cJSON Utils`, see [#251](https://github.com/DaveGamble/cJSON/pull/251), thanks @bobkocisko. 121 | 122 | 1.7.4 (Mar 3, 2018) 123 | ===== 124 | Fixes: 125 | ------ 126 | * Fix potential use after free if the `string` parameter to `cJSON_AddItemToObject` is an alias of the `string` property of the object that is added,see [#248](https://github.com/DaveGamble/cJSON/issues/248). Thanks @hhallen for reporting. 127 | 128 | 1.7.3 (Feb 8, 2018) 129 | ===== 130 | Fixes: 131 | ------ 132 | * Fix potential double free, thanks @projectgus for reporting [#241](https://github.com/DaveGamble/cJSON/issues/241) 133 | 134 | 1.7.2 (Feb 6, 2018) 135 | ===== 136 | Fixes: 137 | ------ 138 | * Fix the use of GNUInstallDirs variables and the pkgconfig file. Thanks @zeerd for reporting [#240](https://github.com/DaveGamble/cJSON/pull/240) 139 | 140 | 1.7.1 (Jan 10, 2018) 141 | ===== 142 | Fixes: 143 | ------ 144 | * Fixed an Off-By-One error that could lead to an out of bounds write. Thanks @liuyunbin for reporting [#230](https://github.com/DaveGamble/cJSON/issues/230) 145 | * Fixed two errors with buffered printing. Thanks @liuyunbin for reporting [#230](https://github.com/DaveGamble/cJSON/issues/230) 146 | 147 | 1.7.0 (Dec 31, 2017) 148 | ===== 149 | Features: 150 | --------- 151 | * Large rewrite of the documentation, see [#215](https://github.com/DaveGamble/cJSON/pull/215) 152 | * Added the `cJSON_GetStringValue` function 153 | * Added the `cJSON_CreateStringReference` function 154 | * Added the `cJSON_CreateArrayReference` function 155 | * Added the `cJSON_CreateObjectReference` function 156 | * The `cJSON_Add...ToObject` macros are now functions that return a pointer to the added item, see [#226](https://github.com/DaveGamble/cJSON/pull/226) 157 | 158 | Fixes: 159 | ------ 160 | * Fix a problem with `GNUInstallDirs` in the CMakeLists.txt, thanks @yangfl, see [#210](https://github.com/DaveGamble/cJSON/pull/210) 161 | * Fix linking the tests when building as static library, see [#213](https://github.com/DaveGamble/cJSON/issues/213) 162 | * New overrides for the CMake option `BUILD_SHARED_LIBS`, see [#207](https://github.com/DaveGamble/cJSON/issues/207) 163 | 164 | Other Changes: 165 | -------------- 166 | * Readme: Explain how to include cJSON, see [#211](https://github.com/DaveGamble/cJSON/pull/211) 167 | * Removed some trailing spaces in the code, thanks @yangfl, see [#212](https://github.com/DaveGamble/cJSON/pull/212) 168 | * Updated [Unity](https://github.com/ThrowTheSwitch/Unity) and [json-patch-tests](https://github.com/json-patch/json-patch-tests) 169 | 170 | 1.6.0 (Oct 9, 2017) 171 | ===== 172 | Features: 173 | --------- 174 | * You can now build cJSON as both shared and static library at once with CMake using `-DBUILD_SHARED_AND_STATIC_LIBS=On`, see [#178](https://github.com/DaveGamble/cJSON/issues/178) 175 | * UTF-8 byte order marks are now ignored, see [#184](https://github.com/DaveGamble/cJSON/issues/184) 176 | * Locales can now be disabled with the option `-DENABLE_LOCALES=Off`, see [#202](https://github.com/DaveGamble/cJSON/issues/202), thanks @Casperinous 177 | * Better support for MSVC and Visual Studio 178 | 179 | Other Changes: 180 | -------------- 181 | * Add the new warnings `-Wswitch-enum`, `-Wused-but-makred-unused`, `-Wmissing-variable-declarations`, `-Wunused-macro` 182 | * More number printing tests. 183 | * Continuous integration testing with AppVeyor (semi automatic at this point), thanks @simon-p-r 184 | 185 | 1.5.9 (Sep 8, 2017) 186 | ===== 187 | Fixes: 188 | ------ 189 | * Set the global error pointer even if `return_parse_end` is passed to `cJSON_ParseWithOpts`, see [#200](https://github.com/DaveGamble/cJSON/pull/200), thanks @rmallins 190 | 191 | 1.5.8 (Aug 21, 2017) 192 | ===== 193 | Fixes: 194 | ------ 195 | * Fix `make test` in the Makefile, thanks @YanhaoMo for reporting this [#195](https://github.com/DaveGamble/cJSON/issues/195) 196 | 197 | 1.5.7 (Jul 13, 2017) 198 | ===== 199 | Fixes: 200 | ------ 201 | * Fix a bug where realloc failing would return a pointer to an invalid memory address. This is a security issue as it could potentially be used by an attacker to write to arbitrary memory addresses, see [#189](https://github.com/DaveGamble/cJSON/issues/189), fixed in [954d61e](https://github.com/DaveGamble/cJSON/commit/954d61e5e7cb9dc6c480fc28ac1cdceca07dd5bd), big thanks @timothyjohncarney for reporting this issue 202 | * Fix a spelling mistake in the AFL fuzzer dictionary, see [#185](https://github.com/DaveGamble/cJSON/pull/185), thanks @jwilk 203 | 204 | 1.5.6 (Jun 28, 2017) 205 | ===== 206 | Fixes: 207 | ------ 208 | * Make cJSON a lot more tolerant about passing NULL pointers to its functions, it should now fail safely instead of dereferencing the pointer, see [#183](https://github.com/DaveGamble/cJSON/pull/183). Thanks @msichal for reporting [#182](https://github.com/DaveGamble/cJSON/issues/182) 209 | 210 | 1.5.5 (Jun 15, 2017) 211 | ===== 212 | Fixes: 213 | ------ 214 | * Fix pointers to nested arrays in cJSON_Utils, see [9abe](https://github.com/DaveGamble/cJSON/commit/9abe75e072050f34732a7169740989a082b65134) 215 | * Fix an error with case sensitivity handling in cJSON_Utils, see [b9cc911](https://github.com/DaveGamble/cJSON/commit/b9cc911831b0b3e1bb72f142389428e59f882b38) 216 | * Fix cJSON_Compare for arrays that are prefixes of the other and objects that are a subset of the other, see [03ba72f](https://github.com/DaveGamble/cJSON/commit/03ba72faec115160d1f3aea5582d9b6af5d3e473) and [#180](https://github.com/DaveGamble/cJSON/issues/180), thanks @zhengqb for reporting 217 | 218 | 1.5.4 (Jun 5, 2017) 219 | ====== 220 | Fixes: 221 | ------ 222 | * Fix build with GCC 7.1.1 and optimization level `-O2`, see [bfbd8fe](https://github.com/DaveGamble/cJSON/commit/bfbd8fe0d85f1dd21e508748fc10fc4c27cc51be) 223 | 224 | Other Changes: 225 | -------------- 226 | * Update [Unity](https://github.com/ThrowTheSwitch/Unity) to 3b69beaa58efc41bbbef70a32a46893cae02719d 227 | 228 | 1.5.3 (May 23, 2017) 229 | ===== 230 | Fixes: 231 | ------ 232 | * Fix `cJSON_ReplaceItemInObject` not keeping the name of an item, see [#174](https://github.com/DaveGamble/cJSON/issues/174) 233 | 234 | 1.5.2 (May 10, 2017) 235 | ===== 236 | Fixes: 237 | ------ 238 | * Fix a reading buffer overflow in `parse_string`, see [a167d9e](https://github.com/DaveGamble/cJSON/commit/a167d9e381e5c84bc03de4e261757b031c0c690d) 239 | * Fix compiling with -Wcomma, see [186cce3](https://github.com/DaveGamble/cJSON/commit/186cce3ece6ce6dfcb58ac8b2a63f7846c3493ad) 240 | * Remove leftover attribute from tests, see [b537ca7](https://github.com/DaveGamble/cJSON/commit/b537ca70a35680db66f1f5b8b437f7114daa699a) 241 | 242 | 1.5.1 (May 6, 2017) 243 | ===== 244 | Fixes: 245 | ------ 246 | * Add gcc version guard to the Makefile, see [#164](https://github.com/DaveGamble/cJSON/pull/164), thanks @juvasquezg 247 | * Fix incorrect free in `cJSON_Utils` if custom memory allocator is used, see [#166](https://github.com/DaveGamble/cJSON/pull/166), thanks @prefetchnta 248 | 249 | 1.5.0 (May 2, 2017) 250 | ===== 251 | Features: 252 | * cJSON finally prints numbers without losing precision, see [#153](https://github.com/DaveGamble/cJSON/pull/153), thanks @DeboraG 253 | * `cJSON_Compare` recursively checks if two cJSON items contain the same values, see [#148](https://github.com/DaveGamble/cJSON/pull/148) 254 | * Provide case sensitive versions of every function where it matters, see [#158](https://github.com/DaveGamble/cJSON/pull/158) and [#159](https://github.com/DaveGamble/cJSON/pull/159) 255 | * Added `cJSON_ReplaceItemViaPointer` and `cJSON_DetachItemViaPointer` 256 | * Added `cJSON_free` and `cJSON_malloc` that expose the internal configured memory allocators. see [02a05ee](https://github.com/DaveGamble/cJSON/commit/02a05eea4e6ba41811f130b322660bea8918e1a0) 257 | 258 | 259 | Enhancements: 260 | ------------- 261 | * Parse into a buffer, this will allow parsing `\u0000` in the future (not quite yet though) 262 | * General simplifications and readability improvements 263 | * More unit tests 264 | * Update [unity](https://github.com/ThrowTheSwitch/Unity) testing library to 2.4.1 265 | * Add the [json-patch-tests](https://github.com/json-patch/json-patch-tests) test suite to test cJSON_Utils. 266 | * Move all tests from `test_utils.c` to unit tests with unity. 267 | 268 | Fixes: 269 | ------ 270 | * Fix some warnings with the Microsoft compiler, see [#139](https://github.com/DaveGamble/cJSON/pull/139), thanks @PawelWMS 271 | * Fix several bugs in cJSON_Utils, mostly found with [json-patch-tests](https://github.com/json-patch/json-patch-tests) 272 | * Prevent a stack overflow by specifying a maximum nesting depth `CJSON_NESTING_LIMIT` 273 | 274 | Other Changes: 275 | -------------- 276 | * Move generated files in the `library_config` subdirectory. 277 | 278 | 1.4.7 (Apr 19, 2017) 279 | ===== 280 | Fixes: 281 | ------ 282 | * Fix `cJSONUtils_ApplyPatches`, it was completely broken and apparently nobody noticed (or at least reported it), see [075a06f](https://github.com/DaveGamble/cJSON/commit/075a06f40bdc4f836c7dd7cad690d253a57cfc50) 283 | * Fix inconsistent prototype for `cJSON_GetObjectItemCaseSensitive`, see [51d3df6](https://github.com/DaveGamble/cJSON/commit/51d3df6c9f7b56b860c8fb24abe7bab255cd4fa9), thanks @PawelWMS 284 | 285 | 1.4.6 (Apr 9, 2017) 286 | ===== 287 | Fixes: 288 | ------ 289 | * Several corrections in the README 290 | * Making clear that `valueint` should not be written to 291 | * Fix overflow detection in `ensure`, see [2683d4d](https://github.com/DaveGamble/cJSON/commit/2683d4d9873df87c4bdccc523903ddd78d1ad250) 292 | * Fix a potential null pointer dereference in cJSON_Utils, see [795c3ac](https://github.com/DaveGamble/cJSON/commit/795c3acabed25c9672006b2c0f40be8845064827) 293 | * Replace incorrect `sizeof('\0')` with `sizeof("")`, see [84237ff](https://github.com/DaveGamble/cJSON/commit/84237ff48e69825c94261c624eb0376d0c328139) 294 | * Add caveats section to the README, see [50b3c30](https://github.com/DaveGamble/cJSON/commit/50b3c30dfa89830f8f477ce33713500740ac3b79) 295 | * Make cJSON locale independent, see [#146](https://github.com/DaveGamble/cJSON/pull/146), Thanks @peterh for reporting 296 | * Fix compiling without CMake with MSVC, see [#147](https://github.com/DaveGamble/cJSON/pull/147), Thanks @dertuxmalwieder for reporting 297 | 298 | 1.4.5 (Mar 28, 2017) 299 | ===== 300 | Fixes: 301 | ------ 302 | * Fix bug in `cJSON_SetNumberHelper`, thanks @mmkeeper, see [#138](https://github.com/DaveGamble/cJSON/issues/138) and [ef34500](https://github.com/DaveGamble/cJSON/commit/ef34500693e8c4a2849d41a4bd66fd19c9ec46c2) 303 | * Workaround for internal compiler error in GCC 5.4.0 and 6.3.1 on x86 (2f65e80a3471d053fdc3f8aed23d01dd1782a5cb [GCC bugreport](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80097)) 304 | 305 | 1.4.4 (Mar 24, 2017) 306 | ===== 307 | Fixes: 308 | ------ 309 | * Fix a theoretical integer overflow, (not sure if it is possible on actual hardware), see [e58f7ec](https://github.com/DaveGamble/cJSON/commit/e58f7ec027d00b7cdcbf63e518c1b5268b29b3da) 310 | * Fix an off by one error, see [cc84a44](https://github.com/DaveGamble/cJSON/commit/cc84a446be20cc283bafdc4d94c050ba1111ac02), thanks @gatzka 311 | * Double check the offset of the print buffer in `ensure`, see [1934059](https://github.com/DaveGamble/cJSON/commit/1934059554b9a0971e00f79e96900f422cfdd114) 312 | 313 | Improvements: 314 | * Add a note in the header about required buffer size when using `cJSON_PrintPreallocated`, see [4bfb8800](https://github.com/DaveGamble/cJSON/commit/4bfb88009342fb568295a7f6dc4b7fee74fbf022) 315 | 316 | 1.4.3 (Mar 19, 2017) 317 | ===== 318 | Fixes: 319 | ------ 320 | * Fix compilation of the tests on 32 bit PowerPC and potentially other systems, see [4ec6e76](https://github.com/DaveGamble/cJSON/commit/4ec6e76ea2eec16f54b58e8c95b4c734e59481e4) 321 | * Fix compilation with old GCC compilers (4.3+ were tested), see [227d33](https://github.com/DaveGamble/cJSON/commit/227d3398d6b967879761ebe02c1b63dbd6ea6e0d), [466eb8e](https://github.com/DaveGamble/cJSON/commit/466eb8e3f8a65080f2b3ca4a79ab7b72bd539dba), see also [#126](https://github.com/DaveGamble/cJSON/issues/126) 322 | 323 | 1.4.2 (Mar 16, 2017) 324 | ===== 325 | Fixes: 326 | ------ 327 | * Fix minimum required cmake version, see [30e1e7a](https://github.com/DaveGamble/cJSON/commit/30e1e7af7c63db9b55f5a3cda977a6c032f0b132) 328 | * Fix detection of supported compiler flags, see [76e5296](https://github.com/DaveGamble/cJSON/commit/76e5296d0d05ceb3018a9901639e0e171b44a557) 329 | * Run `cJSON_test` and `cJSON_test_utils` along with unity tests, see [c597601](https://github.com/DaveGamble/cJSON/commit/c597601cf151a757dcf800548f18034d4ddfe2cb) 330 | 331 | 1.4.1 (Mar 16, 2017) 332 | ===== 333 | Fixes: 334 | ------ 335 | * Make `print_number` abort with a failure in out of memory situations, see [cf1842](https://github.com/DaveGamble/cJSON/commit/cf1842dc6f64c49451a022308b4415e4d468be0a) 336 | 337 | 1.4.0 (Mar 4, 2017) 338 | ===== 339 | Features 340 | -------- 341 | * Functions to check the type of an item, see [#120](https://github.com/DaveGamble/cJSON/pull/120) 342 | * Use dllexport on windows and fvisibility on Unix systems for public functions, see [#116](https://github.com/DaveGamble/cJSON/pull/116), thanks @mjerris 343 | * Remove trailing zeroes from printed numbers, see [#123](https://github.com/DaveGamble/cJSON/pull/123) 344 | * Expose the internal boolean type `cJSON_bool` in the header, see [2d3520e](https://github.com/DaveGamble/cJSON/commit/2d3520e0b9d0eb870e8886e8a21c571eeddbb310) 345 | 346 | Fixes 347 | * Fix handling of NULL pointers in `cJSON_ArrayForEach`, see [b47d0e3](https://github.com/DaveGamble/cJSON/commit/b47d0e34caaef298edfb7bd09a72cfff21d231ff) 348 | * Make it compile with GCC 7 (fix -Wimplicit-fallthrough warning), see [9d07917](https://github.com/DaveGamble/cJSON/commit/9d07917feb1b613544a7513d19233d4c851ad7ad) 349 | 350 | Other Improvements 351 | * internally use realloc if available ([#110](https://github.com/DaveGamble/cJSON/pull/110)) 352 | * builtin support for fuzzing with [afl](http://lcamtuf.coredump.cx/afl/) ([#111](https://github.com/DaveGamble/cJSON/pull/111)) 353 | * unit tests for the print functions ([#112](https://github.com/DaveGamble/cJSON/pull/112)) 354 | * Always use buffered printing ([#113](https://github.com/DaveGamble/cJSON/pull/113)) 355 | * simplify the print functions ([#114](https://github.com/DaveGamble/cJSON/pull/114)) 356 | * Add the compiler flags `-Wdouble-conversion`, `-Wparentheses` and `-Wcomma` ([#122](https://github.com/DaveGamble/cJSON/pull/122)) 357 | 358 | 1.3.2 (Mar 1, 2017) 359 | ===== 360 | Fixes: 361 | ------ 362 | * Don't build the unity library if testing is disabled, see [#121](https://github.com/DaveGamble/cJSON/pull/121). Thanks @ffontaine 363 | 364 | 1.3.1 (Feb 27, 2017) 365 | ===== 366 | Fixes: 367 | ------ 368 | * Bugfix release that fixes an out of bounds read, see [#118](https://github.com/DaveGamble/cJSON/pull/118). This shouldn't have any security implications. 369 | 370 | 1.3.0 (Feb 17, 2017) 371 | ===== 372 | This release includes a lot of rework in the parser and includes the Cunity unit testing framework, as well as some fixes. I increased the minor version number because there were quite a lot of internal changes. 373 | 374 | Features: 375 | * New type for cJSON structs: `cJSON_Invalid`, see [#108](https://github.com/DaveGamble/cJSON/pull/108) 376 | 377 | Fixes: 378 | ------ 379 | * runtime checks for a lot of potential integer overflows 380 | * fix incorrect return in cJSON_PrintBuffered [cf9d57d](https://github.com/DaveGamble/cJSON/commit/cf9d57d56cac21fc59465b8d26cf29bf6d2a87b3) 381 | * fix several potential issues found by [Coverity](https://scan.coverity.com/projects/cjson) 382 | * fix potentially undefined behavior when assigning big numbers to `valueint` ([41e2837](https://github.com/DaveGamble/cJSON/commit/41e2837df1b1091643aff073f2313f6ff3cc10f4)) 383 | * Numbers exceeding `INT_MAX` or lower than `INT_MIN` will be explicitly assigned to `valueint` as `INT_MAX` and `INT_MIN` respectively (saturation on overflow). 384 | * fix the `cJSON_SetNumberValue` macro ([87f7727](https://github.com/DaveGamble/cJSON/commit/87f77274de6b3af00fb9b9a7f3b900ef382296c2)), this slightly changes the behavior, see commit message 385 | 386 | Introduce unit tests 387 | -------------------- 388 | 389 | * Started writing unit tests with the [Cunity](https://github.com/ThrowTheSwitch/Unity) testing framework. Currently this covers the parser functions. 390 | 391 | Also: 392 | * Support for running the tests with [Valgrind](http://valgrind.org) 393 | * Support for compiling the tests with [AddressSanitizer](https://github.com/google/sanitizers) and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html). 394 | * `travis.yml` file for running unit tests on travis. (not enabled for the repository yet though [#102](https://github.com/DaveGamble/cJSON/issues/102) 395 | 396 | Simplifications 397 | --------------- 398 | 399 | After having unit tests for the parser function in place, I started refactoring the parser functions (as well as others) and making them easier to read and maintain. 400 | * Use `strtod` from the standard library for parsing numbers ([0747669](https://github.com/DaveGamble/cJSON/commit/074766997246481dfc72bfa78f07898a2716473f)) 401 | * Use goto-fail in several parser functions ([#100](https://github.com/DaveGamble/cJSON/pull/100)) 402 | * Rewrite/restructure all of the parsing functions to be easier to understand and have less code paths doing the same as another. ([#109](https://github.com/DaveGamble/cJSON/pull/109)) 403 | * Simplify the buffer allocation strategy to always doubling the needed amount ([9f6fa94](https://github.com/DaveGamble/cJSON/commit/9f6fa94c91a87b71e4c6868dbf2ce431a48517b0)) 404 | * Combined `cJSON_AddItemToObject` and `cJSON_AddItemToObjectCS` to one function ([cf862d](https://github.com/DaveGamble/cJSON/commit/cf862d0fed7f9407e4b046d78d3d8050d2080d12)) 405 | 406 | Other changes 407 | ------------- 408 | * Prevent the usage of incompatible C and header versions via preprocessor directive ([123bb1](https://github.com/DaveGamble/cJSON/commit/123bb1af7bfae41d805337fef4b41045ef6c7d25)) 409 | * Let CMake automatically detect compiler flags 410 | * Add new compiler flags (`-Wundef`, `-Wswitch-default`, `-Wconversion`, `-fstack-protector-strong`) ([#98](https://github.com/DaveGamble/cJSON/pull/98)) 411 | * Change internal sizes from `int` to `size_t` ([ecd5678](https://github.com/DaveGamble/cJSON/commit/ecd5678527a6bc422da694e5be9e9979878fe6a0)) 412 | * Change internal strings from `char*` to `unsigned char*` ([28b9ba4](https://github.com/DaveGamble/cJSON/commit/28b9ba4334e0f7309e867e874a31f395c0ac2474)) 413 | * Add `const` in more places 414 | 415 | 1.2.1 (Jan 31, 2017) 416 | ===== 417 | Fixes: 418 | ------ 419 | * Fixes a potential null pointer dereference in cJSON_Utils, discovered using clang's static analyzer by @bnason-nf, see [#96](https://github.com/DaveGamble/cJSON/issues/96) 420 | 421 | 1.2.0 (Jan 9, 2017) 422 | ===== 423 | Features: 424 | --------- 425 | * Add a new type of cJSON item for raw JSON and support printing it. Thanks @loigu, see [#65](https://github.com/DaveGamble/cJSON/pull/65), [#90](https://github.com/DaveGamble/cJSON/pull/90) 426 | 427 | Fixes: 428 | ------ 429 | * Compiler warning if const is casted away, Thanks @gatzka, see [#83](https://github.com/DaveGamble/cJSON/pull/83) 430 | * Fix compile error with strict-overflow on PowerPC, see [#85](https://github.com/DaveGamble/cJSON/issues/85) 431 | * Fix typo in the README, thanks @MicroJoe, see [#88](https://github.com/DaveGamble/cJSON/pull/88) 432 | * Add compile flag for compatibility with C++ compilers 433 | 434 | 1.1.0 (Dec 6, 2016) 435 | ===== 436 | * Add a function `cJSON_PrintPreallocated` to print to a preallocated buffer, thanks @ChisholmKyle, see [#72](https://github.com/DaveGamble/cJSON/pull/72) 437 | * More compiler warnings when using Clang or GCC, thanks @gatzka, see [#75](https://github.com/DaveGamble/cJSON/pull/75), [#78](https://github.com/DaveGamble/cJSON/pull/78) 438 | * fixed a memory leak in `cJSON_Duplicate`, thanks @alperakcan, see [#81](https://github.com/DaveGamble/cJSON/pull/81) 439 | * fix the `ENABLE_CUSTOM_COMPILER_FLAGS` cmake option 440 | 441 | 1.0.2 (Nov 25, 2016) 442 | ===== 443 | * Rename internal boolean type, see [#71](https://github.com/DaveGamble/cJSON/issues/71). 444 | 445 | 1.0.1 (Nov 20, 2016) 446 | ===== 447 | Small bugfix release. 448 | * Fixes a bug with the use of the cJSON structs type in cJSON_Utils, see [d47339e](https://github.com/DaveGamble/cJSON/commit/d47339e2740360e6e0994527d5e4752007480f3a) 449 | * improve code readability 450 | * initialize all variables 451 | 452 | 1.0.0 (Nov 17, 2016) 453 | ===== 454 | This is the first official versioned release of cJSON. It provides an API version for the shared library and improved Makefile and CMake build files. 455 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | Contributors 2 | ============ 3 | 4 | Original Author: 5 | - [Dave Gamble](https://github.com/DaveGamble) 6 | 7 | Current Maintainer: 8 | - [Max Bruckner](https://github.com/FSMaxB) 9 | - [Alan Wang](https://github.com/Alanscut) 10 | 11 | Contributors: 12 | * [Ajay Bhargav](https://github.com/ajaybhargav) 13 | * [AlexanderVasiljev](https://github.com/AlexanderVasiljev) 14 | * [Alper Akcan](https://github.com/alperakcan) 15 | * [Andrew Tang](https://github.com/singku) 16 | * [Andy](https://github.com/mlh0101) 17 | * [Anton Sergeev](https://github.com/anton-sergeev) 18 | * [Benbuck Nason](https://github.com/bnason-nf) 19 | * [Bernt Johan Damslora](https://github.com/bjda) 20 | * [Bob Kocisko](https://github.com/bobkocisko) 21 | * [Christian Schulze](https://github.com/ChristianSch) 22 | * [Casperinous](https://github.com/Casperinous) 23 | * [ChenYuan](https://github.com/zjuchenyuan) 24 | * [Debora Grosse](https://github.com/DeboraG) 25 | * [dieyushi](https://github.com/dieyushi) 26 | * [Dōngwén Huáng (黄东文)](https://github.com/DongwenHuang) 27 | * [Donough Liu](https://github.com/ldm0) 28 | * [Erez Oxman](https://github.com/erez-o) 29 | * Eswar Yaganti 30 | * [Evan Todd](https://github.com/etodd) 31 | * [Fabrice Fontaine](https://github.com/ffontaine) 32 | * Ian Mobley 33 | * Irwan Djadjadi 34 | * [hopper-vul](https://github.com/hopper-vul) 35 | * [HuKeping](https://github.com/HuKeping) 36 | * [IvanVoid](https://github.com/npi3pak) 37 | * [Jakub Wilk](https://github.com/jwilk) 38 | * [Jiri Zouhar](https://github.com/loigu) 39 | * [Jonathan Fether](https://github.com/jfether) 40 | * [Joshua Arulsamy](https://github.com/jarulsamy) 41 | * [Julian Ste](https://github.com/julian-st) 42 | * [Julián Vásquez](https://github.com/juvasquezg) 43 | * [Junbo Zheng](https://github.com/Junbo-Zheng) 44 | * [Kevin Branigan](https://github.com/kbranigan) 45 | * [Kevin Sapper](https://github.com/sappo) 46 | * [Kyle Chisholm](https://github.com/ChisholmKyle) 47 | * [Linus Wallgren](https://github.com/ecksun) 48 | * [MaxBrandtner](https://github.com/MaxBrandtner) 49 | * [Mateusz Szafoni](https://github.com/raiden00pl) 50 | * Mike Pontillo 51 | * [miaoerduo](https://github.com/miaoerduo) 52 | * [mohawk2](https://github.com/mohawk2) 53 | * [Mike Jerris](https://github.com/mjerris) 54 | * [Mike Robinson](https://github.com/mhrobinson) 55 | * [Moorthy](https://github.com/moorthy-bs) 56 | * [myd7349](https://github.com/myd7349) 57 | * [NancyLi1013](https://github.com/NancyLi1013) 58 | * Paulo Antonio Alvarez 59 | * [Paweł Malowany](https://github.com/PawelMalowany) 60 | * [Pawel Winogrodzki](https://github.com/PawelWMS) 61 | * [prefetchnta](https://github.com/prefetchnta) 62 | * [Rafael Leal Dias](https://github.com/rafaeldias) 63 | * [Randy](https://github.com/randy408) 64 | * [raiden00pl](https://github.com/raiden00pl) 65 | * [Robin Mallinson](https://github.com/rmallins) 66 | * [Rod Vagg](https://github.com/rvagg) 67 | * [Roland Meertens](https://github.com/rmeertens) 68 | * [Romain Porte](https://github.com/MicroJoe) 69 | * [SANJEEV BA](https://github.com/basanjeev) 70 | * [Sang-Heon Jeon](https://github.com/lntuition) 71 | * [Sayan Bandyopadhyay](https://github.com/saynb) 72 | * [Simon Sobisch](https://github.com/GitMensch) 73 | * [Simon Ricaldone](https://github.com/simon-p-r) 74 | * [Stoian Ivanov](https://github.com/sdrsdr) 75 | * [SuperH-0630](https://github.com/SuperH-0630) 76 | * [Square789](https://github.com/Square789) 77 | * [Stephan Gatzka](https://github.com/gatzka) 78 | * [Tony Langhammer](https://github.com/BigBrainAFK) 79 | * [Vemake](https://github.com/vemakereporter) 80 | * [Wei Tan](https://github.com/tan-wei) 81 | * [Weston Schmidt](https://github.com/schmidtw) 82 | * [xiaomianhehe](https://github.com/xiaomianhehe) 83 | * [yangfl](https://github.com/yangfl) 84 | * [yuta-oxo](https://github.com/yuta-oxo) 85 | * [Zach Hindes](https://github.com/zhindes) 86 | * [Zhao Zhixu](https://github.com/zhaozhixu) 87 | * [10km](https://github.com/10km) 88 | 89 | And probably more people on [SourceForge](https://sourceforge.net/p/cjson/bugs/search/?q=status%3Aclosed-rejected+or+status%3Aclosed-out-of-date+or+status%3Awont-fix+or+status%3Aclosed-fixed+or+status%3Aclosed&page=0) 90 | 91 | Also thanks to all the people who reported bugs and suggested new features. 92 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 The packages repositories of RT-Thread. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cJSON for RT-Thread 2 | 3 | [中文页](README_ZH.md) | English 4 | 5 | Ultralightweight JSON parser in ANSI C. 6 | 7 | Offical repository: https://github.com/DaveGamble/cJSON 8 | 9 | Maintenance: [Meco Man](https://github.com/mysterywolf) 10 | 11 | Homepage: https://github.com/RT-Thread-packages/cJSON 12 | 13 | -------------------------------------------------------------------------------- /README_ZH.md: -------------------------------------------------------------------------------- 1 | # cJSON for RT-Thread 2 | 3 | 中文页 | [English](README.md) 4 | 5 | 超轻量级的 C 语言 json 解析库 6 | 7 | 官方仓库:https://github.com/DaveGamble/cJSON 8 | 9 | 10 | 维护:[Meco Man](https://github.com/mysterywolf) 11 | 12 | 主页:https://github.com/RT-Thread-packages/cJSON 13 | -------------------------------------------------------------------------------- /SConscript: -------------------------------------------------------------------------------- 1 | from building import * 2 | 3 | cwd = GetCurrentDir() 4 | src = Glob('*.c') 5 | CPPPATH = [cwd] 6 | 7 | group = DefineGroup('cJSON', src, depend = ['PKG_USING_CJSON'], CPPPATH = CPPPATH) 8 | 9 | Return('group') 10 | -------------------------------------------------------------------------------- /cJSON.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 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 | /* disable warnings about old C89 functions in MSVC */ 27 | #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) 28 | #define _CRT_SECURE_NO_DEPRECATE 29 | #endif 30 | 31 | #ifdef __GNUC__ 32 | #pragma GCC visibility push(default) 33 | #endif 34 | #if defined(_MSC_VER) 35 | #pragma warning (push) 36 | /* disable warning about single line comments in system headers */ 37 | #pragma warning (disable : 4001) 38 | #endif 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | 48 | #ifdef ENABLE_LOCALES 49 | #include 50 | #endif 51 | 52 | #if defined(_MSC_VER) 53 | #pragma warning (pop) 54 | #endif 55 | #ifdef __GNUC__ 56 | #pragma GCC visibility pop 57 | #endif 58 | 59 | #include 60 | #include "cJSON.h" 61 | 62 | /* define our own boolean type */ 63 | #ifdef true 64 | #undef true 65 | #endif 66 | #define true ((cJSON_bool)1) 67 | 68 | #ifdef false 69 | #undef false 70 | #endif 71 | #define false ((cJSON_bool)0) 72 | 73 | /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ 74 | #ifndef isinf 75 | #define isinf(d) (isnan((d - d)) && !isnan(d)) 76 | #endif 77 | #ifndef isnan 78 | #define isnan(d) (d != d) 79 | #endif 80 | 81 | #ifndef NAN 82 | #ifdef _WIN32 83 | #define NAN sqrt(-1.0) 84 | #else 85 | #define NAN 0.0/0.0 86 | #endif 87 | #endif 88 | 89 | typedef struct { 90 | const unsigned char *json; 91 | size_t position; 92 | } error; 93 | static error global_error = { NULL, 0 }; 94 | 95 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) 96 | { 97 | return (const char*) (global_error.json + global_error.position); 98 | } 99 | 100 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) 101 | { 102 | if (!cJSON_IsString(item)) 103 | { 104 | return NULL; 105 | } 106 | 107 | return item->valuestring; 108 | } 109 | 110 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) 111 | { 112 | if (!cJSON_IsNumber(item)) 113 | { 114 | return (double) NAN; 115 | } 116 | 117 | return item->valuedouble; 118 | } 119 | 120 | /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 121 | #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 17) 122 | #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 123 | #endif 124 | 125 | CJSON_PUBLIC(const char*) cJSON_Version(void) 126 | { 127 | static char version[15]; 128 | sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 129 | 130 | return version; 131 | } 132 | 133 | /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ 134 | static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) 135 | { 136 | if ((string1 == NULL) || (string2 == NULL)) 137 | { 138 | return 1; 139 | } 140 | 141 | if (string1 == string2) 142 | { 143 | return 0; 144 | } 145 | 146 | for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 147 | { 148 | if (*string1 == '\0') 149 | { 150 | return 0; 151 | } 152 | } 153 | 154 | return tolower(*string1) - tolower(*string2); 155 | } 156 | 157 | typedef struct internal_hooks 158 | { 159 | void *(CJSON_CDECL *allocate)(size_t size); 160 | void (CJSON_CDECL *deallocate)(void *pointer); 161 | void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); 162 | } internal_hooks; 163 | 164 | #if defined(_MSC_VER) 165 | /* work around MSVC error C2322: '...' address of dllimport '...' is not static */ 166 | static void * CJSON_CDECL internal_malloc(size_t size) 167 | { 168 | return malloc(size); 169 | } 170 | static void CJSON_CDECL internal_free(void *pointer) 171 | { 172 | free(pointer); 173 | } 174 | static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) 175 | { 176 | return realloc(pointer, size); 177 | } 178 | #elif defined(__RTTHREAD__) 179 | #define internal_malloc rt_malloc 180 | #define internal_free rt_free 181 | #define internal_realloc rt_realloc 182 | #else 183 | #define internal_malloc malloc 184 | #define internal_free free 185 | #define internal_realloc realloc 186 | #endif 187 | 188 | /* strlen of character literals resolved at compile time */ 189 | #define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) 190 | 191 | static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; 192 | 193 | static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) 194 | { 195 | size_t length = 0; 196 | unsigned char *copy = NULL; 197 | 198 | if (string == NULL) 199 | { 200 | return NULL; 201 | } 202 | 203 | length = strlen((const char*)string) + sizeof(""); 204 | copy = (unsigned char*)hooks->allocate(length); 205 | if (copy == NULL) 206 | { 207 | return NULL; 208 | } 209 | rt_memcpy(copy, string, length); 210 | 211 | return copy; 212 | } 213 | 214 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) 215 | { 216 | if (hooks == NULL) 217 | { 218 | /* Reset hooks */ 219 | global_hooks.allocate = malloc; 220 | global_hooks.deallocate = free; 221 | global_hooks.reallocate = realloc; 222 | return; 223 | } 224 | 225 | global_hooks.allocate = malloc; 226 | if (hooks->malloc_fn != NULL) 227 | { 228 | global_hooks.allocate = hooks->malloc_fn; 229 | } 230 | 231 | global_hooks.deallocate = free; 232 | if (hooks->free_fn != NULL) 233 | { 234 | global_hooks.deallocate = hooks->free_fn; 235 | } 236 | 237 | /* use realloc only if both free and malloc are used */ 238 | global_hooks.reallocate = NULL; 239 | if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) 240 | { 241 | global_hooks.reallocate = realloc; 242 | } 243 | } 244 | 245 | /* Internal constructor. */ 246 | static cJSON *cJSON_New_Item(const internal_hooks * const hooks) 247 | { 248 | cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); 249 | if (node) 250 | { 251 | rt_memset(node, '\0', sizeof(cJSON)); 252 | } 253 | 254 | return node; 255 | } 256 | 257 | /* Delete a cJSON structure. */ 258 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) 259 | { 260 | cJSON *next = NULL; 261 | while (item != NULL) 262 | { 263 | next = item->next; 264 | if (!(item->type & cJSON_IsReference) && (item->child != NULL)) 265 | { 266 | cJSON_Delete(item->child); 267 | } 268 | if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) 269 | { 270 | global_hooks.deallocate(item->valuestring); 271 | } 272 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 273 | { 274 | global_hooks.deallocate(item->string); 275 | } 276 | global_hooks.deallocate(item); 277 | item = next; 278 | } 279 | } 280 | 281 | /* get the decimal point character of the current locale */ 282 | static unsigned char get_decimal_point(void) 283 | { 284 | #ifdef ENABLE_LOCALES 285 | struct lconv *lconv = localeconv(); 286 | return (unsigned char) lconv->decimal_point[0]; 287 | #else 288 | return '.'; 289 | #endif 290 | } 291 | 292 | typedef struct 293 | { 294 | const unsigned char *content; 295 | size_t length; 296 | size_t offset; 297 | size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ 298 | internal_hooks hooks; 299 | } parse_buffer; 300 | 301 | /* check if the given size is left to read in a given parse buffer (starting with 1) */ 302 | #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) 303 | /* check if the buffer can be accessed at the given index (starting with 0) */ 304 | #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) 305 | #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) 306 | /* get a pointer to the buffer at the position */ 307 | #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) 308 | 309 | /* Parse the input text to generate a number, and populate the result into item. */ 310 | static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) 311 | { 312 | double number = 0; 313 | unsigned char *after_end = NULL; 314 | unsigned char number_c_string[64]; 315 | unsigned char decimal_point = get_decimal_point(); 316 | size_t i = 0; 317 | 318 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 319 | { 320 | return false; 321 | } 322 | 323 | /* copy the number into a temporary buffer and replace '.' with the decimal point 324 | * of the current locale (for strtod) 325 | * This also takes care of '\0' not necessarily being available for marking the end of the input */ 326 | for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) 327 | { 328 | switch (buffer_at_offset(input_buffer)[i]) 329 | { 330 | case '0': 331 | case '1': 332 | case '2': 333 | case '3': 334 | case '4': 335 | case '5': 336 | case '6': 337 | case '7': 338 | case '8': 339 | case '9': 340 | case '+': 341 | case '-': 342 | case 'e': 343 | case 'E': 344 | number_c_string[i] = buffer_at_offset(input_buffer)[i]; 345 | break; 346 | 347 | case '.': 348 | number_c_string[i] = decimal_point; 349 | break; 350 | 351 | default: 352 | goto loop_end; 353 | } 354 | } 355 | loop_end: 356 | number_c_string[i] = '\0'; 357 | 358 | number = strtod((const char*)number_c_string, (char**)&after_end); 359 | if (number_c_string == after_end) 360 | { 361 | return false; /* parse_error */ 362 | } 363 | 364 | item->valuedouble = number; 365 | 366 | /* use saturation in case of overflow */ 367 | if (number >= INT_MAX) 368 | { 369 | item->valueint = INT_MAX; 370 | } 371 | else if (number <= (double)INT_MIN) 372 | { 373 | item->valueint = INT_MIN; 374 | } 375 | else 376 | { 377 | item->valueint = (int)number; 378 | } 379 | 380 | item->type = cJSON_Number; 381 | 382 | input_buffer->offset += (size_t)(after_end - number_c_string); 383 | return true; 384 | } 385 | 386 | /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ 387 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) 388 | { 389 | if (number >= INT_MAX) 390 | { 391 | object->valueint = INT_MAX; 392 | } 393 | else if (number <= (double)INT_MIN) 394 | { 395 | object->valueint = INT_MIN; 396 | } 397 | else 398 | { 399 | object->valueint = (int)number; 400 | } 401 | 402 | return object->valuedouble = number; 403 | } 404 | 405 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) 406 | { 407 | char *copy = NULL; 408 | /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ 409 | if ((object == NULL) || !(object->type & cJSON_String) || (object->type & cJSON_IsReference)) 410 | { 411 | return NULL; 412 | } 413 | /* return NULL if the object is corrupted */ 414 | if (object->valuestring == NULL) 415 | { 416 | return NULL; 417 | } 418 | if (strlen(valuestring) <= strlen(object->valuestring)) 419 | { 420 | strcpy(object->valuestring, valuestring); 421 | return object->valuestring; 422 | } 423 | copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); 424 | if (copy == NULL) 425 | { 426 | return NULL; 427 | } 428 | if (object->valuestring != NULL) 429 | { 430 | cJSON_free(object->valuestring); 431 | } 432 | object->valuestring = copy; 433 | 434 | return copy; 435 | } 436 | 437 | typedef struct 438 | { 439 | unsigned char *buffer; 440 | size_t length; 441 | size_t offset; 442 | size_t depth; /* current nesting depth (for formatted printing) */ 443 | cJSON_bool noalloc; 444 | cJSON_bool format; /* is this print a formatted print */ 445 | internal_hooks hooks; 446 | } printbuffer; 447 | 448 | /* realloc printbuffer if necessary to have at least "needed" bytes more */ 449 | static unsigned char* ensure(printbuffer * const p, size_t needed) 450 | { 451 | unsigned char *newbuffer = NULL; 452 | size_t newsize = 0; 453 | 454 | if ((p == NULL) || (p->buffer == NULL)) 455 | { 456 | return NULL; 457 | } 458 | 459 | if ((p->length > 0) && (p->offset >= p->length)) 460 | { 461 | /* make sure that offset is valid */ 462 | return NULL; 463 | } 464 | 465 | if (needed > INT_MAX) 466 | { 467 | /* sizes bigger than INT_MAX are currently not supported */ 468 | return NULL; 469 | } 470 | 471 | needed += p->offset + 1; 472 | if (needed <= p->length) 473 | { 474 | return p->buffer + p->offset; 475 | } 476 | 477 | if (p->noalloc) { 478 | return NULL; 479 | } 480 | 481 | /* calculate new buffer size */ 482 | if (needed > (INT_MAX / 2)) 483 | { 484 | /* overflow of int, use INT_MAX if possible */ 485 | if (needed <= INT_MAX) 486 | { 487 | newsize = INT_MAX; 488 | } 489 | else 490 | { 491 | return NULL; 492 | } 493 | } 494 | else 495 | { 496 | newsize = needed * 2; 497 | } 498 | 499 | if (p->hooks.reallocate != NULL) 500 | { 501 | /* reallocate with realloc if available */ 502 | newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); 503 | if (newbuffer == NULL) 504 | { 505 | p->hooks.deallocate(p->buffer); 506 | p->length = 0; 507 | p->buffer = NULL; 508 | 509 | return NULL; 510 | } 511 | } 512 | else 513 | { 514 | /* otherwise reallocate manually */ 515 | newbuffer = (unsigned char*)p->hooks.allocate(newsize); 516 | if (!newbuffer) 517 | { 518 | p->hooks.deallocate(p->buffer); 519 | p->length = 0; 520 | p->buffer = NULL; 521 | 522 | return NULL; 523 | } 524 | 525 | rt_memcpy(newbuffer, p->buffer, p->offset + 1); 526 | p->hooks.deallocate(p->buffer); 527 | } 528 | p->length = newsize; 529 | p->buffer = newbuffer; 530 | 531 | return newbuffer + p->offset; 532 | } 533 | 534 | /* calculate the new length of the string in a printbuffer and update the offset */ 535 | static void update_offset(printbuffer * const buffer) 536 | { 537 | const unsigned char *buffer_pointer = NULL; 538 | if ((buffer == NULL) || (buffer->buffer == NULL)) 539 | { 540 | return; 541 | } 542 | buffer_pointer = buffer->buffer + buffer->offset; 543 | 544 | buffer->offset += strlen((const char*)buffer_pointer); 545 | } 546 | 547 | /* securely comparison of floating-point variables */ 548 | static cJSON_bool compare_double(double a, double b) 549 | { 550 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 551 | return (fabs(a - b) <= maxVal * DBL_EPSILON); 552 | } 553 | 554 | /* Render the number nicely from the given item into a string. */ 555 | static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) 556 | { 557 | unsigned char *output_pointer = NULL; 558 | double d = item->valuedouble; 559 | int length = 0; 560 | size_t i = 0; 561 | unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ 562 | unsigned char decimal_point = get_decimal_point(); 563 | double test = 0.0; 564 | 565 | if (output_buffer == NULL) 566 | { 567 | return false; 568 | } 569 | 570 | /* This checks for NaN and Infinity */ 571 | if (isnan(d) || isinf(d)) 572 | { 573 | length = sprintf((char*)number_buffer, "null"); 574 | } 575 | else if(d == (double)item->valueint) 576 | { 577 | length = sprintf((char*)number_buffer, "%d", item->valueint); 578 | } 579 | else 580 | { 581 | /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ 582 | length = sprintf((char*)number_buffer, "%1.15g", d); 583 | 584 | /* Check whether the original double can be recovered */ 585 | if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || !compare_double((double)test, d)) 586 | { 587 | /* If not, print with 17 decimal places of precision */ 588 | length = sprintf((char*)number_buffer, "%1.17g", d); 589 | } 590 | } 591 | 592 | /* sprintf failed or buffer overrun occurred */ 593 | if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) 594 | { 595 | return false; 596 | } 597 | 598 | /* reserve appropriate space in the output */ 599 | output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); 600 | if (output_pointer == NULL) 601 | { 602 | return false; 603 | } 604 | 605 | /* copy the printed number to the output and replace locale 606 | * dependent decimal point with '.' */ 607 | for (i = 0; i < ((size_t)length); i++) 608 | { 609 | if (number_buffer[i] == decimal_point) 610 | { 611 | output_pointer[i] = '.'; 612 | continue; 613 | } 614 | 615 | output_pointer[i] = number_buffer[i]; 616 | } 617 | output_pointer[i] = '\0'; 618 | 619 | output_buffer->offset += (size_t)length; 620 | 621 | return true; 622 | } 623 | 624 | /* parse 4 digit hexadecimal number */ 625 | static unsigned parse_hex4(const unsigned char * const input) 626 | { 627 | unsigned int h = 0; 628 | size_t i = 0; 629 | 630 | for (i = 0; i < 4; i++) 631 | { 632 | /* parse digit */ 633 | if ((input[i] >= '0') && (input[i] <= '9')) 634 | { 635 | h += (unsigned int) input[i] - '0'; 636 | } 637 | else if ((input[i] >= 'A') && (input[i] <= 'F')) 638 | { 639 | h += (unsigned int) 10 + input[i] - 'A'; 640 | } 641 | else if ((input[i] >= 'a') && (input[i] <= 'f')) 642 | { 643 | h += (unsigned int) 10 + input[i] - 'a'; 644 | } 645 | else /* invalid */ 646 | { 647 | return 0; 648 | } 649 | 650 | if (i < 3) 651 | { 652 | /* shift left to make place for the next nibble */ 653 | h = h << 4; 654 | } 655 | } 656 | 657 | return h; 658 | } 659 | 660 | /* converts a UTF-16 literal to UTF-8 661 | * A literal can be one or two sequences of the form \uXXXX */ 662 | static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) 663 | { 664 | long unsigned int codepoint = 0; 665 | unsigned int first_code = 0; 666 | const unsigned char *first_sequence = input_pointer; 667 | unsigned char utf8_length = 0; 668 | unsigned char utf8_position = 0; 669 | unsigned char sequence_length = 0; 670 | unsigned char first_byte_mark = 0; 671 | 672 | if ((input_end - first_sequence) < 6) 673 | { 674 | /* input ends unexpectedly */ 675 | goto fail; 676 | } 677 | 678 | /* get the first utf16 sequence */ 679 | first_code = parse_hex4(first_sequence + 2); 680 | 681 | /* check that the code is valid */ 682 | if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) 683 | { 684 | goto fail; 685 | } 686 | 687 | /* UTF16 surrogate pair */ 688 | if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) 689 | { 690 | const unsigned char *second_sequence = first_sequence + 6; 691 | unsigned int second_code = 0; 692 | sequence_length = 12; /* \uXXXX\uXXXX */ 693 | 694 | if ((input_end - second_sequence) < 6) 695 | { 696 | /* input ends unexpectedly */ 697 | goto fail; 698 | } 699 | 700 | if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) 701 | { 702 | /* missing second half of the surrogate pair */ 703 | goto fail; 704 | } 705 | 706 | /* get the second utf16 sequence */ 707 | second_code = parse_hex4(second_sequence + 2); 708 | /* check that the code is valid */ 709 | if ((second_code < 0xDC00) || (second_code > 0xDFFF)) 710 | { 711 | /* invalid second half of the surrogate pair */ 712 | goto fail; 713 | } 714 | 715 | 716 | /* calculate the unicode codepoint from the surrogate pair */ 717 | codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); 718 | } 719 | else 720 | { 721 | sequence_length = 6; /* \uXXXX */ 722 | codepoint = first_code; 723 | } 724 | 725 | /* encode as UTF-8 726 | * takes at maximum 4 bytes to encode: 727 | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 728 | if (codepoint < 0x80) 729 | { 730 | /* normal ascii, encoding 0xxxxxxx */ 731 | utf8_length = 1; 732 | } 733 | else if (codepoint < 0x800) 734 | { 735 | /* two bytes, encoding 110xxxxx 10xxxxxx */ 736 | utf8_length = 2; 737 | first_byte_mark = 0xC0; /* 11000000 */ 738 | } 739 | else if (codepoint < 0x10000) 740 | { 741 | /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ 742 | utf8_length = 3; 743 | first_byte_mark = 0xE0; /* 11100000 */ 744 | } 745 | else if (codepoint <= 0x10FFFF) 746 | { 747 | /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 748 | utf8_length = 4; 749 | first_byte_mark = 0xF0; /* 11110000 */ 750 | } 751 | else 752 | { 753 | /* invalid unicode codepoint */ 754 | goto fail; 755 | } 756 | 757 | /* encode as utf8 */ 758 | for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) 759 | { 760 | /* 10xxxxxx */ 761 | (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); 762 | codepoint >>= 6; 763 | } 764 | /* encode first byte */ 765 | if (utf8_length > 1) 766 | { 767 | (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); 768 | } 769 | else 770 | { 771 | (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); 772 | } 773 | 774 | *output_pointer += utf8_length; 775 | 776 | return sequence_length; 777 | 778 | fail: 779 | return 0; 780 | } 781 | 782 | /* Parse the input text into an unescaped cinput, and populate item. */ 783 | static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) 784 | { 785 | const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; 786 | const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; 787 | unsigned char *output_pointer = NULL; 788 | unsigned char *output = NULL; 789 | 790 | /* not a string */ 791 | if (buffer_at_offset(input_buffer)[0] != '\"') 792 | { 793 | goto fail; 794 | } 795 | 796 | { 797 | /* calculate approximate size of the output (overestimate) */ 798 | size_t allocation_length = 0; 799 | size_t skipped_bytes = 0; 800 | while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) 801 | { 802 | /* is escape sequence */ 803 | if (input_end[0] == '\\') 804 | { 805 | if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) 806 | { 807 | /* prevent buffer overflow when last input character is a backslash */ 808 | goto fail; 809 | } 810 | skipped_bytes++; 811 | input_end++; 812 | } 813 | input_end++; 814 | } 815 | if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) 816 | { 817 | goto fail; /* string ended unexpectedly */ 818 | } 819 | 820 | /* This is at most how much we need for the output */ 821 | allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; 822 | output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); 823 | if (output == NULL) 824 | { 825 | goto fail; /* allocation failure */ 826 | } 827 | } 828 | 829 | output_pointer = output; 830 | /* loop through the string literal */ 831 | while (input_pointer < input_end) 832 | { 833 | if (*input_pointer != '\\') 834 | { 835 | *output_pointer++ = *input_pointer++; 836 | } 837 | /* escape sequence */ 838 | else 839 | { 840 | unsigned char sequence_length = 2; 841 | if ((input_end - input_pointer) < 1) 842 | { 843 | goto fail; 844 | } 845 | 846 | switch (input_pointer[1]) 847 | { 848 | case 'b': 849 | *output_pointer++ = '\b'; 850 | break; 851 | case 'f': 852 | *output_pointer++ = '\f'; 853 | break; 854 | case 'n': 855 | *output_pointer++ = '\n'; 856 | break; 857 | case 'r': 858 | *output_pointer++ = '\r'; 859 | break; 860 | case 't': 861 | *output_pointer++ = '\t'; 862 | break; 863 | case '\"': 864 | case '\\': 865 | case '/': 866 | *output_pointer++ = input_pointer[1]; 867 | break; 868 | 869 | /* UTF-16 literal */ 870 | case 'u': 871 | sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); 872 | if (sequence_length == 0) 873 | { 874 | /* failed to convert UTF16-literal to UTF-8 */ 875 | goto fail; 876 | } 877 | break; 878 | 879 | default: 880 | goto fail; 881 | } 882 | input_pointer += sequence_length; 883 | } 884 | } 885 | 886 | /* zero terminate the output */ 887 | *output_pointer = '\0'; 888 | 889 | item->type = cJSON_String; 890 | item->valuestring = (char*)output; 891 | 892 | input_buffer->offset = (size_t) (input_end - input_buffer->content); 893 | input_buffer->offset++; 894 | 895 | return true; 896 | 897 | fail: 898 | if (output != NULL) 899 | { 900 | input_buffer->hooks.deallocate(output); 901 | } 902 | 903 | if (input_pointer != NULL) 904 | { 905 | input_buffer->offset = (size_t)(input_pointer - input_buffer->content); 906 | } 907 | 908 | return false; 909 | } 910 | 911 | /* Render the cstring provided to an escaped version that can be printed. */ 912 | static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) 913 | { 914 | const unsigned char *input_pointer = NULL; 915 | unsigned char *output = NULL; 916 | unsigned char *output_pointer = NULL; 917 | size_t output_length = 0; 918 | /* numbers of additional characters needed for escaping */ 919 | size_t escape_characters = 0; 920 | 921 | if (output_buffer == NULL) 922 | { 923 | return false; 924 | } 925 | 926 | /* empty string */ 927 | if (input == NULL) 928 | { 929 | output = ensure(output_buffer, sizeof("\"\"")); 930 | if (output == NULL) 931 | { 932 | return false; 933 | } 934 | strcpy((char*)output, "\"\""); 935 | 936 | return true; 937 | } 938 | 939 | /* set "flag" to 1 if something needs to be escaped */ 940 | for (input_pointer = input; *input_pointer; input_pointer++) 941 | { 942 | switch (*input_pointer) 943 | { 944 | case '\"': 945 | case '\\': 946 | case '\b': 947 | case '\f': 948 | case '\n': 949 | case '\r': 950 | case '\t': 951 | /* one character escape sequence */ 952 | escape_characters++; 953 | break; 954 | default: 955 | if (*input_pointer < 32) 956 | { 957 | /* UTF-16 escape sequence uXXXX */ 958 | escape_characters += 5; 959 | } 960 | break; 961 | } 962 | } 963 | output_length = (size_t)(input_pointer - input) + escape_characters; 964 | 965 | output = ensure(output_buffer, output_length + sizeof("\"\"")); 966 | if (output == NULL) 967 | { 968 | return false; 969 | } 970 | 971 | /* no characters have to be escaped */ 972 | if (escape_characters == 0) 973 | { 974 | output[0] = '\"'; 975 | rt_memcpy(output + 1, input, output_length); 976 | output[output_length + 1] = '\"'; 977 | output[output_length + 2] = '\0'; 978 | 979 | return true; 980 | } 981 | 982 | output[0] = '\"'; 983 | output_pointer = output + 1; 984 | /* copy the string */ 985 | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) 986 | { 987 | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) 988 | { 989 | /* normal character, copy */ 990 | *output_pointer = *input_pointer; 991 | } 992 | else 993 | { 994 | /* character needs to be escaped */ 995 | *output_pointer++ = '\\'; 996 | switch (*input_pointer) 997 | { 998 | case '\\': 999 | *output_pointer = '\\'; 1000 | break; 1001 | case '\"': 1002 | *output_pointer = '\"'; 1003 | break; 1004 | case '\b': 1005 | *output_pointer = 'b'; 1006 | break; 1007 | case '\f': 1008 | *output_pointer = 'f'; 1009 | break; 1010 | case '\n': 1011 | *output_pointer = 'n'; 1012 | break; 1013 | case '\r': 1014 | *output_pointer = 'r'; 1015 | break; 1016 | case '\t': 1017 | *output_pointer = 't'; 1018 | break; 1019 | default: 1020 | /* escape and print as unicode codepoint */ 1021 | sprintf((char*)output_pointer, "u%04x", *input_pointer); 1022 | output_pointer += 4; 1023 | break; 1024 | } 1025 | } 1026 | } 1027 | output[output_length + 1] = '\"'; 1028 | output[output_length + 2] = '\0'; 1029 | 1030 | return true; 1031 | } 1032 | 1033 | /* Invoke print_string_ptr (which is useful) on an item. */ 1034 | static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) 1035 | { 1036 | return print_string_ptr((unsigned char*)item->valuestring, p); 1037 | } 1038 | 1039 | /* Predeclare these prototypes. */ 1040 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); 1041 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); 1042 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); 1043 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); 1044 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); 1045 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); 1046 | 1047 | /* Utility to jump whitespace and cr/lf */ 1048 | static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) 1049 | { 1050 | if ((buffer == NULL) || (buffer->content == NULL)) 1051 | { 1052 | return NULL; 1053 | } 1054 | 1055 | if (cannot_access_at_index(buffer, 0)) 1056 | { 1057 | return buffer; 1058 | } 1059 | 1060 | while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) 1061 | { 1062 | buffer->offset++; 1063 | } 1064 | 1065 | if (buffer->offset == buffer->length) 1066 | { 1067 | buffer->offset--; 1068 | } 1069 | 1070 | return buffer; 1071 | } 1072 | 1073 | /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ 1074 | static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) 1075 | { 1076 | if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) 1077 | { 1078 | return NULL; 1079 | } 1080 | 1081 | if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) 1082 | { 1083 | buffer->offset += 3; 1084 | } 1085 | 1086 | return buffer; 1087 | } 1088 | 1089 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) 1090 | { 1091 | size_t buffer_length; 1092 | 1093 | if (NULL == value) 1094 | { 1095 | return NULL; 1096 | } 1097 | 1098 | /* Adding null character size due to require_null_terminated. */ 1099 | buffer_length = strlen(value) + sizeof(""); 1100 | 1101 | return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); 1102 | } 1103 | 1104 | /* Parse an object - create a new root, and populate. */ 1105 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) 1106 | { 1107 | parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; 1108 | cJSON *item = NULL; 1109 | 1110 | /* reset error position */ 1111 | global_error.json = NULL; 1112 | global_error.position = 0; 1113 | 1114 | if (value == NULL || 0 == buffer_length) 1115 | { 1116 | goto fail; 1117 | } 1118 | 1119 | buffer.content = (const unsigned char*)value; 1120 | buffer.length = buffer_length; 1121 | buffer.offset = 0; 1122 | buffer.hooks = global_hooks; 1123 | 1124 | item = cJSON_New_Item(&global_hooks); 1125 | if (item == NULL) /* memory fail */ 1126 | { 1127 | goto fail; 1128 | } 1129 | 1130 | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) 1131 | { 1132 | /* parse failure. ep is set. */ 1133 | goto fail; 1134 | } 1135 | 1136 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 1137 | if (require_null_terminated) 1138 | { 1139 | buffer_skip_whitespace(&buffer); 1140 | if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') 1141 | { 1142 | goto fail; 1143 | } 1144 | } 1145 | if (return_parse_end) 1146 | { 1147 | *return_parse_end = (const char*)buffer_at_offset(&buffer); 1148 | } 1149 | 1150 | return item; 1151 | 1152 | fail: 1153 | if (item != NULL) 1154 | { 1155 | cJSON_Delete(item); 1156 | } 1157 | 1158 | if (value != NULL) 1159 | { 1160 | error local_error; 1161 | local_error.json = (const unsigned char*)value; 1162 | local_error.position = 0; 1163 | 1164 | if (buffer.offset < buffer.length) 1165 | { 1166 | local_error.position = buffer.offset; 1167 | } 1168 | else if (buffer.length > 0) 1169 | { 1170 | local_error.position = buffer.length - 1; 1171 | } 1172 | 1173 | if (return_parse_end != NULL) 1174 | { 1175 | *return_parse_end = (const char*)local_error.json + local_error.position; 1176 | } 1177 | 1178 | global_error = local_error; 1179 | } 1180 | 1181 | return NULL; 1182 | } 1183 | 1184 | /* Default options for cJSON_Parse */ 1185 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) 1186 | { 1187 | return cJSON_ParseWithOpts(value, 0, 0); 1188 | } 1189 | 1190 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) 1191 | { 1192 | return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); 1193 | } 1194 | 1195 | #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) 1196 | 1197 | static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) 1198 | { 1199 | static const size_t default_buffer_size = 256; 1200 | printbuffer buffer[1]; 1201 | unsigned char *printed = NULL; 1202 | 1203 | rt_memset(buffer, 0, sizeof(buffer)); 1204 | 1205 | /* create buffer */ 1206 | buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); 1207 | buffer->length = default_buffer_size; 1208 | buffer->format = format; 1209 | buffer->hooks = *hooks; 1210 | if (buffer->buffer == NULL) 1211 | { 1212 | goto fail; 1213 | } 1214 | 1215 | /* print the value */ 1216 | if (!print_value(item, buffer)) 1217 | { 1218 | goto fail; 1219 | } 1220 | update_offset(buffer); 1221 | 1222 | /* check if reallocate is available */ 1223 | if (hooks->reallocate != NULL) 1224 | { 1225 | printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); 1226 | if (printed == NULL) { 1227 | goto fail; 1228 | } 1229 | buffer->buffer = NULL; 1230 | } 1231 | else /* otherwise copy the JSON over to a new buffer */ 1232 | { 1233 | printed = (unsigned char*) hooks->allocate(buffer->offset + 1); 1234 | if (printed == NULL) 1235 | { 1236 | goto fail; 1237 | } 1238 | rt_memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); 1239 | printed[buffer->offset] = '\0'; /* just to be sure */ 1240 | 1241 | /* free the buffer */ 1242 | hooks->deallocate(buffer->buffer); 1243 | } 1244 | 1245 | return printed; 1246 | 1247 | fail: 1248 | if (buffer->buffer != NULL) 1249 | { 1250 | hooks->deallocate(buffer->buffer); 1251 | } 1252 | 1253 | if (printed != NULL) 1254 | { 1255 | hooks->deallocate(printed); 1256 | } 1257 | 1258 | return NULL; 1259 | } 1260 | 1261 | /* Render a cJSON item/entity/structure to text. */ 1262 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) 1263 | { 1264 | return (char*)print(item, true, &global_hooks); 1265 | } 1266 | 1267 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) 1268 | { 1269 | return (char*)print(item, false, &global_hooks); 1270 | } 1271 | 1272 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) 1273 | { 1274 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1275 | 1276 | if (prebuffer < 0) 1277 | { 1278 | return NULL; 1279 | } 1280 | 1281 | p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); 1282 | if (!p.buffer) 1283 | { 1284 | return NULL; 1285 | } 1286 | 1287 | p.length = (size_t)prebuffer; 1288 | p.offset = 0; 1289 | p.noalloc = false; 1290 | p.format = fmt; 1291 | p.hooks = global_hooks; 1292 | 1293 | if (!print_value(item, &p)) 1294 | { 1295 | global_hooks.deallocate(p.buffer); 1296 | return NULL; 1297 | } 1298 | 1299 | return (char*)p.buffer; 1300 | } 1301 | 1302 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) 1303 | { 1304 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1305 | 1306 | if ((length < 0) || (buffer == NULL)) 1307 | { 1308 | return false; 1309 | } 1310 | 1311 | p.buffer = (unsigned char*)buffer; 1312 | p.length = (size_t)length; 1313 | p.offset = 0; 1314 | p.noalloc = true; 1315 | p.format = format; 1316 | p.hooks = global_hooks; 1317 | 1318 | return print_value(item, &p); 1319 | } 1320 | 1321 | /* Parser core - when encountering text, process appropriately. */ 1322 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) 1323 | { 1324 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 1325 | { 1326 | return false; /* no input */ 1327 | } 1328 | 1329 | /* parse the different types of values */ 1330 | /* null */ 1331 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) 1332 | { 1333 | item->type = cJSON_NULL; 1334 | input_buffer->offset += 4; 1335 | return true; 1336 | } 1337 | /* false */ 1338 | if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) 1339 | { 1340 | item->type = cJSON_False; 1341 | input_buffer->offset += 5; 1342 | return true; 1343 | } 1344 | /* true */ 1345 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) 1346 | { 1347 | item->type = cJSON_True; 1348 | item->valueint = 1; 1349 | input_buffer->offset += 4; 1350 | return true; 1351 | } 1352 | /* string */ 1353 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) 1354 | { 1355 | return parse_string(item, input_buffer); 1356 | } 1357 | /* number */ 1358 | if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) 1359 | { 1360 | return parse_number(item, input_buffer); 1361 | } 1362 | /* array */ 1363 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) 1364 | { 1365 | return parse_array(item, input_buffer); 1366 | } 1367 | /* object */ 1368 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) 1369 | { 1370 | return parse_object(item, input_buffer); 1371 | } 1372 | 1373 | return false; 1374 | } 1375 | 1376 | /* Render a value to text. */ 1377 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) 1378 | { 1379 | unsigned char *output = NULL; 1380 | 1381 | if ((item == NULL) || (output_buffer == NULL)) 1382 | { 1383 | return false; 1384 | } 1385 | 1386 | switch ((item->type) & 0xFF) 1387 | { 1388 | case cJSON_NULL: 1389 | output = ensure(output_buffer, 5); 1390 | if (output == NULL) 1391 | { 1392 | return false; 1393 | } 1394 | strcpy((char*)output, "null"); 1395 | return true; 1396 | 1397 | case cJSON_False: 1398 | output = ensure(output_buffer, 6); 1399 | if (output == NULL) 1400 | { 1401 | return false; 1402 | } 1403 | strcpy((char*)output, "false"); 1404 | return true; 1405 | 1406 | case cJSON_True: 1407 | output = ensure(output_buffer, 5); 1408 | if (output == NULL) 1409 | { 1410 | return false; 1411 | } 1412 | strcpy((char*)output, "true"); 1413 | return true; 1414 | 1415 | case cJSON_Number: 1416 | return print_number(item, output_buffer); 1417 | 1418 | case cJSON_Raw: 1419 | { 1420 | size_t raw_length = 0; 1421 | if (item->valuestring == NULL) 1422 | { 1423 | return false; 1424 | } 1425 | 1426 | raw_length = strlen(item->valuestring) + sizeof(""); 1427 | output = ensure(output_buffer, raw_length); 1428 | if (output == NULL) 1429 | { 1430 | return false; 1431 | } 1432 | rt_memcpy(output, item->valuestring, raw_length); 1433 | return true; 1434 | } 1435 | 1436 | case cJSON_String: 1437 | return print_string(item, output_buffer); 1438 | 1439 | case cJSON_Array: 1440 | return print_array(item, output_buffer); 1441 | 1442 | case cJSON_Object: 1443 | return print_object(item, output_buffer); 1444 | 1445 | default: 1446 | return false; 1447 | } 1448 | } 1449 | 1450 | /* Build an array from input text. */ 1451 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) 1452 | { 1453 | cJSON *head = NULL; /* head of the linked list */ 1454 | cJSON *current_item = NULL; 1455 | 1456 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1457 | { 1458 | return false; /* to deeply nested */ 1459 | } 1460 | input_buffer->depth++; 1461 | 1462 | if (buffer_at_offset(input_buffer)[0] != '[') 1463 | { 1464 | /* not an array */ 1465 | goto fail; 1466 | } 1467 | 1468 | input_buffer->offset++; 1469 | buffer_skip_whitespace(input_buffer); 1470 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) 1471 | { 1472 | /* empty array */ 1473 | goto success; 1474 | } 1475 | 1476 | /* check if we skipped to the end of the buffer */ 1477 | if (cannot_access_at_index(input_buffer, 0)) 1478 | { 1479 | input_buffer->offset--; 1480 | goto fail; 1481 | } 1482 | 1483 | /* step back to character in front of the first element */ 1484 | input_buffer->offset--; 1485 | /* loop through the comma separated array elements */ 1486 | do 1487 | { 1488 | /* allocate next item */ 1489 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1490 | if (new_item == NULL) 1491 | { 1492 | goto fail; /* allocation failure */ 1493 | } 1494 | 1495 | /* attach next item to list */ 1496 | if (head == NULL) 1497 | { 1498 | /* start the linked list */ 1499 | current_item = head = new_item; 1500 | } 1501 | else 1502 | { 1503 | /* add to the end and advance */ 1504 | current_item->next = new_item; 1505 | new_item->prev = current_item; 1506 | current_item = new_item; 1507 | } 1508 | 1509 | /* parse next value */ 1510 | input_buffer->offset++; 1511 | buffer_skip_whitespace(input_buffer); 1512 | if (!parse_value(current_item, input_buffer)) 1513 | { 1514 | goto fail; /* failed to parse value */ 1515 | } 1516 | buffer_skip_whitespace(input_buffer); 1517 | } 1518 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1519 | 1520 | if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') 1521 | { 1522 | goto fail; /* expected end of array */ 1523 | } 1524 | 1525 | success: 1526 | input_buffer->depth--; 1527 | 1528 | if (head != NULL) { 1529 | head->prev = current_item; 1530 | } 1531 | 1532 | item->type = cJSON_Array; 1533 | item->child = head; 1534 | 1535 | input_buffer->offset++; 1536 | 1537 | return true; 1538 | 1539 | fail: 1540 | if (head != NULL) 1541 | { 1542 | cJSON_Delete(head); 1543 | } 1544 | 1545 | return false; 1546 | } 1547 | 1548 | /* Render an array to text */ 1549 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) 1550 | { 1551 | unsigned char *output_pointer = NULL; 1552 | size_t length = 0; 1553 | cJSON *current_element = item->child; 1554 | 1555 | if (output_buffer == NULL) 1556 | { 1557 | return false; 1558 | } 1559 | 1560 | /* Compose the output array. */ 1561 | /* opening square bracket */ 1562 | output_pointer = ensure(output_buffer, 1); 1563 | if (output_pointer == NULL) 1564 | { 1565 | return false; 1566 | } 1567 | 1568 | *output_pointer = '['; 1569 | output_buffer->offset++; 1570 | output_buffer->depth++; 1571 | 1572 | while (current_element != NULL) 1573 | { 1574 | if (!print_value(current_element, output_buffer)) 1575 | { 1576 | return false; 1577 | } 1578 | update_offset(output_buffer); 1579 | if (current_element->next) 1580 | { 1581 | length = (size_t) (output_buffer->format ? 2 : 1); 1582 | output_pointer = ensure(output_buffer, length + 1); 1583 | if (output_pointer == NULL) 1584 | { 1585 | return false; 1586 | } 1587 | *output_pointer++ = ','; 1588 | if(output_buffer->format) 1589 | { 1590 | *output_pointer++ = ' '; 1591 | } 1592 | *output_pointer = '\0'; 1593 | output_buffer->offset += length; 1594 | } 1595 | current_element = current_element->next; 1596 | } 1597 | 1598 | output_pointer = ensure(output_buffer, 2); 1599 | if (output_pointer == NULL) 1600 | { 1601 | return false; 1602 | } 1603 | *output_pointer++ = ']'; 1604 | *output_pointer = '\0'; 1605 | output_buffer->depth--; 1606 | 1607 | return true; 1608 | } 1609 | 1610 | /* Build an object from the text. */ 1611 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) 1612 | { 1613 | cJSON *head = NULL; /* linked list head */ 1614 | cJSON *current_item = NULL; 1615 | 1616 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1617 | { 1618 | return false; /* to deeply nested */ 1619 | } 1620 | input_buffer->depth++; 1621 | 1622 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) 1623 | { 1624 | goto fail; /* not an object */ 1625 | } 1626 | 1627 | input_buffer->offset++; 1628 | buffer_skip_whitespace(input_buffer); 1629 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) 1630 | { 1631 | goto success; /* empty object */ 1632 | } 1633 | 1634 | /* check if we skipped to the end of the buffer */ 1635 | if (cannot_access_at_index(input_buffer, 0)) 1636 | { 1637 | input_buffer->offset--; 1638 | goto fail; 1639 | } 1640 | 1641 | /* step back to character in front of the first element */ 1642 | input_buffer->offset--; 1643 | /* loop through the comma separated array elements */ 1644 | do 1645 | { 1646 | /* allocate next item */ 1647 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1648 | if (new_item == NULL) 1649 | { 1650 | goto fail; /* allocation failure */ 1651 | } 1652 | 1653 | /* attach next item to list */ 1654 | if (head == NULL) 1655 | { 1656 | /* start the linked list */ 1657 | current_item = head = new_item; 1658 | } 1659 | else 1660 | { 1661 | /* add to the end and advance */ 1662 | current_item->next = new_item; 1663 | new_item->prev = current_item; 1664 | current_item = new_item; 1665 | } 1666 | 1667 | /* parse the name of the child */ 1668 | input_buffer->offset++; 1669 | buffer_skip_whitespace(input_buffer); 1670 | if (!parse_string(current_item, input_buffer)) 1671 | { 1672 | goto fail; /* failed to parse name */ 1673 | } 1674 | buffer_skip_whitespace(input_buffer); 1675 | 1676 | /* swap valuestring and string, because we parsed the name */ 1677 | current_item->string = current_item->valuestring; 1678 | current_item->valuestring = NULL; 1679 | 1680 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) 1681 | { 1682 | goto fail; /* invalid object */ 1683 | } 1684 | 1685 | /* parse the value */ 1686 | input_buffer->offset++; 1687 | buffer_skip_whitespace(input_buffer); 1688 | if (!parse_value(current_item, input_buffer)) 1689 | { 1690 | goto fail; /* failed to parse value */ 1691 | } 1692 | buffer_skip_whitespace(input_buffer); 1693 | } 1694 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1695 | 1696 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) 1697 | { 1698 | goto fail; /* expected end of object */ 1699 | } 1700 | 1701 | success: 1702 | input_buffer->depth--; 1703 | 1704 | if (head != NULL) { 1705 | head->prev = current_item; 1706 | } 1707 | 1708 | item->type = cJSON_Object; 1709 | item->child = head; 1710 | 1711 | input_buffer->offset++; 1712 | return true; 1713 | 1714 | fail: 1715 | if (head != NULL) 1716 | { 1717 | cJSON_Delete(head); 1718 | } 1719 | 1720 | return false; 1721 | } 1722 | 1723 | /* Render an object to text. */ 1724 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) 1725 | { 1726 | unsigned char *output_pointer = NULL; 1727 | size_t length = 0; 1728 | cJSON *current_item = item->child; 1729 | 1730 | if (output_buffer == NULL) 1731 | { 1732 | return false; 1733 | } 1734 | 1735 | /* Compose the output: */ 1736 | length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ 1737 | output_pointer = ensure(output_buffer, length + 1); 1738 | if (output_pointer == NULL) 1739 | { 1740 | return false; 1741 | } 1742 | 1743 | *output_pointer++ = '{'; 1744 | output_buffer->depth++; 1745 | if (output_buffer->format) 1746 | { 1747 | *output_pointer++ = '\n'; 1748 | } 1749 | output_buffer->offset += length; 1750 | 1751 | while (current_item) 1752 | { 1753 | if (output_buffer->format) 1754 | { 1755 | size_t i; 1756 | output_pointer = ensure(output_buffer, output_buffer->depth); 1757 | if (output_pointer == NULL) 1758 | { 1759 | return false; 1760 | } 1761 | for (i = 0; i < output_buffer->depth; i++) 1762 | { 1763 | *output_pointer++ = '\t'; 1764 | } 1765 | output_buffer->offset += output_buffer->depth; 1766 | } 1767 | 1768 | /* print key */ 1769 | if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) 1770 | { 1771 | return false; 1772 | } 1773 | update_offset(output_buffer); 1774 | 1775 | length = (size_t) (output_buffer->format ? 2 : 1); 1776 | output_pointer = ensure(output_buffer, length); 1777 | if (output_pointer == NULL) 1778 | { 1779 | return false; 1780 | } 1781 | *output_pointer++ = ':'; 1782 | if (output_buffer->format) 1783 | { 1784 | *output_pointer++ = '\t'; 1785 | } 1786 | output_buffer->offset += length; 1787 | 1788 | /* print value */ 1789 | if (!print_value(current_item, output_buffer)) 1790 | { 1791 | return false; 1792 | } 1793 | update_offset(output_buffer); 1794 | 1795 | /* print comma if not last */ 1796 | length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); 1797 | output_pointer = ensure(output_buffer, length + 1); 1798 | if (output_pointer == NULL) 1799 | { 1800 | return false; 1801 | } 1802 | if (current_item->next) 1803 | { 1804 | *output_pointer++ = ','; 1805 | } 1806 | 1807 | if (output_buffer->format) 1808 | { 1809 | *output_pointer++ = '\n'; 1810 | } 1811 | *output_pointer = '\0'; 1812 | output_buffer->offset += length; 1813 | 1814 | current_item = current_item->next; 1815 | } 1816 | 1817 | output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); 1818 | if (output_pointer == NULL) 1819 | { 1820 | return false; 1821 | } 1822 | if (output_buffer->format) 1823 | { 1824 | size_t i; 1825 | for (i = 0; i < (output_buffer->depth - 1); i++) 1826 | { 1827 | *output_pointer++ = '\t'; 1828 | } 1829 | } 1830 | *output_pointer++ = '}'; 1831 | *output_pointer = '\0'; 1832 | output_buffer->depth--; 1833 | 1834 | return true; 1835 | } 1836 | 1837 | /* Get Array size/item / object item. */ 1838 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) 1839 | { 1840 | cJSON *child = NULL; 1841 | size_t size = 0; 1842 | 1843 | if (array == NULL) 1844 | { 1845 | return 0; 1846 | } 1847 | 1848 | child = array->child; 1849 | 1850 | while(child != NULL) 1851 | { 1852 | size++; 1853 | child = child->next; 1854 | } 1855 | 1856 | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1857 | 1858 | return (int)size; 1859 | } 1860 | 1861 | static cJSON* get_array_item(const cJSON *array, size_t index) 1862 | { 1863 | cJSON *current_child = NULL; 1864 | 1865 | if (array == NULL) 1866 | { 1867 | return NULL; 1868 | } 1869 | 1870 | current_child = array->child; 1871 | while ((current_child != NULL) && (index > 0)) 1872 | { 1873 | index--; 1874 | current_child = current_child->next; 1875 | } 1876 | 1877 | return current_child; 1878 | } 1879 | 1880 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) 1881 | { 1882 | if (index < 0) 1883 | { 1884 | return NULL; 1885 | } 1886 | 1887 | return get_array_item(array, (size_t)index); 1888 | } 1889 | 1890 | static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) 1891 | { 1892 | cJSON *current_element = NULL; 1893 | 1894 | if ((object == NULL) || (name == NULL)) 1895 | { 1896 | return NULL; 1897 | } 1898 | 1899 | current_element = object->child; 1900 | if (case_sensitive) 1901 | { 1902 | while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) 1903 | { 1904 | current_element = current_element->next; 1905 | } 1906 | } 1907 | else 1908 | { 1909 | while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) 1910 | { 1911 | current_element = current_element->next; 1912 | } 1913 | } 1914 | 1915 | if ((current_element == NULL) || (current_element->string == NULL)) { 1916 | return NULL; 1917 | } 1918 | 1919 | return current_element; 1920 | } 1921 | 1922 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) 1923 | { 1924 | return get_object_item(object, string, false); 1925 | } 1926 | 1927 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) 1928 | { 1929 | return get_object_item(object, string, true); 1930 | } 1931 | 1932 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) 1933 | { 1934 | return cJSON_GetObjectItem(object, string) ? 1 : 0; 1935 | } 1936 | 1937 | /* Utility for array list handling. */ 1938 | static void suffix_object(cJSON *prev, cJSON *item) 1939 | { 1940 | prev->next = item; 1941 | item->prev = prev; 1942 | } 1943 | 1944 | /* Utility for handling references. */ 1945 | static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) 1946 | { 1947 | cJSON *reference = NULL; 1948 | if (item == NULL) 1949 | { 1950 | return NULL; 1951 | } 1952 | 1953 | reference = cJSON_New_Item(hooks); 1954 | if (reference == NULL) 1955 | { 1956 | return NULL; 1957 | } 1958 | 1959 | rt_memcpy(reference, item, sizeof(cJSON)); 1960 | reference->string = NULL; 1961 | reference->type |= cJSON_IsReference; 1962 | reference->next = reference->prev = NULL; 1963 | return reference; 1964 | } 1965 | 1966 | static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) 1967 | { 1968 | cJSON *child = NULL; 1969 | 1970 | if ((item == NULL) || (array == NULL) || (array == item)) 1971 | { 1972 | return false; 1973 | } 1974 | 1975 | child = array->child; 1976 | /* 1977 | * To find the last item in array quickly, we use prev in array 1978 | */ 1979 | if (child == NULL) 1980 | { 1981 | /* list is empty, start new one */ 1982 | array->child = item; 1983 | item->prev = item; 1984 | item->next = NULL; 1985 | } 1986 | else 1987 | { 1988 | /* append to the end */ 1989 | if (child->prev) 1990 | { 1991 | suffix_object(child->prev, item); 1992 | array->child->prev = item; 1993 | } 1994 | } 1995 | 1996 | return true; 1997 | } 1998 | 1999 | /* Add item to array/object. */ 2000 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) 2001 | { 2002 | return add_item_to_array(array, item); 2003 | } 2004 | 2005 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2006 | #pragma GCC diagnostic push 2007 | #endif 2008 | #ifdef __GNUC__ 2009 | #pragma GCC diagnostic ignored "-Wcast-qual" 2010 | #endif 2011 | /* helper function to cast away const */ 2012 | static void* cast_away_const(const void* string) 2013 | { 2014 | return (void*)string; 2015 | } 2016 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2017 | #pragma GCC diagnostic pop 2018 | #endif 2019 | 2020 | 2021 | static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key) 2022 | { 2023 | char *new_key = NULL; 2024 | int new_type = cJSON_Invalid; 2025 | 2026 | if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) 2027 | { 2028 | return false; 2029 | } 2030 | 2031 | if (constant_key) 2032 | { 2033 | new_key = (char*)cast_away_const(string); 2034 | new_type = item->type | cJSON_StringIsConst; 2035 | } 2036 | else 2037 | { 2038 | new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); 2039 | if (new_key == NULL) 2040 | { 2041 | return false; 2042 | } 2043 | 2044 | new_type = item->type & ~cJSON_StringIsConst; 2045 | } 2046 | 2047 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 2048 | { 2049 | hooks->deallocate(item->string); 2050 | } 2051 | 2052 | item->string = new_key; 2053 | item->type = new_type; 2054 | 2055 | return add_item_to_array(object, item); 2056 | } 2057 | 2058 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 2059 | { 2060 | return add_item_to_object(object, string, item, &global_hooks, false); 2061 | } 2062 | 2063 | /* Add an item to an object with constant string as key */ 2064 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 2065 | { 2066 | return add_item_to_object(object, string, item, &global_hooks, true); 2067 | } 2068 | 2069 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 2070 | { 2071 | if (array == NULL) 2072 | { 2073 | return false; 2074 | } 2075 | 2076 | return add_item_to_array(array, create_reference(item, &global_hooks)); 2077 | } 2078 | 2079 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 2080 | { 2081 | if ((object == NULL) || (string == NULL)) 2082 | { 2083 | return false; 2084 | } 2085 | 2086 | return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); 2087 | } 2088 | 2089 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) 2090 | { 2091 | cJSON *null = cJSON_CreateNull(); 2092 | if (add_item_to_object(object, name, null, &global_hooks, false)) 2093 | { 2094 | return null; 2095 | } 2096 | 2097 | cJSON_Delete(null); 2098 | return NULL; 2099 | } 2100 | 2101 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) 2102 | { 2103 | cJSON *true_item = cJSON_CreateTrue(); 2104 | if (add_item_to_object(object, name, true_item, &global_hooks, false)) 2105 | { 2106 | return true_item; 2107 | } 2108 | 2109 | cJSON_Delete(true_item); 2110 | return NULL; 2111 | } 2112 | 2113 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) 2114 | { 2115 | cJSON *false_item = cJSON_CreateFalse(); 2116 | if (add_item_to_object(object, name, false_item, &global_hooks, false)) 2117 | { 2118 | return false_item; 2119 | } 2120 | 2121 | cJSON_Delete(false_item); 2122 | return NULL; 2123 | } 2124 | 2125 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) 2126 | { 2127 | cJSON *bool_item = cJSON_CreateBool(boolean); 2128 | if (add_item_to_object(object, name, bool_item, &global_hooks, false)) 2129 | { 2130 | return bool_item; 2131 | } 2132 | 2133 | cJSON_Delete(bool_item); 2134 | return NULL; 2135 | } 2136 | 2137 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) 2138 | { 2139 | cJSON *number_item = cJSON_CreateNumber(number); 2140 | if (add_item_to_object(object, name, number_item, &global_hooks, false)) 2141 | { 2142 | return number_item; 2143 | } 2144 | 2145 | cJSON_Delete(number_item); 2146 | return NULL; 2147 | } 2148 | 2149 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) 2150 | { 2151 | cJSON *string_item = cJSON_CreateString(string); 2152 | if (add_item_to_object(object, name, string_item, &global_hooks, false)) 2153 | { 2154 | return string_item; 2155 | } 2156 | 2157 | cJSON_Delete(string_item); 2158 | return NULL; 2159 | } 2160 | 2161 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) 2162 | { 2163 | cJSON *raw_item = cJSON_CreateRaw(raw); 2164 | if (add_item_to_object(object, name, raw_item, &global_hooks, false)) 2165 | { 2166 | return raw_item; 2167 | } 2168 | 2169 | cJSON_Delete(raw_item); 2170 | return NULL; 2171 | } 2172 | 2173 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) 2174 | { 2175 | cJSON *object_item = cJSON_CreateObject(); 2176 | if (add_item_to_object(object, name, object_item, &global_hooks, false)) 2177 | { 2178 | return object_item; 2179 | } 2180 | 2181 | cJSON_Delete(object_item); 2182 | return NULL; 2183 | } 2184 | 2185 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) 2186 | { 2187 | cJSON *array = cJSON_CreateArray(); 2188 | if (add_item_to_object(object, name, array, &global_hooks, false)) 2189 | { 2190 | return array; 2191 | } 2192 | 2193 | cJSON_Delete(array); 2194 | return NULL; 2195 | } 2196 | 2197 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) 2198 | { 2199 | if ((parent == NULL) || (item == NULL)) 2200 | { 2201 | return NULL; 2202 | } 2203 | 2204 | if (item != parent->child) 2205 | { 2206 | /* not the first element */ 2207 | item->prev->next = item->next; 2208 | } 2209 | if (item->next != NULL) 2210 | { 2211 | /* not the last element */ 2212 | item->next->prev = item->prev; 2213 | } 2214 | 2215 | if (item == parent->child) 2216 | { 2217 | /* first element */ 2218 | parent->child = item->next; 2219 | } 2220 | else if (item->next == NULL) 2221 | { 2222 | /* last element */ 2223 | parent->child->prev = item->prev; 2224 | } 2225 | 2226 | /* make sure the detached item doesn't point anywhere anymore */ 2227 | item->prev = NULL; 2228 | item->next = NULL; 2229 | 2230 | return item; 2231 | } 2232 | 2233 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) 2234 | { 2235 | if (which < 0) 2236 | { 2237 | return NULL; 2238 | } 2239 | 2240 | return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); 2241 | } 2242 | 2243 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) 2244 | { 2245 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 2246 | } 2247 | 2248 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) 2249 | { 2250 | cJSON *to_detach = cJSON_GetObjectItem(object, string); 2251 | 2252 | return cJSON_DetachItemViaPointer(object, to_detach); 2253 | } 2254 | 2255 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) 2256 | { 2257 | cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); 2258 | 2259 | return cJSON_DetachItemViaPointer(object, to_detach); 2260 | } 2261 | 2262 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) 2263 | { 2264 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 2265 | } 2266 | 2267 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) 2268 | { 2269 | cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); 2270 | } 2271 | 2272 | /* Replace array/object items with new ones. */ 2273 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 2274 | { 2275 | cJSON *after_inserted = NULL; 2276 | 2277 | if (which < 0 || newitem == NULL) 2278 | { 2279 | return false; 2280 | } 2281 | 2282 | after_inserted = get_array_item(array, (size_t)which); 2283 | if (after_inserted == NULL) 2284 | { 2285 | return add_item_to_array(array, newitem); 2286 | } 2287 | 2288 | if (after_inserted != array->child && after_inserted->prev == NULL) { 2289 | /* return false if after_inserted is a corrupted array item */ 2290 | return false; 2291 | } 2292 | 2293 | newitem->next = after_inserted; 2294 | newitem->prev = after_inserted->prev; 2295 | after_inserted->prev = newitem; 2296 | if (after_inserted == array->child) 2297 | { 2298 | array->child = newitem; 2299 | } 2300 | else 2301 | { 2302 | newitem->prev->next = newitem; 2303 | } 2304 | return true; 2305 | } 2306 | 2307 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) 2308 | { 2309 | if ((parent == NULL) || (parent->child == NULL) || (replacement == NULL) || (item == NULL)) 2310 | { 2311 | return false; 2312 | } 2313 | 2314 | if (replacement == item) 2315 | { 2316 | return true; 2317 | } 2318 | 2319 | replacement->next = item->next; 2320 | replacement->prev = item->prev; 2321 | 2322 | if (replacement->next != NULL) 2323 | { 2324 | replacement->next->prev = replacement; 2325 | } 2326 | if (parent->child == item) 2327 | { 2328 | if (parent->child->prev == parent->child) 2329 | { 2330 | replacement->prev = replacement; 2331 | } 2332 | parent->child = replacement; 2333 | } 2334 | else 2335 | { /* 2336 | * To find the last item in array quickly, we use prev in array. 2337 | * We can't modify the last item's next pointer where this item was the parent's child 2338 | */ 2339 | if (replacement->prev != NULL) 2340 | { 2341 | replacement->prev->next = replacement; 2342 | } 2343 | if (replacement->next == NULL) 2344 | { 2345 | parent->child->prev = replacement; 2346 | } 2347 | } 2348 | 2349 | item->next = NULL; 2350 | item->prev = NULL; 2351 | cJSON_Delete(item); 2352 | 2353 | return true; 2354 | } 2355 | 2356 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 2357 | { 2358 | if (which < 0) 2359 | { 2360 | return false; 2361 | } 2362 | 2363 | return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); 2364 | } 2365 | 2366 | static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) 2367 | { 2368 | if ((replacement == NULL) || (string == NULL)) 2369 | { 2370 | return false; 2371 | } 2372 | 2373 | /* replace the name in the replacement */ 2374 | if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) 2375 | { 2376 | cJSON_free(replacement->string); 2377 | } 2378 | replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2379 | if (replacement->string == NULL) 2380 | { 2381 | return false; 2382 | } 2383 | 2384 | replacement->type &= ~cJSON_StringIsConst; 2385 | 2386 | return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); 2387 | } 2388 | 2389 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 2390 | { 2391 | return replace_item_in_object(object, string, newitem, false); 2392 | } 2393 | 2394 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) 2395 | { 2396 | return replace_item_in_object(object, string, newitem, true); 2397 | } 2398 | 2399 | /* Create basic types: */ 2400 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) 2401 | { 2402 | cJSON *item = cJSON_New_Item(&global_hooks); 2403 | if(item) 2404 | { 2405 | item->type = cJSON_NULL; 2406 | } 2407 | 2408 | return item; 2409 | } 2410 | 2411 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) 2412 | { 2413 | cJSON *item = cJSON_New_Item(&global_hooks); 2414 | if(item) 2415 | { 2416 | item->type = cJSON_True; 2417 | } 2418 | 2419 | return item; 2420 | } 2421 | 2422 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) 2423 | { 2424 | cJSON *item = cJSON_New_Item(&global_hooks); 2425 | if(item) 2426 | { 2427 | item->type = cJSON_False; 2428 | } 2429 | 2430 | return item; 2431 | } 2432 | 2433 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) 2434 | { 2435 | cJSON *item = cJSON_New_Item(&global_hooks); 2436 | if(item) 2437 | { 2438 | item->type = boolean ? cJSON_True : cJSON_False; 2439 | } 2440 | 2441 | return item; 2442 | } 2443 | 2444 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) 2445 | { 2446 | cJSON *item = cJSON_New_Item(&global_hooks); 2447 | if(item) 2448 | { 2449 | item->type = cJSON_Number; 2450 | item->valuedouble = num; 2451 | 2452 | /* use saturation in case of overflow */ 2453 | if (num >= INT_MAX) 2454 | { 2455 | item->valueint = INT_MAX; 2456 | } 2457 | else if (num <= (double)INT_MIN) 2458 | { 2459 | item->valueint = INT_MIN; 2460 | } 2461 | else 2462 | { 2463 | item->valueint = (int)num; 2464 | } 2465 | } 2466 | 2467 | return item; 2468 | } 2469 | 2470 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) 2471 | { 2472 | cJSON *item = cJSON_New_Item(&global_hooks); 2473 | if(item) 2474 | { 2475 | item->type = cJSON_String; 2476 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2477 | if(!item->valuestring) 2478 | { 2479 | cJSON_Delete(item); 2480 | return NULL; 2481 | } 2482 | } 2483 | 2484 | return item; 2485 | } 2486 | 2487 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) 2488 | { 2489 | cJSON *item = cJSON_New_Item(&global_hooks); 2490 | if (item != NULL) 2491 | { 2492 | item->type = cJSON_String | cJSON_IsReference; 2493 | item->valuestring = (char*)cast_away_const(string); 2494 | } 2495 | 2496 | return item; 2497 | } 2498 | 2499 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) 2500 | { 2501 | cJSON *item = cJSON_New_Item(&global_hooks); 2502 | if (item != NULL) { 2503 | item->type = cJSON_Object | cJSON_IsReference; 2504 | item->child = (cJSON*)cast_away_const(child); 2505 | } 2506 | 2507 | return item; 2508 | } 2509 | 2510 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { 2511 | cJSON *item = cJSON_New_Item(&global_hooks); 2512 | if (item != NULL) { 2513 | item->type = cJSON_Array | cJSON_IsReference; 2514 | item->child = (cJSON*)cast_away_const(child); 2515 | } 2516 | 2517 | return item; 2518 | } 2519 | 2520 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) 2521 | { 2522 | cJSON *item = cJSON_New_Item(&global_hooks); 2523 | if(item) 2524 | { 2525 | item->type = cJSON_Raw; 2526 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); 2527 | if(!item->valuestring) 2528 | { 2529 | cJSON_Delete(item); 2530 | return NULL; 2531 | } 2532 | } 2533 | 2534 | return item; 2535 | } 2536 | 2537 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) 2538 | { 2539 | cJSON *item = cJSON_New_Item(&global_hooks); 2540 | if(item) 2541 | { 2542 | item->type=cJSON_Array; 2543 | } 2544 | 2545 | return item; 2546 | } 2547 | 2548 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) 2549 | { 2550 | cJSON *item = cJSON_New_Item(&global_hooks); 2551 | if (item) 2552 | { 2553 | item->type = cJSON_Object; 2554 | } 2555 | 2556 | return item; 2557 | } 2558 | 2559 | /* Create Arrays: */ 2560 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) 2561 | { 2562 | size_t i = 0; 2563 | cJSON *n = NULL; 2564 | cJSON *p = NULL; 2565 | cJSON *a = NULL; 2566 | 2567 | if ((count < 0) || (numbers == NULL)) 2568 | { 2569 | return NULL; 2570 | } 2571 | 2572 | a = cJSON_CreateArray(); 2573 | 2574 | for(i = 0; a && (i < (size_t)count); i++) 2575 | { 2576 | n = cJSON_CreateNumber(numbers[i]); 2577 | if (!n) 2578 | { 2579 | cJSON_Delete(a); 2580 | return NULL; 2581 | } 2582 | if(!i) 2583 | { 2584 | a->child = n; 2585 | } 2586 | else 2587 | { 2588 | suffix_object(p, n); 2589 | } 2590 | p = n; 2591 | } 2592 | 2593 | if (a && a->child) { 2594 | a->child->prev = n; 2595 | } 2596 | 2597 | return a; 2598 | } 2599 | 2600 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) 2601 | { 2602 | size_t i = 0; 2603 | cJSON *n = NULL; 2604 | cJSON *p = NULL; 2605 | cJSON *a = NULL; 2606 | 2607 | if ((count < 0) || (numbers == NULL)) 2608 | { 2609 | return NULL; 2610 | } 2611 | 2612 | a = cJSON_CreateArray(); 2613 | 2614 | for(i = 0; a && (i < (size_t)count); i++) 2615 | { 2616 | n = cJSON_CreateNumber((double)numbers[i]); 2617 | if(!n) 2618 | { 2619 | cJSON_Delete(a); 2620 | return NULL; 2621 | } 2622 | if(!i) 2623 | { 2624 | a->child = n; 2625 | } 2626 | else 2627 | { 2628 | suffix_object(p, n); 2629 | } 2630 | p = n; 2631 | } 2632 | 2633 | if (a && a->child) { 2634 | a->child->prev = n; 2635 | } 2636 | 2637 | return a; 2638 | } 2639 | 2640 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) 2641 | { 2642 | size_t i = 0; 2643 | cJSON *n = NULL; 2644 | cJSON *p = NULL; 2645 | cJSON *a = NULL; 2646 | 2647 | if ((count < 0) || (numbers == NULL)) 2648 | { 2649 | return NULL; 2650 | } 2651 | 2652 | a = cJSON_CreateArray(); 2653 | 2654 | for(i = 0; a && (i < (size_t)count); i++) 2655 | { 2656 | n = cJSON_CreateNumber(numbers[i]); 2657 | if(!n) 2658 | { 2659 | cJSON_Delete(a); 2660 | return NULL; 2661 | } 2662 | if(!i) 2663 | { 2664 | a->child = n; 2665 | } 2666 | else 2667 | { 2668 | suffix_object(p, n); 2669 | } 2670 | p = n; 2671 | } 2672 | 2673 | if (a && a->child) { 2674 | a->child->prev = n; 2675 | } 2676 | 2677 | return a; 2678 | } 2679 | 2680 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) 2681 | { 2682 | size_t i = 0; 2683 | cJSON *n = NULL; 2684 | cJSON *p = NULL; 2685 | cJSON *a = NULL; 2686 | 2687 | if ((count < 0) || (strings == NULL)) 2688 | { 2689 | return NULL; 2690 | } 2691 | 2692 | a = cJSON_CreateArray(); 2693 | 2694 | for (i = 0; a && (i < (size_t)count); i++) 2695 | { 2696 | n = cJSON_CreateString(strings[i]); 2697 | if(!n) 2698 | { 2699 | cJSON_Delete(a); 2700 | return NULL; 2701 | } 2702 | if(!i) 2703 | { 2704 | a->child = n; 2705 | } 2706 | else 2707 | { 2708 | suffix_object(p,n); 2709 | } 2710 | p = n; 2711 | } 2712 | 2713 | if (a && a->child) { 2714 | a->child->prev = n; 2715 | } 2716 | 2717 | return a; 2718 | } 2719 | 2720 | /* Duplication */ 2721 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) 2722 | { 2723 | cJSON *newitem = NULL; 2724 | cJSON *child = NULL; 2725 | cJSON *next = NULL; 2726 | cJSON *newchild = NULL; 2727 | 2728 | /* Bail on bad ptr */ 2729 | if (!item) 2730 | { 2731 | goto fail; 2732 | } 2733 | /* Create new item */ 2734 | newitem = cJSON_New_Item(&global_hooks); 2735 | if (!newitem) 2736 | { 2737 | goto fail; 2738 | } 2739 | /* Copy over all vars */ 2740 | newitem->type = item->type & (~cJSON_IsReference); 2741 | newitem->valueint = item->valueint; 2742 | newitem->valuedouble = item->valuedouble; 2743 | if (item->valuestring) 2744 | { 2745 | newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); 2746 | if (!newitem->valuestring) 2747 | { 2748 | goto fail; 2749 | } 2750 | } 2751 | if (item->string) 2752 | { 2753 | newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); 2754 | if (!newitem->string) 2755 | { 2756 | goto fail; 2757 | } 2758 | } 2759 | /* If non-recursive, then we're done! */ 2760 | if (!recurse) 2761 | { 2762 | return newitem; 2763 | } 2764 | /* Walk the ->next chain for the child. */ 2765 | child = item->child; 2766 | while (child != NULL) 2767 | { 2768 | newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2769 | if (!newchild) 2770 | { 2771 | goto fail; 2772 | } 2773 | if (next != NULL) 2774 | { 2775 | /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2776 | next->next = newchild; 2777 | newchild->prev = next; 2778 | next = newchild; 2779 | } 2780 | else 2781 | { 2782 | /* Set newitem->child and move to it */ 2783 | newitem->child = newchild; 2784 | next = newchild; 2785 | } 2786 | child = child->next; 2787 | } 2788 | if (newitem && newitem->child) 2789 | { 2790 | newitem->child->prev = newchild; 2791 | } 2792 | 2793 | return newitem; 2794 | 2795 | fail: 2796 | if (newitem != NULL) 2797 | { 2798 | cJSON_Delete(newitem); 2799 | } 2800 | 2801 | return NULL; 2802 | } 2803 | 2804 | static void skip_oneline_comment(char **input) 2805 | { 2806 | *input += static_strlen("//"); 2807 | 2808 | for (; (*input)[0] != '\0'; ++(*input)) 2809 | { 2810 | if ((*input)[0] == '\n') { 2811 | *input += static_strlen("\n"); 2812 | return; 2813 | } 2814 | } 2815 | } 2816 | 2817 | static void skip_multiline_comment(char **input) 2818 | { 2819 | *input += static_strlen("/*"); 2820 | 2821 | for (; (*input)[0] != '\0'; ++(*input)) 2822 | { 2823 | if (((*input)[0] == '*') && ((*input)[1] == '/')) 2824 | { 2825 | *input += static_strlen("*/"); 2826 | return; 2827 | } 2828 | } 2829 | } 2830 | 2831 | static void minify_string(char **input, char **output) { 2832 | (*output)[0] = (*input)[0]; 2833 | *input += static_strlen("\""); 2834 | *output += static_strlen("\""); 2835 | 2836 | 2837 | for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 2838 | (*output)[0] = (*input)[0]; 2839 | 2840 | if ((*input)[0] == '\"') { 2841 | (*output)[0] = '\"'; 2842 | *input += static_strlen("\""); 2843 | *output += static_strlen("\""); 2844 | return; 2845 | } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 2846 | (*output)[1] = (*input)[1]; 2847 | *input += static_strlen("\""); 2848 | *output += static_strlen("\""); 2849 | } 2850 | } 2851 | } 2852 | 2853 | CJSON_PUBLIC(void) cJSON_Minify(char *json) 2854 | { 2855 | char *into = json; 2856 | 2857 | if (json == NULL) 2858 | { 2859 | return; 2860 | } 2861 | 2862 | while (json[0] != '\0') 2863 | { 2864 | switch (json[0]) 2865 | { 2866 | case ' ': 2867 | case '\t': 2868 | case '\r': 2869 | case '\n': 2870 | json++; 2871 | break; 2872 | 2873 | case '/': 2874 | if (json[1] == '/') 2875 | { 2876 | skip_oneline_comment(&json); 2877 | } 2878 | else if (json[1] == '*') 2879 | { 2880 | skip_multiline_comment(&json); 2881 | } else { 2882 | json++; 2883 | } 2884 | break; 2885 | 2886 | case '\"': 2887 | minify_string(&json, (char**)&into); 2888 | break; 2889 | 2890 | default: 2891 | into[0] = json[0]; 2892 | json++; 2893 | into++; 2894 | } 2895 | } 2896 | 2897 | /* and null-terminate. */ 2898 | *into = '\0'; 2899 | } 2900 | 2901 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) 2902 | { 2903 | if (item == NULL) 2904 | { 2905 | return false; 2906 | } 2907 | 2908 | return (item->type & 0xFF) == cJSON_Invalid; 2909 | } 2910 | 2911 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) 2912 | { 2913 | if (item == NULL) 2914 | { 2915 | return false; 2916 | } 2917 | 2918 | return (item->type & 0xFF) == cJSON_False; 2919 | } 2920 | 2921 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) 2922 | { 2923 | if (item == NULL) 2924 | { 2925 | return false; 2926 | } 2927 | 2928 | return (item->type & 0xff) == cJSON_True; 2929 | } 2930 | 2931 | 2932 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) 2933 | { 2934 | if (item == NULL) 2935 | { 2936 | return false; 2937 | } 2938 | 2939 | return (item->type & (cJSON_True | cJSON_False)) != 0; 2940 | } 2941 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) 2942 | { 2943 | if (item == NULL) 2944 | { 2945 | return false; 2946 | } 2947 | 2948 | return (item->type & 0xFF) == cJSON_NULL; 2949 | } 2950 | 2951 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) 2952 | { 2953 | if (item == NULL) 2954 | { 2955 | return false; 2956 | } 2957 | 2958 | return (item->type & 0xFF) == cJSON_Number; 2959 | } 2960 | 2961 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) 2962 | { 2963 | if (item == NULL) 2964 | { 2965 | return false; 2966 | } 2967 | 2968 | return (item->type & 0xFF) == cJSON_String; 2969 | } 2970 | 2971 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) 2972 | { 2973 | if (item == NULL) 2974 | { 2975 | return false; 2976 | } 2977 | 2978 | return (item->type & 0xFF) == cJSON_Array; 2979 | } 2980 | 2981 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) 2982 | { 2983 | if (item == NULL) 2984 | { 2985 | return false; 2986 | } 2987 | 2988 | return (item->type & 0xFF) == cJSON_Object; 2989 | } 2990 | 2991 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) 2992 | { 2993 | if (item == NULL) 2994 | { 2995 | return false; 2996 | } 2997 | 2998 | return (item->type & 0xFF) == cJSON_Raw; 2999 | } 3000 | 3001 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) 3002 | { 3003 | if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) 3004 | { 3005 | return false; 3006 | } 3007 | 3008 | /* check if type is valid */ 3009 | switch (a->type & 0xFF) 3010 | { 3011 | case cJSON_False: 3012 | case cJSON_True: 3013 | case cJSON_NULL: 3014 | case cJSON_Number: 3015 | case cJSON_String: 3016 | case cJSON_Raw: 3017 | case cJSON_Array: 3018 | case cJSON_Object: 3019 | break; 3020 | 3021 | default: 3022 | return false; 3023 | } 3024 | 3025 | /* identical objects are equal */ 3026 | if (a == b) 3027 | { 3028 | return true; 3029 | } 3030 | 3031 | switch (a->type & 0xFF) 3032 | { 3033 | /* in these cases and equal type is enough */ 3034 | case cJSON_False: 3035 | case cJSON_True: 3036 | case cJSON_NULL: 3037 | return true; 3038 | 3039 | case cJSON_Number: 3040 | if (compare_double(a->valuedouble, b->valuedouble)) 3041 | { 3042 | return true; 3043 | } 3044 | return false; 3045 | 3046 | case cJSON_String: 3047 | case cJSON_Raw: 3048 | if ((a->valuestring == NULL) || (b->valuestring == NULL)) 3049 | { 3050 | return false; 3051 | } 3052 | if (strcmp(a->valuestring, b->valuestring) == 0) 3053 | { 3054 | return true; 3055 | } 3056 | 3057 | return false; 3058 | 3059 | case cJSON_Array: 3060 | { 3061 | cJSON *a_element = a->child; 3062 | cJSON *b_element = b->child; 3063 | 3064 | for (; (a_element != NULL) && (b_element != NULL);) 3065 | { 3066 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3067 | { 3068 | return false; 3069 | } 3070 | 3071 | a_element = a_element->next; 3072 | b_element = b_element->next; 3073 | } 3074 | 3075 | /* one of the arrays is longer than the other */ 3076 | if (a_element != b_element) { 3077 | return false; 3078 | } 3079 | 3080 | return true; 3081 | } 3082 | 3083 | case cJSON_Object: 3084 | { 3085 | cJSON *a_element = NULL; 3086 | cJSON *b_element = NULL; 3087 | cJSON_ArrayForEach(a_element, a) 3088 | { 3089 | /* TODO This has O(n^2) runtime, which is horrible! */ 3090 | b_element = get_object_item(b, a_element->string, case_sensitive); 3091 | if (b_element == NULL) 3092 | { 3093 | return false; 3094 | } 3095 | 3096 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3097 | { 3098 | return false; 3099 | } 3100 | } 3101 | 3102 | /* doing this twice, once on a and b to prevent true comparison if a subset of b 3103 | * TODO: Do this the proper way, this is just a fix for now */ 3104 | cJSON_ArrayForEach(b_element, b) 3105 | { 3106 | a_element = get_object_item(a, b_element->string, case_sensitive); 3107 | if (a_element == NULL) 3108 | { 3109 | return false; 3110 | } 3111 | 3112 | if (!cJSON_Compare(b_element, a_element, case_sensitive)) 3113 | { 3114 | return false; 3115 | } 3116 | } 3117 | 3118 | return true; 3119 | } 3120 | 3121 | default: 3122 | return false; 3123 | } 3124 | } 3125 | 3126 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size) 3127 | { 3128 | return global_hooks.allocate(size); 3129 | } 3130 | 3131 | CJSON_PUBLIC(void) cJSON_free(void *object) 3132 | { 3133 | global_hooks.deallocate(object); 3134 | } 3135 | -------------------------------------------------------------------------------- /cJSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 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 | #if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) 32 | #define __WINDOWS__ 33 | #endif 34 | 35 | #ifdef __WINDOWS__ 36 | 37 | /* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 3 define options: 38 | 39 | CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols 40 | CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) 41 | CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol 42 | 43 | For *nix builds that support visibility attribute, you can define similar behavior by 44 | 45 | setting default visibility to hidden by adding 46 | -fvisibility=hidden (for gcc) 47 | or 48 | -xldscope=hidden (for sun cc) 49 | to CFLAGS 50 | 51 | then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does 52 | 53 | */ 54 | 55 | #define CJSON_CDECL __cdecl 56 | #define CJSON_STDCALL __stdcall 57 | 58 | /* export symbols by default, this is necessary for copy pasting the C and header file */ 59 | #if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) 60 | #define CJSON_EXPORT_SYMBOLS 61 | #endif 62 | 63 | #if defined(CJSON_HIDE_SYMBOLS) 64 | #define CJSON_PUBLIC(type) type CJSON_STDCALL 65 | #elif defined(CJSON_EXPORT_SYMBOLS) 66 | #define CJSON_PUBLIC(type) __declspec(dllexport) type CJSON_STDCALL 67 | #elif defined(CJSON_IMPORT_SYMBOLS) 68 | #define CJSON_PUBLIC(type) __declspec(dllimport) type CJSON_STDCALL 69 | #endif 70 | #else /* !__WINDOWS__ */ 71 | #define CJSON_CDECL 72 | #define CJSON_STDCALL 73 | 74 | #if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) 75 | #define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type 76 | #else 77 | #define CJSON_PUBLIC(type) type 78 | #endif 79 | #endif 80 | 81 | /* project version */ 82 | #define CJSON_VERSION_MAJOR 1 83 | #define CJSON_VERSION_MINOR 7 84 | #define CJSON_VERSION_PATCH 17 85 | 86 | #include 87 | 88 | /* cJSON Types: */ 89 | #define cJSON_Invalid (0) 90 | #define cJSON_False (1 << 0) 91 | #define cJSON_True (1 << 1) 92 | #define cJSON_NULL (1 << 2) 93 | #define cJSON_Number (1 << 3) 94 | #define cJSON_String (1 << 4) 95 | #define cJSON_Array (1 << 5) 96 | #define cJSON_Object (1 << 6) 97 | #define cJSON_Raw (1 << 7) /* raw json */ 98 | 99 | #define cJSON_IsReference 256 100 | #define cJSON_StringIsConst 512 101 | 102 | /* The cJSON structure: */ 103 | typedef struct cJSON 104 | { 105 | /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ 106 | struct cJSON *next; 107 | struct cJSON *prev; 108 | /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ 109 | struct cJSON *child; 110 | 111 | /* The type of the item, as above. */ 112 | int type; 113 | 114 | /* The item's string, if type==cJSON_String and type == cJSON_Raw */ 115 | char *valuestring; 116 | /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ 117 | int valueint; 118 | /* The item's number, if type==cJSON_Number */ 119 | double valuedouble; 120 | 121 | /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ 122 | char *string; 123 | } cJSON; 124 | 125 | typedef struct cJSON_Hooks 126 | { 127 | /* malloc/free are CDECL on Windows regardless of the default calling convention of the compiler, so ensure the hooks allow passing those functions directly. */ 128 | void *(CJSON_CDECL *malloc_fn)(size_t sz); 129 | void (CJSON_CDECL *free_fn)(void *ptr); 130 | } cJSON_Hooks; 131 | 132 | typedef int cJSON_bool; 133 | 134 | /* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. 135 | * This is to prevent stack overflows. */ 136 | #ifndef CJSON_NESTING_LIMIT 137 | #define CJSON_NESTING_LIMIT 1000 138 | #endif 139 | 140 | /* returns the version of cJSON as a string */ 141 | CJSON_PUBLIC(const char*) cJSON_Version(void); 142 | 143 | /* Supply malloc, realloc and free functions to cJSON */ 144 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); 145 | 146 | /* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ 147 | /* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ 148 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); 149 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length); 150 | /* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ 151 | /* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ 152 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); 153 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated); 154 | 155 | /* Render a cJSON entity to text for transfer/storage. */ 156 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); 157 | /* Render a cJSON entity to text for transfer/storage without any formatting. */ 158 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); 159 | /* 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 */ 160 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); 161 | /* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ 162 | /* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ 163 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); 164 | /* Delete a cJSON entity and all subentities. */ 165 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item); 166 | 167 | /* Returns the number of items in an array (or object). */ 168 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); 169 | /* Retrieve item number "index" from array "array". Returns NULL if unsuccessful. */ 170 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); 171 | /* Get item "string" from object. Case insensitive. */ 172 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); 173 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); 174 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); 175 | /* 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. */ 176 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); 177 | 178 | /* Check item type and return its value */ 179 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item); 180 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item); 181 | 182 | /* These functions check the type of an item */ 183 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); 184 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); 185 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); 186 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); 187 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); 188 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); 189 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); 190 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); 191 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); 192 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); 193 | 194 | /* These calls create a cJSON item of the appropriate type. */ 195 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); 196 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); 197 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); 198 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); 199 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); 200 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); 201 | /* raw json */ 202 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); 203 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); 204 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); 205 | 206 | /* Create a string where valuestring references a string so 207 | * it will not be freed by cJSON_Delete */ 208 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string); 209 | /* Create an object/array that only references it's elements so 210 | * they will not be freed by cJSON_Delete */ 211 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child); 212 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child); 213 | 214 | /* These utilities create an Array of count items. 215 | * The parameter count cannot be greater than the number of elements in the number array, otherwise array access will be out of bounds.*/ 216 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); 217 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); 218 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); 219 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count); 220 | 221 | /* Append item to the specified array/object. */ 222 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item); 223 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); 224 | /* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. 225 | * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before 226 | * writing to `item->string` */ 227 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); 228 | /* 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. */ 229 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); 230 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); 231 | 232 | /* Remove/Detach items from Arrays/Objects. */ 233 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); 234 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); 235 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); 236 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); 237 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); 238 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); 239 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); 240 | 241 | /* Update array items. */ 242 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ 243 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); 244 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); 245 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); 246 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); 247 | 248 | /* Duplicate a cJSON item */ 249 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); 250 | /* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will 251 | * need to be released. With recurse!=0, it will duplicate any children connected to the item. 252 | * The item->next and ->prev pointers are always zero on return from Duplicate. */ 253 | /* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. 254 | * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ 255 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); 256 | 257 | /* Minify a strings, remove blank characters(such as ' ', '\t', '\r', '\n') from strings. 258 | * The input pointer json cannot point to a read-only address area, such as a string constant, 259 | * but should point to a readable and writable address area. */ 260 | CJSON_PUBLIC(void) cJSON_Minify(char *json); 261 | 262 | /* Helper functions for creating and adding items to an object at the same time. 263 | * They return the added item or NULL on failure. */ 264 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name); 265 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name); 266 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name); 267 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean); 268 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number); 269 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string); 270 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw); 271 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name); 272 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name); 273 | 274 | /* When assigning an integer value, it needs to be propagated to valuedouble too. */ 275 | #define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) 276 | /* helper for the cJSON_SetNumberValue macro */ 277 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); 278 | #define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) 279 | /* Change the valuestring of a cJSON_String object, only takes effect when type of object is cJSON_String */ 280 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring); 281 | 282 | /* If the object is not a boolean type this does nothing and returns cJSON_Invalid else it returns the new type*/ 283 | #define cJSON_SetBoolValue(object, boolValue) ( \ 284 | (object != NULL && ((object)->type & (cJSON_False|cJSON_True))) ? \ 285 | (object)->type=((object)->type &(~(cJSON_False|cJSON_True)))|((boolValue)?cJSON_True:cJSON_False) : \ 286 | cJSON_Invalid\ 287 | ) 288 | 289 | /* Macro for iterating over an array or object */ 290 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 291 | 292 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 293 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 294 | CJSON_PUBLIC(void) cJSON_free(void *object); 295 | 296 | #ifdef __cplusplus 297 | } 298 | #endif 299 | 300 | #endif 301 | -------------------------------------------------------------------------------- /cJSON_Utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 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 | /* disable warnings about old C89 functions in MSVC */ 24 | #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) 25 | #define _CRT_SECURE_NO_DEPRECATE 26 | #endif 27 | 28 | #ifdef __GNUCC__ 29 | #pragma GCC visibility push(default) 30 | #endif 31 | #if defined(_MSC_VER) 32 | #pragma warning (push) 33 | /* disable warning about single line comments in system headers */ 34 | #pragma warning (disable : 4001) 35 | #endif 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #if defined(_MSC_VER) 47 | #pragma warning (pop) 48 | #endif 49 | #ifdef __GNUCC__ 50 | #pragma GCC visibility pop 51 | #endif 52 | 53 | #include 54 | #include "cJSON_Utils.h" 55 | 56 | /* define our own boolean type */ 57 | #ifdef true 58 | #undef true 59 | #endif 60 | #define true ((cJSON_bool)1) 61 | 62 | #ifdef false 63 | #undef false 64 | #endif 65 | #define false ((cJSON_bool)0) 66 | 67 | static unsigned char* cJSONUtils_strdup(const unsigned char* const string) 68 | { 69 | size_t length = 0; 70 | unsigned char *copy = NULL; 71 | 72 | length = strlen((const char*)string) + sizeof(""); 73 | copy = (unsigned char*) cJSON_malloc(length); 74 | if (copy == NULL) 75 | { 76 | return NULL; 77 | } 78 | rt_memcpy(copy, string, length); 79 | 80 | return copy; 81 | } 82 | 83 | /* string comparison which doesn't consider NULL pointers equal */ 84 | static int compare_strings(const unsigned char *string1, const unsigned char *string2, const cJSON_bool case_sensitive) 85 | { 86 | if ((string1 == NULL) || (string2 == NULL)) 87 | { 88 | return 1; 89 | } 90 | 91 | if (string1 == string2) 92 | { 93 | return 0; 94 | } 95 | 96 | if (case_sensitive) 97 | { 98 | return strcmp((const char*)string1, (const char*)string2); 99 | } 100 | 101 | for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 102 | { 103 | if (*string1 == '\0') 104 | { 105 | return 0; 106 | } 107 | } 108 | 109 | return tolower(*string1) - tolower(*string2); 110 | } 111 | 112 | /* securely comparison of floating-point variables */ 113 | static cJSON_bool compare_double(double a, double b) 114 | { 115 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 116 | return (fabs(a - b) <= maxVal * DBL_EPSILON); 117 | } 118 | 119 | 120 | /* Compare the next path element of two JSON pointers, two NULL pointers are considered unequal: */ 121 | static cJSON_bool compare_pointers(const unsigned char *name, const unsigned char *pointer, const cJSON_bool case_sensitive) 122 | { 123 | if ((name == NULL) || (pointer == NULL)) 124 | { 125 | return false; 126 | } 127 | 128 | for (; (*name != '\0') && (*pointer != '\0') && (*pointer != '/'); (void)name++, pointer++) /* compare until next '/' */ 129 | { 130 | if (*pointer == '~') 131 | { 132 | /* check for escaped '~' (~0) and '/' (~1) */ 133 | if (((pointer[1] != '0') || (*name != '~')) && ((pointer[1] != '1') || (*name != '/'))) 134 | { 135 | /* invalid escape sequence or wrong character in *name */ 136 | return false; 137 | } 138 | else 139 | { 140 | pointer++; 141 | } 142 | } 143 | else if ((!case_sensitive && (tolower(*name) != tolower(*pointer))) || (case_sensitive && (*name != *pointer))) 144 | { 145 | return false; 146 | } 147 | } 148 | if (((*pointer != 0) && (*pointer != '/')) != (*name != 0)) 149 | { 150 | /* one string has ended, the other not */ 151 | return false;; 152 | } 153 | 154 | return true; 155 | } 156 | 157 | /* calculate the length of a string if encoded as JSON pointer with ~0 and ~1 escape sequences */ 158 | static size_t pointer_encoded_length(const unsigned char *string) 159 | { 160 | size_t length; 161 | for (length = 0; *string != '\0'; (void)string++, length++) 162 | { 163 | /* character needs to be escaped? */ 164 | if ((*string == '~') || (*string == '/')) 165 | { 166 | length++; 167 | } 168 | } 169 | 170 | return length; 171 | } 172 | 173 | /* copy a string while escaping '~' and '/' with ~0 and ~1 JSON pointer escape codes */ 174 | static void encode_string_as_pointer(unsigned char *destination, const unsigned char *source) 175 | { 176 | for (; source[0] != '\0'; (void)source++, destination++) 177 | { 178 | if (source[0] == '/') 179 | { 180 | destination[0] = '~'; 181 | destination[1] = '1'; 182 | destination++; 183 | } 184 | else if (source[0] == '~') 185 | { 186 | destination[0] = '~'; 187 | destination[1] = '0'; 188 | destination++; 189 | } 190 | else 191 | { 192 | destination[0] = source[0]; 193 | } 194 | } 195 | 196 | destination[0] = '\0'; 197 | } 198 | 199 | CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target) 200 | { 201 | size_t child_index = 0; 202 | cJSON *current_child = 0; 203 | 204 | if ((object == NULL) || (target == NULL)) 205 | { 206 | return NULL; 207 | } 208 | 209 | if (object == target) 210 | { 211 | /* found */ 212 | return (char*)cJSONUtils_strdup((const unsigned char*)""); 213 | } 214 | 215 | /* recursively search all children of the object or array */ 216 | for (current_child = object->child; current_child != NULL; (void)(current_child = current_child->next), child_index++) 217 | { 218 | unsigned char *target_pointer = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(current_child, target); 219 | /* found the target? */ 220 | if (target_pointer != NULL) 221 | { 222 | if (cJSON_IsArray(object)) 223 | { 224 | /* reserve enough memory for a 64 bit integer + '/' and '\0' */ 225 | unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + 20 + sizeof("/")); 226 | /* check if conversion to unsigned long is valid 227 | * This should be eliminated at compile time by dead code elimination 228 | * if size_t is an alias of unsigned long, or if it is bigger */ 229 | if (child_index > ULONG_MAX) 230 | { 231 | cJSON_free(target_pointer); 232 | cJSON_free(full_pointer); 233 | return NULL; 234 | } 235 | sprintf((char*)full_pointer, "/%lu%s", (unsigned long)child_index, target_pointer); /* / */ 236 | cJSON_free(target_pointer); 237 | 238 | return (char*)full_pointer; 239 | } 240 | 241 | if (cJSON_IsObject(object)) 242 | { 243 | unsigned char *full_pointer = (unsigned char*)cJSON_malloc(strlen((char*)target_pointer) + pointer_encoded_length((unsigned char*)current_child->string) + 2); 244 | full_pointer[0] = '/'; 245 | encode_string_as_pointer(full_pointer + 1, (unsigned char*)current_child->string); 246 | strcat((char*)full_pointer, (char*)target_pointer); 247 | cJSON_free(target_pointer); 248 | 249 | return (char*)full_pointer; 250 | } 251 | 252 | /* reached leaf of the tree, found nothing */ 253 | cJSON_free(target_pointer); 254 | return NULL; 255 | } 256 | } 257 | 258 | /* not found */ 259 | return NULL; 260 | } 261 | 262 | /* non broken version of cJSON_GetArrayItem */ 263 | static cJSON *get_array_item(const cJSON *array, size_t item) 264 | { 265 | cJSON *child = array ? array->child : NULL; 266 | while ((child != NULL) && (item > 0)) 267 | { 268 | item--; 269 | child = child->next; 270 | } 271 | 272 | return child; 273 | } 274 | 275 | static cJSON_bool decode_array_index_from_pointer(const unsigned char * const pointer, size_t * const index) 276 | { 277 | size_t parsed_index = 0; 278 | size_t position = 0; 279 | 280 | if ((pointer[0] == '0') && ((pointer[1] != '\0') && (pointer[1] != '/'))) 281 | { 282 | /* leading zeroes are not permitted */ 283 | return 0; 284 | } 285 | 286 | for (position = 0; (pointer[position] >= '0') && (pointer[0] <= '9'); position++) 287 | { 288 | parsed_index = (10 * parsed_index) + (size_t)(pointer[position] - '0'); 289 | 290 | } 291 | 292 | if ((pointer[position] != '\0') && (pointer[position] != '/')) 293 | { 294 | return 0; 295 | } 296 | 297 | *index = parsed_index; 298 | 299 | return 1; 300 | } 301 | 302 | static cJSON *get_item_from_pointer(cJSON * const object, const char * pointer, const cJSON_bool case_sensitive) 303 | { 304 | cJSON *current_element = object; 305 | 306 | if (pointer == NULL) 307 | { 308 | return NULL; 309 | } 310 | 311 | /* follow path of the pointer */ 312 | while ((pointer[0] == '/') && (current_element != NULL)) 313 | { 314 | pointer++; 315 | if (cJSON_IsArray(current_element)) 316 | { 317 | size_t index = 0; 318 | if (!decode_array_index_from_pointer((const unsigned char*)pointer, &index)) 319 | { 320 | return NULL; 321 | } 322 | 323 | current_element = get_array_item(current_element, index); 324 | } 325 | else if (cJSON_IsObject(current_element)) 326 | { 327 | current_element = current_element->child; 328 | /* GetObjectItem. */ 329 | while ((current_element != NULL) && !compare_pointers((unsigned char*)current_element->string, (const unsigned char*)pointer, case_sensitive)) 330 | { 331 | current_element = current_element->next; 332 | } 333 | } 334 | else 335 | { 336 | return NULL; 337 | } 338 | 339 | /* skip to the next path token or end of string */ 340 | while ((pointer[0] != '\0') && (pointer[0] != '/')) 341 | { 342 | pointer++; 343 | } 344 | } 345 | 346 | return current_element; 347 | } 348 | 349 | CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer) 350 | { 351 | return get_item_from_pointer(object, pointer, false); 352 | } 353 | 354 | CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer) 355 | { 356 | return get_item_from_pointer(object, pointer, true); 357 | } 358 | 359 | /* JSON Patch implementation. */ 360 | static void decode_pointer_inplace(unsigned char *string) 361 | { 362 | unsigned char *decoded_string = string; 363 | 364 | if (string == NULL) { 365 | return; 366 | } 367 | 368 | for (; *string; (void)decoded_string++, string++) 369 | { 370 | if (string[0] == '~') 371 | { 372 | if (string[1] == '0') 373 | { 374 | decoded_string[0] = '~'; 375 | } 376 | else if (string[1] == '1') 377 | { 378 | decoded_string[1] = '/'; 379 | } 380 | else 381 | { 382 | /* invalid escape sequence */ 383 | return; 384 | } 385 | 386 | string++; 387 | } 388 | } 389 | 390 | decoded_string[0] = '\0'; 391 | } 392 | 393 | /* non-broken cJSON_DetachItemFromArray */ 394 | static cJSON *detach_item_from_array(cJSON *array, size_t which) 395 | { 396 | cJSON *c = array->child; 397 | while (c && (which > 0)) 398 | { 399 | c = c->next; 400 | which--; 401 | } 402 | if (!c) 403 | { 404 | /* item doesn't exist */ 405 | return NULL; 406 | } 407 | if (c != array->child) 408 | { 409 | /* not the first element */ 410 | c->prev->next = c->next; 411 | } 412 | if (c->next) 413 | { 414 | c->next->prev = c->prev; 415 | } 416 | if (c == array->child) 417 | { 418 | array->child = c->next; 419 | } 420 | else if (c->next == NULL) 421 | { 422 | array->child->prev = c->prev; 423 | } 424 | /* make sure the detached item doesn't point anywhere anymore */ 425 | c->prev = c->next = NULL; 426 | 427 | return c; 428 | } 429 | 430 | /* detach an item at the given path */ 431 | static cJSON *detach_path(cJSON *object, const unsigned char *path, const cJSON_bool case_sensitive) 432 | { 433 | unsigned char *parent_pointer = NULL; 434 | unsigned char *child_pointer = NULL; 435 | cJSON *parent = NULL; 436 | cJSON *detached_item = NULL; 437 | 438 | /* copy path and split it in parent and child */ 439 | parent_pointer = cJSONUtils_strdup(path); 440 | if (parent_pointer == NULL) { 441 | goto cleanup; 442 | } 443 | 444 | child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); /* last '/' */ 445 | if (child_pointer == NULL) 446 | { 447 | goto cleanup; 448 | } 449 | /* split strings */ 450 | child_pointer[0] = '\0'; 451 | child_pointer++; 452 | 453 | parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); 454 | decode_pointer_inplace(child_pointer); 455 | 456 | if (cJSON_IsArray(parent)) 457 | { 458 | size_t index = 0; 459 | if (!decode_array_index_from_pointer(child_pointer, &index)) 460 | { 461 | goto cleanup; 462 | } 463 | detached_item = detach_item_from_array(parent, index); 464 | } 465 | else if (cJSON_IsObject(parent)) 466 | { 467 | detached_item = cJSON_DetachItemFromObject(parent, (char*)child_pointer); 468 | } 469 | else 470 | { 471 | /* Couldn't find object to remove child from. */ 472 | goto cleanup; 473 | } 474 | 475 | cleanup: 476 | if (parent_pointer != NULL) 477 | { 478 | cJSON_free(parent_pointer); 479 | } 480 | 481 | return detached_item; 482 | } 483 | 484 | /* sort lists using mergesort */ 485 | static cJSON *sort_list(cJSON *list, const cJSON_bool case_sensitive) 486 | { 487 | cJSON *first = list; 488 | cJSON *second = list; 489 | cJSON *current_item = list; 490 | cJSON *result = list; 491 | cJSON *result_tail = NULL; 492 | 493 | if ((list == NULL) || (list->next == NULL)) 494 | { 495 | /* One entry is sorted already. */ 496 | return result; 497 | } 498 | 499 | while ((current_item != NULL) && (current_item->next != NULL) && (compare_strings((unsigned char*)current_item->string, (unsigned char*)current_item->next->string, case_sensitive) < 0)) 500 | { 501 | /* Test for list sorted. */ 502 | current_item = current_item->next; 503 | } 504 | if ((current_item == NULL) || (current_item->next == NULL)) 505 | { 506 | /* Leave sorted lists unmodified. */ 507 | return result; 508 | } 509 | 510 | /* reset pointer to the beginning */ 511 | current_item = list; 512 | while (current_item != NULL) 513 | { 514 | /* Walk two pointers to find the middle. */ 515 | second = second->next; 516 | current_item = current_item->next; 517 | /* advances current_item two steps at a time */ 518 | if (current_item != NULL) 519 | { 520 | current_item = current_item->next; 521 | } 522 | } 523 | if ((second != NULL) && (second->prev != NULL)) 524 | { 525 | /* Split the lists */ 526 | second->prev->next = NULL; 527 | second->prev = NULL; 528 | } 529 | 530 | /* Recursively sort the sub-lists. */ 531 | first = sort_list(first, case_sensitive); 532 | second = sort_list(second, case_sensitive); 533 | result = NULL; 534 | 535 | /* Merge the sub-lists */ 536 | while ((first != NULL) && (second != NULL)) 537 | { 538 | cJSON *smaller = NULL; 539 | if (compare_strings((unsigned char*)first->string, (unsigned char*)second->string, case_sensitive) < 0) 540 | { 541 | smaller = first; 542 | } 543 | else 544 | { 545 | smaller = second; 546 | } 547 | 548 | if (result == NULL) 549 | { 550 | /* start merged list with the smaller element */ 551 | result_tail = smaller; 552 | result = smaller; 553 | } 554 | else 555 | { 556 | /* add smaller element to the list */ 557 | result_tail->next = smaller; 558 | smaller->prev = result_tail; 559 | result_tail = smaller; 560 | } 561 | 562 | if (first == smaller) 563 | { 564 | first = first->next; 565 | } 566 | else 567 | { 568 | second = second->next; 569 | } 570 | } 571 | 572 | if (first != NULL) 573 | { 574 | /* Append rest of first list. */ 575 | if (result == NULL) 576 | { 577 | return first; 578 | } 579 | result_tail->next = first; 580 | first->prev = result_tail; 581 | } 582 | if (second != NULL) 583 | { 584 | /* Append rest of second list */ 585 | if (result == NULL) 586 | { 587 | return second; 588 | } 589 | result_tail->next = second; 590 | second->prev = result_tail; 591 | } 592 | 593 | return result; 594 | } 595 | 596 | static void sort_object(cJSON * const object, const cJSON_bool case_sensitive) 597 | { 598 | if (object == NULL) 599 | { 600 | return; 601 | } 602 | object->child = sort_list(object->child, case_sensitive); 603 | } 604 | 605 | static cJSON_bool compare_json(cJSON *a, cJSON *b, const cJSON_bool case_sensitive) 606 | { 607 | if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) 608 | { 609 | /* mismatched type. */ 610 | return false; 611 | } 612 | switch (a->type & 0xFF) 613 | { 614 | case cJSON_Number: 615 | /* numeric mismatch. */ 616 | if ((a->valueint != b->valueint) || (!compare_double(a->valuedouble, b->valuedouble))) 617 | { 618 | return false; 619 | } 620 | else 621 | { 622 | return true; 623 | } 624 | 625 | case cJSON_String: 626 | /* string mismatch. */ 627 | if (strcmp(a->valuestring, b->valuestring) != 0) 628 | { 629 | return false; 630 | } 631 | else 632 | { 633 | return true; 634 | } 635 | 636 | case cJSON_Array: 637 | for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) 638 | { 639 | cJSON_bool identical = compare_json(a, b, case_sensitive); 640 | if (!identical) 641 | { 642 | return false; 643 | } 644 | } 645 | 646 | /* array size mismatch? (one of both children is not NULL) */ 647 | if ((a != NULL) || (b != NULL)) 648 | { 649 | return false; 650 | } 651 | else 652 | { 653 | return true; 654 | } 655 | 656 | case cJSON_Object: 657 | sort_object(a, case_sensitive); 658 | sort_object(b, case_sensitive); 659 | for ((void)(a = a->child), b = b->child; (a != NULL) && (b != NULL); (void)(a = a->next), b = b->next) 660 | { 661 | cJSON_bool identical = false; 662 | /* compare object keys */ 663 | if (compare_strings((unsigned char*)a->string, (unsigned char*)b->string, case_sensitive)) 664 | { 665 | /* missing member */ 666 | return false; 667 | } 668 | identical = compare_json(a, b, case_sensitive); 669 | if (!identical) 670 | { 671 | return false; 672 | } 673 | } 674 | 675 | /* object length mismatch (one of both children is not null) */ 676 | if ((a != NULL) || (b != NULL)) 677 | { 678 | return false; 679 | } 680 | else 681 | { 682 | return true; 683 | } 684 | 685 | default: 686 | break; 687 | } 688 | 689 | /* null, true or false */ 690 | return true; 691 | } 692 | 693 | /* non broken version of cJSON_InsertItemInArray */ 694 | static cJSON_bool insert_item_in_array(cJSON *array, size_t which, cJSON *newitem) 695 | { 696 | cJSON *child = array->child; 697 | while (child && (which > 0)) 698 | { 699 | child = child->next; 700 | which--; 701 | } 702 | if (which > 0) 703 | { 704 | /* item is after the end of the array */ 705 | return 0; 706 | } 707 | if (child == NULL) 708 | { 709 | cJSON_AddItemToArray(array, newitem); 710 | return 1; 711 | } 712 | 713 | /* insert into the linked list */ 714 | newitem->next = child; 715 | newitem->prev = child->prev; 716 | child->prev = newitem; 717 | 718 | /* was it at the beginning */ 719 | if (child == array->child) 720 | { 721 | array->child = newitem; 722 | } 723 | else 724 | { 725 | newitem->prev->next = newitem; 726 | } 727 | 728 | return 1; 729 | } 730 | 731 | static cJSON *get_object_item(const cJSON * const object, const char* name, const cJSON_bool case_sensitive) 732 | { 733 | if (case_sensitive) 734 | { 735 | return cJSON_GetObjectItemCaseSensitive(object, name); 736 | } 737 | 738 | return cJSON_GetObjectItem(object, name); 739 | } 740 | 741 | enum patch_operation { INVALID, ADD, REMOVE, REPLACE, MOVE, COPY, TEST }; 742 | 743 | static enum patch_operation decode_patch_operation(const cJSON * const patch, const cJSON_bool case_sensitive) 744 | { 745 | cJSON *operation = get_object_item(patch, "op", case_sensitive); 746 | if (!cJSON_IsString(operation)) 747 | { 748 | return INVALID; 749 | } 750 | 751 | if (strcmp(operation->valuestring, "add") == 0) 752 | { 753 | return ADD; 754 | } 755 | 756 | if (strcmp(operation->valuestring, "remove") == 0) 757 | { 758 | return REMOVE; 759 | } 760 | 761 | if (strcmp(operation->valuestring, "replace") == 0) 762 | { 763 | return REPLACE; 764 | } 765 | 766 | if (strcmp(operation->valuestring, "move") == 0) 767 | { 768 | return MOVE; 769 | } 770 | 771 | if (strcmp(operation->valuestring, "copy") == 0) 772 | { 773 | return COPY; 774 | } 775 | 776 | if (strcmp(operation->valuestring, "test") == 0) 777 | { 778 | return TEST; 779 | } 780 | 781 | return INVALID; 782 | } 783 | 784 | /* overwrite and existing item with another one and free resources on the way */ 785 | static void overwrite_item(cJSON * const root, const cJSON replacement) 786 | { 787 | if (root == NULL) 788 | { 789 | return; 790 | } 791 | 792 | if (root->string != NULL) 793 | { 794 | cJSON_free(root->string); 795 | } 796 | if (root->valuestring != NULL) 797 | { 798 | cJSON_free(root->valuestring); 799 | } 800 | if (root->child != NULL) 801 | { 802 | cJSON_Delete(root->child); 803 | } 804 | 805 | rt_memcpy(root, &replacement, sizeof(cJSON)); 806 | } 807 | 808 | static int apply_patch(cJSON *object, const cJSON *patch, const cJSON_bool case_sensitive) 809 | { 810 | cJSON *path = NULL; 811 | cJSON *value = NULL; 812 | cJSON *parent = NULL; 813 | enum patch_operation opcode = INVALID; 814 | unsigned char *parent_pointer = NULL; 815 | unsigned char *child_pointer = NULL; 816 | int status = 0; 817 | 818 | path = get_object_item(patch, "path", case_sensitive); 819 | if (!cJSON_IsString(path)) 820 | { 821 | /* malformed patch. */ 822 | status = 2; 823 | goto cleanup; 824 | } 825 | 826 | opcode = decode_patch_operation(patch, case_sensitive); 827 | if (opcode == INVALID) 828 | { 829 | status = 3; 830 | goto cleanup; 831 | } 832 | else if (opcode == TEST) 833 | { 834 | /* compare value: {...} with the given path */ 835 | status = !compare_json(get_item_from_pointer(object, path->valuestring, case_sensitive), get_object_item(patch, "value", case_sensitive), case_sensitive); 836 | goto cleanup; 837 | } 838 | 839 | /* special case for replacing the root */ 840 | if (path->valuestring[0] == '\0') 841 | { 842 | if (opcode == REMOVE) 843 | { 844 | static const cJSON invalid = { NULL, NULL, NULL, cJSON_Invalid, NULL, 0, 0, NULL}; 845 | 846 | overwrite_item(object, invalid); 847 | 848 | status = 0; 849 | goto cleanup; 850 | } 851 | 852 | if ((opcode == REPLACE) || (opcode == ADD)) 853 | { 854 | value = get_object_item(patch, "value", case_sensitive); 855 | if (value == NULL) 856 | { 857 | /* missing "value" for add/replace. */ 858 | status = 7; 859 | goto cleanup; 860 | } 861 | 862 | value = cJSON_Duplicate(value, 1); 863 | if (value == NULL) 864 | { 865 | /* out of memory for add/replace. */ 866 | status = 8; 867 | goto cleanup; 868 | } 869 | 870 | overwrite_item(object, *value); 871 | 872 | /* delete the duplicated value */ 873 | cJSON_free(value); 874 | value = NULL; 875 | 876 | /* the string "value" isn't needed */ 877 | if (object->string != NULL) 878 | { 879 | cJSON_free(object->string); 880 | object->string = NULL; 881 | } 882 | 883 | status = 0; 884 | goto cleanup; 885 | } 886 | } 887 | 888 | if ((opcode == REMOVE) || (opcode == REPLACE)) 889 | { 890 | /* Get rid of old. */ 891 | cJSON *old_item = detach_path(object, (unsigned char*)path->valuestring, case_sensitive); 892 | if (old_item == NULL) 893 | { 894 | status = 13; 895 | goto cleanup; 896 | } 897 | cJSON_Delete(old_item); 898 | if (opcode == REMOVE) 899 | { 900 | /* For Remove, this job is done. */ 901 | status = 0; 902 | goto cleanup; 903 | } 904 | } 905 | 906 | /* Copy/Move uses "from". */ 907 | if ((opcode == MOVE) || (opcode == COPY)) 908 | { 909 | cJSON *from = get_object_item(patch, "from", case_sensitive); 910 | if (from == NULL) 911 | { 912 | /* missing "from" for copy/move. */ 913 | status = 4; 914 | goto cleanup; 915 | } 916 | 917 | if (opcode == MOVE) 918 | { 919 | value = detach_path(object, (unsigned char*)from->valuestring, case_sensitive); 920 | } 921 | if (opcode == COPY) 922 | { 923 | value = get_item_from_pointer(object, from->valuestring, case_sensitive); 924 | } 925 | if (value == NULL) 926 | { 927 | /* missing "from" for copy/move. */ 928 | status = 5; 929 | goto cleanup; 930 | } 931 | if (opcode == COPY) 932 | { 933 | value = cJSON_Duplicate(value, 1); 934 | } 935 | if (value == NULL) 936 | { 937 | /* out of memory for copy/move. */ 938 | status = 6; 939 | goto cleanup; 940 | } 941 | } 942 | else /* Add/Replace uses "value". */ 943 | { 944 | value = get_object_item(patch, "value", case_sensitive); 945 | if (value == NULL) 946 | { 947 | /* missing "value" for add/replace. */ 948 | status = 7; 949 | goto cleanup; 950 | } 951 | value = cJSON_Duplicate(value, 1); 952 | if (value == NULL) 953 | { 954 | /* out of memory for add/replace. */ 955 | status = 8; 956 | goto cleanup; 957 | } 958 | } 959 | 960 | /* Now, just add "value" to "path". */ 961 | 962 | /* split pointer in parent and child */ 963 | parent_pointer = cJSONUtils_strdup((unsigned char*)path->valuestring); 964 | if (parent_pointer) { 965 | child_pointer = (unsigned char*)strrchr((char*)parent_pointer, '/'); 966 | } 967 | if (child_pointer != NULL) 968 | { 969 | child_pointer[0] = '\0'; 970 | child_pointer++; 971 | } 972 | parent = get_item_from_pointer(object, (char*)parent_pointer, case_sensitive); 973 | decode_pointer_inplace(child_pointer); 974 | 975 | /* add, remove, replace, move, copy, test. */ 976 | if ((parent == NULL) || (child_pointer == NULL)) 977 | { 978 | /* Couldn't find object to add to. */ 979 | status = 9; 980 | goto cleanup; 981 | } 982 | else if (cJSON_IsArray(parent)) 983 | { 984 | if (strcmp((char*)child_pointer, "-") == 0) 985 | { 986 | cJSON_AddItemToArray(parent, value); 987 | value = NULL; 988 | } 989 | else 990 | { 991 | size_t index = 0; 992 | if (!decode_array_index_from_pointer(child_pointer, &index)) 993 | { 994 | status = 11; 995 | goto cleanup; 996 | } 997 | 998 | if (!insert_item_in_array(parent, index, value)) 999 | { 1000 | status = 10; 1001 | goto cleanup; 1002 | } 1003 | value = NULL; 1004 | } 1005 | } 1006 | else if (cJSON_IsObject(parent)) 1007 | { 1008 | if (case_sensitive) 1009 | { 1010 | cJSON_DeleteItemFromObjectCaseSensitive(parent, (char*)child_pointer); 1011 | } 1012 | else 1013 | { 1014 | cJSON_DeleteItemFromObject(parent, (char*)child_pointer); 1015 | } 1016 | cJSON_AddItemToObject(parent, (char*)child_pointer, value); 1017 | value = NULL; 1018 | } 1019 | else /* parent is not an object */ 1020 | { 1021 | /* Couldn't find object to add to. */ 1022 | status = 9; 1023 | goto cleanup; 1024 | } 1025 | 1026 | cleanup: 1027 | if (value != NULL) 1028 | { 1029 | cJSON_Delete(value); 1030 | } 1031 | if (parent_pointer != NULL) 1032 | { 1033 | cJSON_free(parent_pointer); 1034 | } 1035 | 1036 | return status; 1037 | } 1038 | 1039 | CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches) 1040 | { 1041 | const cJSON *current_patch = NULL; 1042 | int status = 0; 1043 | 1044 | if (!cJSON_IsArray(patches)) 1045 | { 1046 | /* malformed patches. */ 1047 | return 1; 1048 | } 1049 | 1050 | if (patches != NULL) 1051 | { 1052 | current_patch = patches->child; 1053 | } 1054 | 1055 | while (current_patch != NULL) 1056 | { 1057 | status = apply_patch(object, current_patch, false); 1058 | if (status != 0) 1059 | { 1060 | return status; 1061 | } 1062 | current_patch = current_patch->next; 1063 | } 1064 | 1065 | return 0; 1066 | } 1067 | 1068 | CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches) 1069 | { 1070 | const cJSON *current_patch = NULL; 1071 | int status = 0; 1072 | 1073 | if (!cJSON_IsArray(patches)) 1074 | { 1075 | /* malformed patches. */ 1076 | return 1; 1077 | } 1078 | 1079 | if (patches != NULL) 1080 | { 1081 | current_patch = patches->child; 1082 | } 1083 | 1084 | while (current_patch != NULL) 1085 | { 1086 | status = apply_patch(object, current_patch, true); 1087 | if (status != 0) 1088 | { 1089 | return status; 1090 | } 1091 | current_patch = current_patch->next; 1092 | } 1093 | 1094 | return 0; 1095 | } 1096 | 1097 | static void compose_patch(cJSON * const patches, const unsigned char * const operation, const unsigned char * const path, const unsigned char *suffix, const cJSON * const value) 1098 | { 1099 | cJSON *patch = NULL; 1100 | 1101 | if ((patches == NULL) || (operation == NULL) || (path == NULL)) 1102 | { 1103 | return; 1104 | } 1105 | 1106 | patch = cJSON_CreateObject(); 1107 | if (patch == NULL) 1108 | { 1109 | return; 1110 | } 1111 | cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)operation)); 1112 | 1113 | if (suffix == NULL) 1114 | { 1115 | cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path)); 1116 | } 1117 | else 1118 | { 1119 | size_t suffix_length = pointer_encoded_length(suffix); 1120 | size_t path_length = strlen((const char*)path); 1121 | unsigned char *full_path = (unsigned char*)cJSON_malloc(path_length + suffix_length + sizeof("/")); 1122 | 1123 | sprintf((char*)full_path, "%s/", (const char*)path); 1124 | encode_string_as_pointer(full_path + path_length + 1, suffix); 1125 | 1126 | cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)full_path)); 1127 | cJSON_free(full_path); 1128 | } 1129 | 1130 | if (value != NULL) 1131 | { 1132 | cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(value, 1)); 1133 | } 1134 | cJSON_AddItemToArray(patches, patch); 1135 | } 1136 | 1137 | CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value) 1138 | { 1139 | compose_patch(array, (const unsigned char*)operation, (const unsigned char*)path, NULL, value); 1140 | } 1141 | 1142 | static void create_patches(cJSON * const patches, const unsigned char * const path, cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) 1143 | { 1144 | if ((from == NULL) || (to == NULL)) 1145 | { 1146 | return; 1147 | } 1148 | 1149 | if ((from->type & 0xFF) != (to->type & 0xFF)) 1150 | { 1151 | compose_patch(patches, (const unsigned char*)"replace", path, 0, to); 1152 | return; 1153 | } 1154 | 1155 | switch (from->type & 0xFF) 1156 | { 1157 | case cJSON_Number: 1158 | if ((from->valueint != to->valueint) || !compare_double(from->valuedouble, to->valuedouble)) 1159 | { 1160 | compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); 1161 | } 1162 | return; 1163 | 1164 | case cJSON_String: 1165 | if (strcmp(from->valuestring, to->valuestring) != 0) 1166 | { 1167 | compose_patch(patches, (const unsigned char*)"replace", path, NULL, to); 1168 | } 1169 | return; 1170 | 1171 | case cJSON_Array: 1172 | { 1173 | size_t index = 0; 1174 | cJSON *from_child = from->child; 1175 | cJSON *to_child = to->child; 1176 | unsigned char *new_path = (unsigned char*)cJSON_malloc(strlen((const char*)path) + 20 + sizeof("/")); /* Allow space for 64bit int. log10(2^64) = 20 */ 1177 | 1178 | /* generate patches for all array elements that exist in both "from" and "to" */ 1179 | for (index = 0; (from_child != NULL) && (to_child != NULL); (void)(from_child = from_child->next), (void)(to_child = to_child->next), index++) 1180 | { 1181 | /* check if conversion to unsigned long is valid 1182 | * This should be eliminated at compile time by dead code elimination 1183 | * if size_t is an alias of unsigned long, or if it is bigger */ 1184 | if (index > ULONG_MAX) 1185 | { 1186 | cJSON_free(new_path); 1187 | return; 1188 | } 1189 | sprintf((char*)new_path, "%s/%lu", path, (unsigned long)index); /* path of the current array element */ 1190 | create_patches(patches, new_path, from_child, to_child, case_sensitive); 1191 | } 1192 | 1193 | /* remove leftover elements from 'from' that are not in 'to' */ 1194 | for (; (from_child != NULL); (void)(from_child = from_child->next)) 1195 | { 1196 | /* check if conversion to unsigned long is valid 1197 | * This should be eliminated at compile time by dead code elimination 1198 | * if size_t is an alias of unsigned long, or if it is bigger */ 1199 | if (index > ULONG_MAX) 1200 | { 1201 | cJSON_free(new_path); 1202 | return; 1203 | } 1204 | sprintf((char*)new_path, "%lu", (unsigned long)index); 1205 | compose_patch(patches, (const unsigned char*)"remove", path, new_path, NULL); 1206 | } 1207 | /* add new elements in 'to' that were not in 'from' */ 1208 | for (; (to_child != NULL); (void)(to_child = to_child->next), index++) 1209 | { 1210 | compose_patch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to_child); 1211 | } 1212 | cJSON_free(new_path); 1213 | return; 1214 | } 1215 | 1216 | case cJSON_Object: 1217 | { 1218 | cJSON *from_child = NULL; 1219 | cJSON *to_child = NULL; 1220 | sort_object(from, case_sensitive); 1221 | sort_object(to, case_sensitive); 1222 | 1223 | from_child = from->child; 1224 | to_child = to->child; 1225 | /* for all object values in the object with more of them */ 1226 | while ((from_child != NULL) || (to_child != NULL)) 1227 | { 1228 | int diff; 1229 | if (from_child == NULL) 1230 | { 1231 | diff = 1; 1232 | } 1233 | else if (to_child == NULL) 1234 | { 1235 | diff = -1; 1236 | } 1237 | else 1238 | { 1239 | diff = compare_strings((unsigned char*)from_child->string, (unsigned char*)to_child->string, case_sensitive); 1240 | } 1241 | 1242 | if (diff == 0) 1243 | { 1244 | /* both object keys are the same */ 1245 | size_t path_length = strlen((const char*)path); 1246 | size_t from_child_name_length = pointer_encoded_length((unsigned char*)from_child->string); 1247 | unsigned char *new_path = (unsigned char*)cJSON_malloc(path_length + from_child_name_length + sizeof("/")); 1248 | 1249 | sprintf((char*)new_path, "%s/", path); 1250 | encode_string_as_pointer(new_path + path_length + 1, (unsigned char*)from_child->string); 1251 | 1252 | /* create a patch for the element */ 1253 | create_patches(patches, new_path, from_child, to_child, case_sensitive); 1254 | cJSON_free(new_path); 1255 | 1256 | from_child = from_child->next; 1257 | to_child = to_child->next; 1258 | } 1259 | else if (diff < 0) 1260 | { 1261 | /* object element doesn't exist in 'to' --> remove it */ 1262 | compose_patch(patches, (const unsigned char*)"remove", path, (unsigned char*)from_child->string, NULL); 1263 | 1264 | from_child = from_child->next; 1265 | } 1266 | else 1267 | { 1268 | /* object element doesn't exist in 'from' --> add it */ 1269 | compose_patch(patches, (const unsigned char*)"add", path, (unsigned char*)to_child->string, to_child); 1270 | 1271 | to_child = to_child->next; 1272 | } 1273 | } 1274 | return; 1275 | } 1276 | 1277 | default: 1278 | break; 1279 | } 1280 | } 1281 | 1282 | CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to) 1283 | { 1284 | cJSON *patches = NULL; 1285 | 1286 | if ((from == NULL) || (to == NULL)) 1287 | { 1288 | return NULL; 1289 | } 1290 | 1291 | patches = cJSON_CreateArray(); 1292 | create_patches(patches, (const unsigned char*)"", from, to, false); 1293 | 1294 | return patches; 1295 | } 1296 | 1297 | CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to) 1298 | { 1299 | cJSON *patches = NULL; 1300 | 1301 | if ((from == NULL) || (to == NULL)) 1302 | { 1303 | return NULL; 1304 | } 1305 | 1306 | patches = cJSON_CreateArray(); 1307 | create_patches(patches, (const unsigned char*)"", from, to, true); 1308 | 1309 | return patches; 1310 | } 1311 | 1312 | CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object) 1313 | { 1314 | sort_object(object, false); 1315 | } 1316 | 1317 | CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object) 1318 | { 1319 | sort_object(object, true); 1320 | } 1321 | 1322 | static cJSON *merge_patch(cJSON *target, const cJSON * const patch, const cJSON_bool case_sensitive) 1323 | { 1324 | cJSON *patch_child = NULL; 1325 | 1326 | if (!cJSON_IsObject(patch)) 1327 | { 1328 | /* scalar value, array or NULL, just duplicate */ 1329 | cJSON_Delete(target); 1330 | return cJSON_Duplicate(patch, 1); 1331 | } 1332 | 1333 | if (!cJSON_IsObject(target)) 1334 | { 1335 | cJSON_Delete(target); 1336 | target = cJSON_CreateObject(); 1337 | } 1338 | 1339 | patch_child = patch->child; 1340 | while (patch_child != NULL) 1341 | { 1342 | if (cJSON_IsNull(patch_child)) 1343 | { 1344 | /* NULL is the indicator to remove a value, see RFC7396 */ 1345 | if (case_sensitive) 1346 | { 1347 | cJSON_DeleteItemFromObjectCaseSensitive(target, patch_child->string); 1348 | } 1349 | else 1350 | { 1351 | cJSON_DeleteItemFromObject(target, patch_child->string); 1352 | } 1353 | } 1354 | else 1355 | { 1356 | cJSON *replace_me = NULL; 1357 | cJSON *replacement = NULL; 1358 | 1359 | if (case_sensitive) 1360 | { 1361 | replace_me = cJSON_DetachItemFromObjectCaseSensitive(target, patch_child->string); 1362 | } 1363 | else 1364 | { 1365 | replace_me = cJSON_DetachItemFromObject(target, patch_child->string); 1366 | } 1367 | 1368 | replacement = merge_patch(replace_me, patch_child, case_sensitive); 1369 | if (replacement == NULL) 1370 | { 1371 | cJSON_Delete(target); 1372 | return NULL; 1373 | } 1374 | 1375 | cJSON_AddItemToObject(target, patch_child->string, replacement); 1376 | } 1377 | patch_child = patch_child->next; 1378 | } 1379 | return target; 1380 | } 1381 | 1382 | CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch) 1383 | { 1384 | return merge_patch(target, patch, false); 1385 | } 1386 | 1387 | CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch) 1388 | { 1389 | return merge_patch(target, patch, true); 1390 | } 1391 | 1392 | static cJSON *generate_merge_patch(cJSON * const from, cJSON * const to, const cJSON_bool case_sensitive) 1393 | { 1394 | cJSON *from_child = NULL; 1395 | cJSON *to_child = NULL; 1396 | cJSON *patch = NULL; 1397 | if (to == NULL) 1398 | { 1399 | /* patch to delete everything */ 1400 | return cJSON_CreateNull(); 1401 | } 1402 | if (!cJSON_IsObject(to) || !cJSON_IsObject(from)) 1403 | { 1404 | return cJSON_Duplicate(to, 1); 1405 | } 1406 | 1407 | sort_object(from, case_sensitive); 1408 | sort_object(to, case_sensitive); 1409 | 1410 | from_child = from->child; 1411 | to_child = to->child; 1412 | patch = cJSON_CreateObject(); 1413 | if (patch == NULL) 1414 | { 1415 | return NULL; 1416 | } 1417 | while (from_child || to_child) 1418 | { 1419 | int diff; 1420 | if (from_child != NULL) 1421 | { 1422 | if (to_child != NULL) 1423 | { 1424 | diff = strcmp(from_child->string, to_child->string); 1425 | } 1426 | else 1427 | { 1428 | diff = -1; 1429 | } 1430 | } 1431 | else 1432 | { 1433 | diff = 1; 1434 | } 1435 | 1436 | if (diff < 0) 1437 | { 1438 | /* from has a value that to doesn't have -> remove */ 1439 | cJSON_AddItemToObject(patch, from_child->string, cJSON_CreateNull()); 1440 | 1441 | from_child = from_child->next; 1442 | } 1443 | else if (diff > 0) 1444 | { 1445 | /* to has a value that from doesn't have -> add to patch */ 1446 | cJSON_AddItemToObject(patch, to_child->string, cJSON_Duplicate(to_child, 1)); 1447 | 1448 | to_child = to_child->next; 1449 | } 1450 | else 1451 | { 1452 | /* object key exists in both objects */ 1453 | if (!compare_json(from_child, to_child, case_sensitive)) 1454 | { 1455 | /* not identical --> generate a patch */ 1456 | cJSON_AddItemToObject(patch, to_child->string, cJSONUtils_GenerateMergePatch(from_child, to_child)); 1457 | } 1458 | 1459 | /* next key in the object */ 1460 | from_child = from_child->next; 1461 | to_child = to_child->next; 1462 | } 1463 | } 1464 | if (patch->child == NULL) 1465 | { 1466 | /* no patch generated */ 1467 | cJSON_Delete(patch); 1468 | return NULL; 1469 | } 1470 | 1471 | return patch; 1472 | } 1473 | 1474 | CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to) 1475 | { 1476 | return generate_merge_patch(from, to, false); 1477 | } 1478 | 1479 | CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to) 1480 | { 1481 | return generate_merge_patch(from, to, true); 1482 | } 1483 | -------------------------------------------------------------------------------- /cJSON_Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 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_Utils__h 24 | #define cJSON_Utils__h 25 | 26 | #ifdef __cplusplus 27 | extern "C" 28 | { 29 | #endif 30 | 31 | #include "cJSON.h" 32 | 33 | /* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ 34 | CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON * const object, const char *pointer); 35 | CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointerCaseSensitive(cJSON * const object, const char *pointer); 36 | 37 | /* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ 38 | /* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ 39 | CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON * const from, cJSON * const to); 40 | CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatchesCaseSensitive(cJSON * const from, cJSON * const to); 41 | /* Utility for generating patch array entries. */ 42 | CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON * const array, const char * const operation, const char * const path, const cJSON * const value); 43 | /* Returns 0 for success. */ 44 | CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON * const object, const cJSON * const patches); 45 | CJSON_PUBLIC(int) cJSONUtils_ApplyPatchesCaseSensitive(cJSON * const object, const cJSON * const patches); 46 | 47 | /* 48 | // Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use: 49 | //int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches) 50 | //{ 51 | // cJSON *modme = cJSON_Duplicate(*object, 1); 52 | // int error = cJSONUtils_ApplyPatches(modme, patches); 53 | // if (!error) 54 | // { 55 | // cJSON_Delete(*object); 56 | // *object = modme; 57 | // } 58 | // else 59 | // { 60 | // cJSON_Delete(modme); 61 | // } 62 | // 63 | // return error; 64 | //} 65 | // Code not added to library since this strategy is a LOT slower. 66 | */ 67 | 68 | /* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */ 69 | /* target will be modified by patch. return value is new ptr for target. */ 70 | CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, const cJSON * const patch); 71 | CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatchCaseSensitive(cJSON *target, const cJSON * const patch); 72 | /* generates a patch to move from -> to */ 73 | /* NOTE: This modifies objects in 'from' and 'to' by sorting the elements by their key */ 74 | CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON * const from, cJSON * const to); 75 | CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatchCaseSensitive(cJSON * const from, cJSON * const to); 76 | 77 | /* Given a root object and a target object, construct a pointer from one to the other. */ 78 | CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(const cJSON * const object, const cJSON * const target); 79 | 80 | /* Sorts the members of the object into alphabetical order. */ 81 | CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON * const object); 82 | CJSON_PUBLIC(void) cJSONUtils_SortObjectCaseSensitive(cJSON * const object); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /cJSON_util.h: -------------------------------------------------------------------------------- 1 | #include "cJSON_Utils.h" 2 | --------------------------------------------------------------------------------