├── .codespellrc ├── .github ├── dependabot.yml └── workflows │ ├── check-arduino.yml │ ├── compile-examples.yml │ ├── report-size-deltas.yml │ ├── spell-check.yml │ └── sync-labels.yml ├── LICENSE.txt ├── README.adoc ├── examples ├── JSONArray │ └── JSONArray.ino ├── JSONKitchenSink │ └── JSONKitchenSink.ino ├── JSONObject │ └── JSONObject.ino └── JSONValueExtractor │ └── JSONValueExtractor.ino ├── keywords.txt ├── library.properties └── src ├── Arduino_JSON.h ├── JSON.cpp ├── JSON.h ├── JSONVar.cpp ├── JSONVar.h └── cjson ├── LICENSE ├── cJSON.c └── cJSON.h /.codespellrc: -------------------------------------------------------------------------------- 1 | # See: https://github.com/codespell-project/codespell#using-a-config-file 2 | [codespell] 3 | # In the event of a false positive, add the problematic word, in all lowercase, to a comma-separated list here: 4 | ignore-words-list = writen 5 | check-filenames = 6 | check-hidden = 7 | skip = ./.git,./src/cjson 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # See: https://docs.github.com/en/github/administering-a-repository/configuration-options-for-dependency-updates#about-the-dependabotyml-file 2 | version: 2 3 | 4 | updates: 5 | # Configure check for outdated GitHub Actions actions in workflows. 6 | # See: https://docs.github.com/en/github/administering-a-repository/keeping-your-actions-up-to-date-with-dependabot 7 | - package-ecosystem: github-actions 8 | directory: / # Check the repository's workflows under /.github/workflows/ 9 | schedule: 10 | interval: daily 11 | labels: 12 | - "topic: infrastructure" 13 | -------------------------------------------------------------------------------- /.github/workflows/check-arduino.yml: -------------------------------------------------------------------------------- 1 | name: Check Arduino 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | pull_request: 7 | schedule: 8 | # Run every Tuesday at 8 AM UTC to catch breakage caused by new rules added to Arduino Lint. 9 | - cron: "0 8 * * TUE" 10 | workflow_dispatch: 11 | repository_dispatch: 12 | 13 | jobs: 14 | lint: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Arduino Lint 22 | uses: arduino/arduino-lint-action@v2 23 | with: 24 | compliance: strict 25 | library-manager: update 26 | # Always use this setting for official repositories. Remove for 3rd party projects. 27 | official: true 28 | project-type: library 29 | -------------------------------------------------------------------------------- /.github/workflows/compile-examples.yml: -------------------------------------------------------------------------------- 1 | name: Compile Examples 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/compile-examples.yml" 8 | - "library.properties" 9 | - "examples/**" 10 | - "src/**" 11 | pull_request: 12 | paths: 13 | - ".github/workflows/compile-examples.yml" 14 | - "library.properties" 15 | - "examples/**" 16 | - "src/**" 17 | schedule: 18 | # Run every Tuesday at 8 AM UTC to catch breakage caused by changes to external resources (libraries, platforms). 19 | - cron: "0 8 * * TUE" 20 | workflow_dispatch: 21 | repository_dispatch: 22 | 23 | jobs: 24 | build: 25 | name: ${{ matrix.board.fqbn }} 26 | runs-on: ubuntu-latest 27 | 28 | env: 29 | SKETCHES_REPORTS_PATH: sketches-reports 30 | 31 | strategy: 32 | fail-fast: false 33 | 34 | matrix: 35 | board: 36 | - fqbn: arduino:avr:nano 37 | platforms: | 38 | - name: arduino:avr 39 | artifact-name-suffix: arduino-avr-nano 40 | - fqbn: arduino:avr:mega 41 | platforms: | 42 | - name: arduino:avr 43 | artifact-name-suffix: arduino-avr-mega 44 | - fqbn: arduino:avr:leonardo 45 | platforms: | 46 | - name: arduino:avr 47 | artifact-name-suffix: arduino-avr-leonardo 48 | - fqbn: arduino:avr:yun 49 | platforms: | 50 | - name: arduino:avr 51 | artifact-name-suffix: arduino-avr-yun 52 | - fqbn: arduino:megaavr:uno2018 53 | platforms: | 54 | - name: arduino:megaavr 55 | artifact-name-suffix: arduino-megaavr-uno2018 56 | - fqbn: arduino:megaavr:nona4809 57 | platforms: | 58 | - name: arduino:megaavr 59 | artifact-name-suffix: arduino-megaavr-nona4809 60 | - fqbn: arduino:sam:arduino_due_x_dbg 61 | platforms: | 62 | - name: arduino:sam 63 | artifact-name-suffix: arduino-sam-arduino_due_x_dbg 64 | - fqbn: arduino:samd:arduino_zero_edbg 65 | platforms: | 66 | - name: arduino:samd 67 | artifact-name-suffix: arduino-samd-arduino_zero_edbg 68 | - fqbn: arduino:samd:mkrzero 69 | platforms: | 70 | - name: arduino:samd 71 | artifact-name-suffix: arduino-samd-mkrzero 72 | - fqbn: arduino:samd:nano_33_iot 73 | platforms: | 74 | - name: arduino:samd 75 | artifact-name-suffix: arduino-samd-nano_33_iot 76 | - fqbn: arduino:mbed_portenta:envie_m7:target_core=cm4 77 | platforms: | 78 | - name: arduino:mbed_portenta 79 | artifact-name-suffix: arduino-mbed_portenta-envie_m7-target_core-cm4 80 | - fqbn: arduino:mbed_portenta:envie_m7 81 | platforms: | 82 | - name: arduino:mbed_portenta 83 | artifact-name-suffix: arduino-mbed_portenta-envie_m7 84 | - fqbn: arduino:mbed_edge:edge_control 85 | platforms: | 86 | - name: arduino:mbed_edge 87 | artifact-name-suffix: arduino-mbed_edge-edge_control 88 | - fqbn: arduino:mbed_nano:nano33ble 89 | platforms: | 90 | - name: arduino:mbed_nano 91 | artifact-name-suffix: arduino-mbed_nano-nano33ble 92 | - fqbn: arduino:mbed_nano:nanorp2040connect 93 | platforms: | 94 | - name: arduino:mbed_nano 95 | artifact-name-suffix: arduino-mbed_nano-nanorp2040connect 96 | 97 | steps: 98 | - name: Checkout repository 99 | uses: actions/checkout@v4 100 | 101 | - name: Compile examples 102 | uses: arduino/compile-sketches@v1 103 | with: 104 | github-token: ${{ secrets.GITHUB_TOKEN }} 105 | fqbn: ${{ matrix.board.fqbn }} 106 | platforms: ${{ matrix.board.platforms }} 107 | libraries: | 108 | # Install the library from the local path. 109 | - source-path: ./ 110 | # Additional library dependencies can be listed here. 111 | # See: https://github.com/arduino/compile-sketches#libraries 112 | sketch-paths: | 113 | - examples 114 | enable-deltas-report: true 115 | sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} 116 | 117 | - name: Save sketches report as workflow artifact 118 | uses: actions/upload-artifact@v4 119 | with: 120 | if-no-files-found: error 121 | path: ${{ env.SKETCHES_REPORTS_PATH }} 122 | name: sketches-report-${{ matrix.board.artifact-name-suffix }} 123 | -------------------------------------------------------------------------------- /.github/workflows/report-size-deltas.yml: -------------------------------------------------------------------------------- 1 | name: Report Size Deltas 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | paths: 7 | - ".github/workflows/report-size-deltas.yml" 8 | schedule: 9 | # Run at the minimum interval allowed by GitHub Actions. 10 | # Note: GitHub Actions periodically has outages which result in workflow failures. 11 | # In this event, the workflows will start passing again once the service recovers. 12 | - cron: "*/5 * * * *" 13 | workflow_dispatch: 14 | repository_dispatch: 15 | 16 | jobs: 17 | report: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Comment size deltas reports to PRs 21 | uses: arduino/report-size-deltas@v1 22 | with: 23 | # Regex matching the names of the workflow artifacts created by the "Compile Examples" workflow 24 | sketches-reports-source: ^sketches-report-.+ 25 | -------------------------------------------------------------------------------- /.github/workflows/spell-check.yml: -------------------------------------------------------------------------------- 1 | name: Spell Check 2 | 3 | # See: https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows 4 | on: 5 | push: 6 | pull_request: 7 | schedule: 8 | # Run every Tuesday at 8 AM UTC to catch new misspelling detections resulting from dictionary updates. 9 | - cron: "0 8 * * TUE" 10 | workflow_dispatch: 11 | repository_dispatch: 12 | 13 | jobs: 14 | spellcheck: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Spell check 22 | uses: codespell-project/actions-codespell@master 23 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md 2 | name: Sync Labels 3 | 4 | # See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows 5 | on: 6 | push: 7 | paths: 8 | - ".github/workflows/sync-labels.ya?ml" 9 | - ".github/label-configuration-files/*.ya?ml" 10 | pull_request: 11 | paths: 12 | - ".github/workflows/sync-labels.ya?ml" 13 | - ".github/label-configuration-files/*.ya?ml" 14 | schedule: 15 | # Run daily at 8 AM UTC to sync with changes to shared label configurations. 16 | - cron: "0 8 * * *" 17 | workflow_dispatch: 18 | repository_dispatch: 19 | 20 | env: 21 | CONFIGURATIONS_FOLDER: .github/label-configuration-files 22 | CONFIGURATIONS_ARTIFACT: label-configuration-files 23 | 24 | jobs: 25 | check: 26 | runs-on: ubuntu-latest 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v4 31 | 32 | - name: Download JSON schema for labels configuration file 33 | id: download-schema 34 | uses: carlosperate/download-file-action@v2 35 | with: 36 | file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json 37 | location: ${{ runner.temp }}/label-configuration-schema 38 | 39 | - name: Install JSON schema validator 40 | run: | 41 | sudo npm install \ 42 | --global \ 43 | ajv-cli \ 44 | ajv-formats 45 | 46 | - name: Validate local labels configuration 47 | run: | 48 | # See: https://github.com/ajv-validator/ajv-cli#readme 49 | ajv validate \ 50 | --all-errors \ 51 | -c ajv-formats \ 52 | -s "${{ steps.download-schema.outputs.file-path }}" \ 53 | -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}" 54 | 55 | download: 56 | needs: check 57 | runs-on: ubuntu-latest 58 | 59 | strategy: 60 | matrix: 61 | filename: 62 | # Filenames of the shared configurations to apply to the repository in addition to the local configuration. 63 | # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels 64 | - universal.yml 65 | 66 | steps: 67 | - name: Download 68 | uses: carlosperate/download-file-action@v2 69 | with: 70 | file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }} 71 | 72 | - name: Pass configuration files to next job via workflow artifact 73 | uses: actions/upload-artifact@v4 74 | with: 75 | path: | 76 | *.yaml 77 | *.yml 78 | if-no-files-found: error 79 | name: ${{ env.CONFIGURATIONS_ARTIFACT }} 80 | 81 | sync: 82 | needs: download 83 | runs-on: ubuntu-latest 84 | 85 | steps: 86 | - name: Set environment variables 87 | run: | 88 | # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable 89 | echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV" 90 | 91 | - name: Determine whether to dry run 92 | id: dry-run 93 | if: > 94 | github.event_name == 'pull_request' || 95 | ( 96 | ( 97 | github.event_name == 'push' || 98 | github.event_name == 'workflow_dispatch' 99 | ) && 100 | github.ref != format('refs/heads/{0}', github.event.repository.default_branch) 101 | ) 102 | run: | 103 | # Use of this flag in the github-label-sync command will cause it to only check the validity of the 104 | # configuration. 105 | echo "::set-output name=flag::--dry-run" 106 | 107 | - name: Checkout repository 108 | uses: actions/checkout@v4 109 | 110 | - name: Download configuration files artifact 111 | uses: actions/download-artifact@v4 112 | with: 113 | name: ${{ env.CONFIGURATIONS_ARTIFACT }} 114 | path: ${{ env.CONFIGURATIONS_FOLDER }} 115 | 116 | - name: Remove unneeded artifact 117 | uses: geekyeggo/delete-artifact@v5 118 | with: 119 | name: ${{ env.CONFIGURATIONS_ARTIFACT }} 120 | 121 | - name: Merge label configuration files 122 | run: | 123 | # Merge all configuration files 124 | shopt -s extglob 125 | cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}" 126 | 127 | - name: Install github-label-sync 128 | run: sudo npm install --global github-label-sync 129 | 130 | - name: Sync labels 131 | env: 132 | GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} 133 | run: | 134 | # See: https://github.com/Financial-Times/github-label-sync 135 | github-label-sync \ 136 | --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \ 137 | ${{ steps.dry-run.outputs.flag }} \ 138 | ${{ github.repository }} 139 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | :repository-owner: arduino-libraries 2 | :repository-name: Arduino_JSON 3 | 4 | = {repository-name} Library for Arduino = 5 | 6 | image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-arduino.yml/badge.svg["Check Arduino status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/check-arduino.yml"] 7 | image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/compile-examples.yml/badge.svg["Compile Examples status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/compile-examples.yml"] 8 | image:https://github.com/{repository-owner}/{repository-name}/actions/workflows/spell-check.yml/badge.svg["Spell Check status", link="https://github.com/{repository-owner}/{repository-name}/actions/workflows/spell-check.yml"] 9 | 10 | Process JSON in your Arduino sketches. 11 | 12 | This library is based on https://github.com/DaveGamble/cJSON[cJSON]. 13 | 14 | == License == 15 | 16 | Copyright (c) 2019 Arduino SA. All rights reserved. 17 | 18 | This library is free software; you can redistribute it and/or 19 | modify it under the terms of the GNU Lesser General Public 20 | License as published by the Free Software Foundation; either 21 | version 2.1 of the License, or (at your option) any later version. 22 | 23 | This library is distributed in the hope that it will be useful, 24 | but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 26 | Lesser General Public License for more details. 27 | 28 | You should have received a copy of the GNU Lesser General Public 29 | License along with this library; if not, write to the Free Software 30 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 31 | -------------------------------------------------------------------------------- /examples/JSONArray/JSONArray.ino: -------------------------------------------------------------------------------- 1 | /* 2 | JSON Array 3 | 4 | This sketch demonstrates how to use various features 5 | of the Official Arduino_JSON library, in particular for JSON arrays. 6 | 7 | This example code is in the public domain. 8 | */ 9 | 10 | #include 11 | 12 | const char input[] = "[true, 42, \"apple\"]"; 13 | 14 | void setup() { 15 | Serial.begin(9600); 16 | while (!Serial); 17 | 18 | demoParse(); 19 | 20 | demoCreation(); 21 | } 22 | 23 | void loop() { 24 | } 25 | 26 | void demoParse() { 27 | Serial.println("parse"); 28 | Serial.println("====="); 29 | 30 | JSONVar myArray = JSON.parse(input); 31 | 32 | // JSON.typeof(jsonVar) can be used to get the type of the variable 33 | if (JSON.typeof(myArray) == "undefined") { 34 | Serial.println("Parsing input failed!"); 35 | return; 36 | } 37 | 38 | Serial.print("JSON.typeof(myArray) = "); 39 | Serial.println(JSON.typeof(myArray)); // prints: array 40 | 41 | // myArray.length() can be used to get the length of the array 42 | Serial.print("myArray.length() = "); 43 | Serial.println(myArray.length()); 44 | Serial.println(); 45 | 46 | Serial.print("JSON.typeof(myArray[0]) = "); 47 | Serial.println(JSON.typeof(myArray[0])); 48 | 49 | Serial.print("myArray[0] = "); 50 | Serial.println(myArray[0]); 51 | Serial.println(); 52 | 53 | Serial.print("myArray[1] = "); 54 | Serial.println((int) myArray[1]); 55 | Serial.println(); 56 | 57 | Serial.print("myArray[2] = "); 58 | Serial.println((const char*) myArray[2]); 59 | Serial.println(); 60 | 61 | Serial.println(); 62 | } 63 | 64 | void demoCreation() { 65 | Serial.println("creation"); 66 | Serial.println("========"); 67 | 68 | JSONVar myArray; 69 | 70 | myArray[0] = false; 71 | myArray[1] = 4242.5; 72 | myArray[2] = "orange"; 73 | myArray[3] = "world"; 74 | myArray[4] = true; 75 | myArray[5] = 42; 76 | 77 | Serial.print("myArray.length() = "); 78 | Serial.println(myArray.length()); 79 | 80 | // JSON.stringify(myVar) can be used to convert the JSONVar to a String 81 | String jsonString = JSON.stringify(myArray); 82 | 83 | Serial.print("JSON.stringify(myArray) = "); 84 | Serial.println(jsonString); 85 | Serial.println(); 86 | 87 | for (int i = 0; i < myArray.length(); i++) { 88 | JSONVar value = myArray[i]; 89 | 90 | Serial.print("JSON.typeof(myArray["); 91 | Serial.print(i); 92 | Serial.print("]) = "); 93 | Serial.println(JSON.typeof(value)); 94 | 95 | Serial.print("myArray["); 96 | Serial.print(i); 97 | Serial.print("] = "); 98 | Serial.println(value); 99 | 100 | Serial.println(); 101 | } 102 | 103 | Serial.println(); 104 | } 105 | -------------------------------------------------------------------------------- /examples/JSONKitchenSink/JSONKitchenSink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | JSON Kitchen Sink 3 | 4 | This sketch demonstrates how to use various features 5 | of the Official Arduino_JSON library. 6 | 7 | This example code is in the public domain. 8 | */ 9 | 10 | #include 11 | 12 | void setup() { 13 | Serial.begin(9600); 14 | while (!Serial); 15 | 16 | // boolean 17 | booleanDemo(); 18 | 19 | intDemo(); 20 | 21 | doubleDemo(); 22 | 23 | stringDemo(); 24 | 25 | arrayDemo(); 26 | 27 | objectDemo(); 28 | } 29 | 30 | void loop() { 31 | } 32 | 33 | void booleanDemo() { 34 | Serial.println("boolean"); 35 | Serial.println("======="); 36 | 37 | JSONVar myBoolean = true; 38 | 39 | Serial.print("JSON.typeof(myBoolean) = "); 40 | Serial.println(JSON.typeof(myBoolean)); // prints: boolean 41 | 42 | Serial.print("myBoolean = "); 43 | Serial.println(myBoolean); // prints: true 44 | 45 | myBoolean = false; 46 | 47 | Serial.print("myBoolean = "); 48 | Serial.println((boolean) myBoolean); // prints: 0 49 | 50 | Serial.println(); 51 | } 52 | 53 | void intDemo() { 54 | Serial.println("int"); 55 | Serial.println("==="); 56 | 57 | JSONVar myInt = 42; 58 | 59 | Serial.print("JSON.typeof(myInt) = "); 60 | Serial.println(JSON.typeof(myInt)); // prints: number 61 | 62 | Serial.print("myInt = "); 63 | Serial.println(myInt); // prints: 42 64 | 65 | myInt = 4242; 66 | 67 | Serial.print("myInt = "); 68 | Serial.println((int) myInt); // prints: 4242 69 | 70 | Serial.println(); 71 | } 72 | 73 | void doubleDemo() { 74 | Serial.println("double"); 75 | Serial.println("======"); 76 | 77 | JSONVar myDouble = 42.5; 78 | 79 | Serial.print("JSON.typeof(myDouble) = "); 80 | Serial.println(JSON.typeof(myDouble)); // prints: number 81 | 82 | Serial.print("myDouble = "); 83 | Serial.println(myDouble); // prints: 42.5 84 | 85 | myDouble = 4242.4242; 86 | 87 | Serial.print("myDouble = "); 88 | Serial.println((double) myDouble, 4); // prints: 4242.4242 89 | 90 | Serial.println(); 91 | } 92 | 93 | void stringDemo() { 94 | Serial.println("string"); 95 | Serial.println("======"); 96 | 97 | JSONVar myString = "Hello World!"; 98 | 99 | Serial.print("JSON.typeof(myString) = "); 100 | Serial.println(JSON.typeof(myString)); // prints: string 101 | 102 | Serial.print("myString = "); 103 | Serial.println(myString); // prints: Hello World! 104 | 105 | myString = ":)"; 106 | 107 | Serial.print("myString = "); 108 | Serial.println((const char*) myString); // prints: :) 109 | 110 | Serial.println(); 111 | } 112 | 113 | void arrayDemo() { 114 | Serial.println("array"); 115 | Serial.println("====="); 116 | 117 | JSONVar myArray; 118 | 119 | myArray[0] = 42; 120 | 121 | Serial.print("JSON.typeof(myArray) = "); 122 | Serial.println(JSON.typeof(myArray)); // prints: array 123 | 124 | Serial.print("myArray = "); 125 | Serial.println(myArray); // prints: [42] 126 | 127 | Serial.print("myArray[0] = "); 128 | Serial.println((int)myArray[0]); // prints: 42 129 | 130 | myArray[1] = 42.5; 131 | 132 | Serial.print("myArray = "); 133 | Serial.println(myArray); // prints: [42,42.5] 134 | 135 | Serial.print("myArray[1] = "); 136 | Serial.println((double)myArray[1]); // prints: 42.50 137 | 138 | Serial.println(); 139 | } 140 | 141 | void objectDemo() { 142 | Serial.println("object"); 143 | Serial.println("======"); 144 | 145 | JSONVar myObject; 146 | 147 | myObject["foo"] = "bar"; 148 | 149 | Serial.print("JSON.typeof(myObject) = "); 150 | Serial.println(JSON.typeof(myObject)); // prints: object 151 | 152 | Serial.print("myObject.keys() = "); 153 | Serial.println(myObject.keys()); // prints: ["foo"] 154 | 155 | Serial.print("myObject = "); 156 | Serial.println(myObject); // prints: {"foo":"bar"} 157 | 158 | myObject["blah"]["abc"] = 42; 159 | 160 | Serial.print("myObject.keys() = "); 161 | Serial.println(myObject.keys()); // prints: ["foo","blah"] 162 | 163 | Serial.print("myObject = "); 164 | Serial.println(myObject); // prints: {"foo":"bar","blah":{"abc":42}} 165 | } 166 | -------------------------------------------------------------------------------- /examples/JSONObject/JSONObject.ino: -------------------------------------------------------------------------------- 1 | /* 2 | JSON Object 3 | 4 | This sketch demonstrates how to use various features 5 | of the Official Arduino_JSON library, in particular for JSON objects. 6 | 7 | This example code is in the public domain. 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | const char input[] = "{\"result\":true,\"count\":42,\"foo\":\"bar\"}"; 14 | 15 | void setup() { 16 | Serial.begin(9600); 17 | while (!Serial); 18 | 19 | demoParse(); 20 | 21 | demoCreation(); 22 | } 23 | 24 | void loop() { 25 | } 26 | 27 | void demoParse() { 28 | Serial.println("parse"); 29 | Serial.println("====="); 30 | 31 | JSONVar myObject = JSON.parse(input); 32 | 33 | // JSON.typeof(jsonVar) can be used to get the type of the variable 34 | if (JSON.typeof(myObject) == "undefined") { 35 | Serial.println("Parsing input failed!"); 36 | return; 37 | } 38 | 39 | Serial.print("JSON.typeof(myObject) = "); 40 | Serial.println(JSON.typeof(myObject)); // prints: object 41 | 42 | // myObject.hasOwnProperty(key) checks if the object contains an entry for key 43 | if (myObject.hasOwnProperty("result")) { 44 | Serial.print("myObject[\"result\"] = "); 45 | 46 | Serial.println((bool) myObject["result"]); 47 | } 48 | 49 | if (myObject.hasOwnProperty("count")) { 50 | Serial.print("myObject[\"count\"] = "); 51 | 52 | Serial.println((int) myObject["count"]); 53 | } 54 | 55 | if (myObject.hasOwnProperty("count")) { 56 | Serial.print("myObject[\"count\"] = "); 57 | 58 | Serial.println((double) myObject["count"]); 59 | } 60 | 61 | if (myObject.hasOwnProperty("foo")) { 62 | Serial.print("myObject[\"foo\"] = "); 63 | 64 | Serial.println((const char*) myObject["foo"]); 65 | } 66 | 67 | // JSONVars can be printed using print or println 68 | Serial.print("myObject = "); 69 | Serial.println(myObject); 70 | 71 | Serial.println(); 72 | } 73 | 74 | void demoCreation() { 75 | Serial.println("creation"); 76 | Serial.println("========"); 77 | 78 | JSONVar myObject; 79 | 80 | myObject["hello"] = "world"; 81 | myObject["true"] = true; 82 | 83 | myObject["x1"] = (int) 42; 84 | myObject["x2"] = (long) 42; 85 | myObject["x3"] = (unsigned long) 42; 86 | 87 | int x1 = myObject["x1"]; 88 | assert(x1 == 42); 89 | 90 | long x2 = myObject["x2"]; 91 | assert(x2 == 42); 92 | 93 | unsigned long x3 = myObject["x3"]; 94 | assert(x3 == 42); 95 | 96 | Serial.print("myObject.keys() = "); 97 | Serial.println(myObject.keys()); 98 | 99 | // JSON.stringify(myVar) can be used to convert the JSONVar to a String 100 | String jsonString = JSON.stringify(myObject); 101 | 102 | Serial.print("JSON.stringify(myObject) = "); 103 | Serial.println(jsonString); 104 | 105 | Serial.println(); 106 | 107 | // myObject.keys() can be used to get an array of all the keys in the object 108 | JSONVar keys = myObject.keys(); 109 | 110 | for (int i = 0; i < keys.length(); i++) { 111 | JSONVar value = myObject[keys[i]]; 112 | 113 | Serial.print("JSON.typeof(myObject["); 114 | Serial.print(keys[i]); 115 | Serial.print("]) = "); 116 | Serial.println(JSON.typeof(value)); 117 | 118 | Serial.print("myObject["); 119 | Serial.print(keys[i]); 120 | Serial.print("] = "); 121 | Serial.println(value); 122 | 123 | Serial.println(); 124 | } 125 | 126 | Serial.println(); 127 | 128 | // setting a value to undefined can remove it from the object 129 | myObject["x"] = undefined; 130 | 131 | // you can also change a value 132 | myObject["hello"] = "there!"; 133 | 134 | Serial.print("myObject = "); 135 | Serial.println(myObject); 136 | } 137 | -------------------------------------------------------------------------------- /examples/JSONValueExtractor/JSONValueExtractor.ino: -------------------------------------------------------------------------------- 1 | /* 2 | JSON Value Extractor 3 | 4 | This sketch demonstrates how to use some features 5 | of the Official Arduino JSON library to traverse through all the 6 | key value pair in the object and the nested objects. 7 | Can be very helpful when searching for a specific data in a key 8 | which is nested at multiple levels 9 | The sketch actually use recursion to traverse all the keys in 10 | a given JSON. 11 | 12 | Example originally added on 24-03-2020 13 | by Madhur Dixit https://github.com/Chester-King 14 | 15 | This example code is in the public domain. 16 | */ 17 | 18 | #include 19 | 20 | void setup() { 21 | 22 | Serial.begin(9600); 23 | while (!Serial); 24 | valueExtractor(); 25 | 26 | } 27 | 28 | void loop() { 29 | } 30 | 31 | void valueExtractor() { 32 | 33 | Serial.println("object"); 34 | Serial.println("======"); 35 | JSONVar myObject; 36 | 37 | // Making a JSON Object 38 | myObject["foo"] = "bar"; 39 | myObject["blah"]["abc"] = 42; 40 | myObject["blah"]["efg"] = "pod"; 41 | myObject["blah"]["cde"]["pan1"] = "King"; 42 | myObject["blah"]["cde"]["pan2"] = 3.14; 43 | myObject["jok"]["hij"] = "bar"; 44 | 45 | Serial.println(myObject); 46 | Serial.println(); 47 | Serial.println("Extracted Values"); 48 | Serial.println("======"); 49 | 50 | objRec(myObject); 51 | 52 | } 53 | 54 | void objRec(JSONVar myObject) { 55 | Serial.println("{"); 56 | for (int x = 0; x < myObject.keys().length(); x++) { 57 | if ((JSON.typeof(myObject[myObject.keys()[x]])).equals("object")) { 58 | Serial.print(myObject.keys()[x]); 59 | Serial.println(" : "); 60 | objRec(myObject[myObject.keys()[x]]); 61 | } 62 | else { 63 | Serial.print(myObject.keys()[x]); 64 | Serial.print(" : "); 65 | Serial.println(myObject[myObject.keys()[x]]); 66 | } 67 | } 68 | Serial.println("}"); 69 | } 70 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For Arduino_JSON 3 | ####################################### 4 | # Class 5 | ####################################### 6 | 7 | Arduino_JSON KEYWORD1 8 | JSON KEYWORD1 9 | JSONVar KEYWORD1 10 | var KEYWORD1 11 | null KEYWORD1 12 | undefined KEYWORD1 13 | 14 | ####################################### 15 | # Methods and Functions 16 | ####################################### 17 | 18 | typeof KEYWORD2 19 | parse KEYWORD2 20 | stringify KEYWORD2 21 | 22 | length KEYWORD2 23 | keys KEYWORD2 24 | hasOwnProperty KEYWORD2 25 | 26 | ####################################### 27 | # Constants 28 | ####################################### 29 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Arduino_JSON 2 | version=0.2.0 3 | author=Arduino 4 | maintainer=Arduino 5 | sentence=[BETA] Process JSON in your Arduino sketches. 6 | paragraph= 7 | category=Other 8 | url=http://github.com/arduino-libraries/Arduino_JSON 9 | architectures=* 10 | includes=Arduino_JSON.h 11 | -------------------------------------------------------------------------------- /src/Arduino_JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino_JSON library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _ARDUINO_JSON_H_ 21 | #define _ARDUINO_JSON_H_ 22 | 23 | #include "JSON.h" 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/JSON.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino_JSON library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "JSON.h" 21 | 22 | // #define JSON_HOOKS 23 | 24 | #ifdef JSON_HOOKS 25 | 26 | #include "cjson/cJSON.h" 27 | 28 | static int jsonAllocations = 0; 29 | 30 | void* JSON_malloc(size_t sz) 31 | { 32 | void* ptr = malloc(sz); 33 | 34 | jsonAllocations++; 35 | 36 | Serial.print("JSON malloc: 0x"); 37 | Serial.print((unsigned int)ptr); 38 | Serial.print(' '); 39 | Serial.print(sz); 40 | Serial.print(' '); 41 | Serial.println(jsonAllocations); 42 | 43 | return ptr; 44 | } 45 | 46 | void JSON_free(void* ptr) 47 | { 48 | jsonAllocations--; 49 | 50 | Serial.print("JSON free: 0x"); 51 | Serial.print((unsigned int)ptr); 52 | Serial.print(' '); 53 | Serial.println(jsonAllocations); 54 | 55 | free(ptr); 56 | } 57 | #endif 58 | 59 | JSONClass::JSONClass() 60 | { 61 | #ifdef JSON_HOOKS 62 | struct cJSON_Hooks hooks = { 63 | JSON_malloc, 64 | JSON_free 65 | }; 66 | 67 | cJSON_InitHooks(&hooks); 68 | #endif 69 | } 70 | 71 | JSONClass::~JSONClass() 72 | { 73 | } 74 | 75 | JSONVar JSONClass::parse(const char* s) 76 | { 77 | return JSONVar::parse(s); 78 | } 79 | 80 | JSONVar JSONClass::parse(const String& s) 81 | { 82 | return JSONVar::parse(s); 83 | } 84 | 85 | String JSONClass::stringify(const JSONVar& value) 86 | { 87 | return JSONVar::stringify(value); 88 | } 89 | 90 | String JSONClass::typeof(const JSONVar& value) 91 | { 92 | return JSONVar::typeof(value); 93 | } 94 | 95 | JSONClass JSON; 96 | -------------------------------------------------------------------------------- /src/JSON.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino_JSON library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _JSON_H_ 21 | #define _JSON_H_ 22 | 23 | #include 24 | 25 | #include "JSONVar.h" 26 | 27 | class JSONClass { 28 | public: 29 | JSONClass(); 30 | virtual ~JSONClass(); 31 | 32 | JSONVar parse(const char* s); 33 | JSONVar parse(const String& s); 34 | 35 | String stringify(const JSONVar& value); 36 | 37 | String typeof(const JSONVar& value); 38 | }; 39 | 40 | extern JSONClass JSON; 41 | 42 | #endif 43 | -------------------------------------------------------------------------------- /src/JSONVar.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino_JSON library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #include "cjson/cJSON.h" 21 | 22 | #include "JSONVar.h" 23 | 24 | JSONVar::JSONVar(struct cJSON* json, struct cJSON* parent) : 25 | _json(json), 26 | _parent(parent) 27 | { 28 | } 29 | 30 | JSONVar::JSONVar(bool b) : 31 | JSONVar() 32 | { 33 | *this = b; 34 | } 35 | 36 | JSONVar::JSONVar (char i) : 37 | JSONVar () 38 | { 39 | *this = i; 40 | } 41 | 42 | JSONVar::JSONVar (unsigned char i) : 43 | JSONVar () 44 | { 45 | *this = i; 46 | } 47 | 48 | JSONVar::JSONVar (short i) : 49 | JSONVar () 50 | { 51 | *this = i; 52 | } 53 | 54 | JSONVar::JSONVar (unsigned short i) : 55 | JSONVar () 56 | { 57 | *this = i; 58 | } 59 | 60 | JSONVar::JSONVar(int i) : 61 | JSONVar() 62 | { 63 | *this = i; 64 | } 65 | 66 | JSONVar::JSONVar (unsigned int i) : 67 | JSONVar () 68 | { 69 | *this = i; 70 | } 71 | 72 | JSONVar::JSONVar(long l) : 73 | JSONVar() 74 | { 75 | *this = l; 76 | } 77 | 78 | JSONVar::JSONVar(unsigned long ul) : 79 | JSONVar() 80 | { 81 | *this = ul; 82 | } 83 | 84 | JSONVar::JSONVar(double d) : 85 | JSONVar() 86 | { 87 | *this = d; 88 | } 89 | 90 | JSONVar::JSONVar(const char* s) : 91 | JSONVar() 92 | { 93 | *this = s; 94 | } 95 | 96 | JSONVar::JSONVar(const String& s) : 97 | JSONVar() 98 | { 99 | *this = s; 100 | } 101 | 102 | JSONVar::JSONVar(const JSONVar& v) 103 | { 104 | _json = cJSON_Duplicate(v._json, true); 105 | _parent = NULL; 106 | } 107 | 108 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 109 | JSONVar::JSONVar(JSONVar&& v) 110 | { 111 | cJSON* tmp; 112 | 113 | // swap _json 114 | tmp = _json; 115 | _json = v._json; 116 | v._json = tmp; 117 | 118 | // swap parent 119 | tmp = _parent; 120 | _parent = v._parent; 121 | v._parent = tmp; 122 | } 123 | #endif 124 | 125 | JSONVar::JSONVar(nullptr_t) : 126 | JSONVar() 127 | { 128 | *this = nullptr; 129 | } 130 | 131 | JSONVar::JSONVar() : 132 | JSONVar(NULL, NULL) 133 | { 134 | } 135 | 136 | JSONVar::~JSONVar() 137 | { 138 | if (_json != NULL && _parent == NULL) { 139 | cJSON_Delete(_json); 140 | 141 | _json = NULL; 142 | } 143 | } 144 | 145 | size_t JSONVar::printTo(Print& p) const 146 | { 147 | if (_json == NULL) { 148 | return 0; 149 | } 150 | 151 | char* s = cJSON_PrintUnformatted(_json); 152 | 153 | size_t writen = p.print(s); 154 | 155 | cJSON_free(s); 156 | 157 | return writen; 158 | } 159 | 160 | JSONVar::operator bool() const 161 | { 162 | return cJSON_IsBool(_json) && cJSON_IsTrue(_json); 163 | } 164 | 165 | JSONVar::operator char () const 166 | { 167 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 168 | } 169 | 170 | JSONVar::operator unsigned char () const 171 | { 172 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 173 | } 174 | 175 | JSONVar::operator short () const 176 | { 177 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 178 | } 179 | 180 | JSONVar::operator unsigned short () const 181 | { 182 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 183 | } 184 | 185 | JSONVar::operator int () const 186 | { 187 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 188 | } 189 | 190 | JSONVar::operator unsigned int () const 191 | { 192 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 193 | } 194 | 195 | JSONVar::operator long () const 196 | { 197 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 198 | } 199 | 200 | JSONVar::operator unsigned long () const 201 | { 202 | return cJSON_IsNumber (_json) ? _json->valueint : 0; 203 | } 204 | 205 | JSONVar::operator double() const 206 | { 207 | return cJSON_IsNumber(_json) ? _json->valuedouble : NAN; 208 | } 209 | 210 | JSONVar::operator const char*() const 211 | { 212 | if (cJSON_IsString(_json)) { 213 | return _json->valuestring; 214 | } 215 | 216 | return NULL; 217 | } 218 | 219 | JSONVar::operator const String () const 220 | { 221 | if (cJSON_IsString (_json)) { 222 | return String(_json->valuestring); 223 | } 224 | 225 | return String(); 226 | } 227 | 228 | void JSONVar::operator=(const JSONVar& v) 229 | { 230 | if (&v == &undefined) { 231 | if (cJSON_IsObject(_parent)) { 232 | cJSON_DeleteItemFromObjectCaseSensitive(_parent, _json->string); 233 | 234 | _json = NULL; 235 | _parent = NULL; 236 | } else { 237 | replaceJson(cJSON_CreateNull()); 238 | } 239 | } else { 240 | replaceJson(cJSON_Duplicate(v._json, true)); 241 | } 242 | } 243 | 244 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 245 | JSONVar& JSONVar::operator=(JSONVar&& v) 246 | { 247 | cJSON* tmp; 248 | 249 | // swap _json 250 | tmp = _json; 251 | _json = v._json; 252 | v._json = tmp; 253 | 254 | // swap parent 255 | tmp = _parent; 256 | _parent = v._parent; 257 | v._parent = tmp; 258 | 259 | return *this; 260 | } 261 | #endif 262 | 263 | void JSONVar::operator=(bool b) 264 | { 265 | replaceJson(b ? cJSON_CreateTrue() : cJSON_CreateFalse()); 266 | } 267 | 268 | void JSONVar::operator=(char i) 269 | { 270 | replaceJson (cJSON_CreateNumber (i)); 271 | } 272 | 273 | void JSONVar::operator=(unsigned char i) 274 | { 275 | replaceJson (cJSON_CreateNumber (i)); 276 | } 277 | 278 | void JSONVar::operator=(short i) 279 | { 280 | replaceJson (cJSON_CreateNumber (i)); 281 | } 282 | 283 | void JSONVar::operator=(unsigned short i) 284 | { 285 | replaceJson (cJSON_CreateNumber (i)); 286 | } 287 | 288 | void JSONVar::operator=(int i) 289 | { 290 | replaceJson (cJSON_CreateNumber (i)); 291 | } 292 | 293 | void JSONVar::operator=(unsigned int i) 294 | { 295 | replaceJson (cJSON_CreateNumber (i)); 296 | } 297 | 298 | void JSONVar::operator=(long l) 299 | { 300 | replaceJson(cJSON_CreateNumber(l)); 301 | } 302 | 303 | void JSONVar::operator=(unsigned long ul) 304 | { 305 | replaceJson(cJSON_CreateNumber(ul)); 306 | } 307 | 308 | void JSONVar::operator=(double d) 309 | { 310 | replaceJson(cJSON_CreateNumber(d)); 311 | } 312 | 313 | void JSONVar::operator=(const char* s) 314 | { 315 | replaceJson(cJSON_CreateString(s)); 316 | } 317 | 318 | void JSONVar::operator=(const String& s) 319 | { 320 | *this = s.c_str(); 321 | } 322 | 323 | void JSONVar::operator=(nullptr_t) 324 | { 325 | replaceJson(cJSON_CreateNull()); 326 | } 327 | 328 | bool JSONVar::operator==(const JSONVar& v) const 329 | { 330 | return cJSON_Compare(_json, v._json, 1) || 331 | (_json == NULL && v._json == NULL); 332 | } 333 | 334 | bool JSONVar::operator==(nullptr_t) const 335 | { 336 | return (cJSON_IsNull(_json)); 337 | } 338 | 339 | JSONVar JSONVar::operator[](const char* key) 340 | { 341 | if (!cJSON_IsObject(_json)) { 342 | replaceJson(cJSON_CreateObject()); 343 | } 344 | 345 | cJSON* json = cJSON_GetObjectItemCaseSensitive(_json, key); 346 | 347 | if (json == NULL) { 348 | json = cJSON_AddNullToObject(_json, key); 349 | } 350 | 351 | return JSONVar(json, _json); 352 | } 353 | 354 | JSONVar JSONVar::operator[](const String& key) 355 | { 356 | return (*this)[key.c_str()]; 357 | } 358 | 359 | JSONVar JSONVar::operator[](int index) 360 | { 361 | if (!cJSON_IsArray(_json)) { 362 | replaceJson(cJSON_CreateArray()); 363 | } 364 | 365 | cJSON* json = cJSON_GetArrayItem(_json, index); 366 | 367 | if (json == NULL) { 368 | while (index >= cJSON_GetArraySize(_json)) { 369 | json = cJSON_CreateNull(); 370 | 371 | cJSON_AddItemToArray(_json, json); 372 | } 373 | } 374 | 375 | return JSONVar(json, _json); 376 | } 377 | 378 | JSONVar JSONVar::operator[](const JSONVar& key) 379 | { 380 | if (cJSON_IsArray(_json) && cJSON_IsNumber(key._json)) { 381 | int index = (int)key; 382 | 383 | return (*this)[index]; 384 | } 385 | 386 | if (cJSON_IsObject(_json) && cJSON_IsString(key._json)) { 387 | const char* str = (const char*) key; 388 | 389 | return (*this)[str]; 390 | } 391 | 392 | return JSONVar(NULL, NULL); 393 | } 394 | 395 | int JSONVar::length() const 396 | { 397 | if (cJSON_IsString(_json)) { 398 | return strlen(_json->string); 399 | } else if (cJSON_IsArray(_json)) { 400 | return cJSON_GetArraySize(_json); 401 | } else { 402 | return -1; 403 | } 404 | } 405 | 406 | JSONVar JSONVar::keys() const 407 | { 408 | if (!cJSON_IsObject(_json)) { 409 | return JSONVar(NULL, NULL); 410 | } 411 | 412 | int length = cJSON_GetArraySize(_json); 413 | 414 | const char* keys[length]; 415 | cJSON* child = _json->child; 416 | 417 | for (int i = 0; i < length; i++, child = child->next) { 418 | keys[i] = child->string; 419 | } 420 | 421 | return JSONVar(cJSON_CreateStringArray(keys, length), NULL); 422 | } 423 | 424 | bool JSONVar::hasOwnProperty(const char* key) const 425 | { 426 | if (!cJSON_IsObject(_json)) { 427 | return false; 428 | } 429 | 430 | cJSON* json = cJSON_GetObjectItemCaseSensitive(_json, key); 431 | return (json != NULL); 432 | } 433 | 434 | bool JSONVar::hasOwnProperty(const String& key) const 435 | { 436 | return hasOwnProperty(key.c_str()); 437 | } 438 | 439 | JSONVar JSONVar::parse(const char* s) 440 | { 441 | cJSON* json = cJSON_Parse(s); 442 | 443 | return JSONVar(json, NULL); 444 | } 445 | 446 | JSONVar JSONVar::parse(const String& s) 447 | { 448 | return parse(s.c_str()); 449 | } 450 | 451 | String JSONVar::stringify(const JSONVar& value) 452 | { 453 | if (value._json == NULL) { 454 | return String((const char *)NULL); 455 | } 456 | 457 | char* s = cJSON_PrintUnformatted(value._json); 458 | 459 | String str = s; 460 | 461 | cJSON_free(s); 462 | 463 | return str; 464 | } 465 | 466 | String JSONVar::typeof_(const JSONVar& value) 467 | { 468 | struct cJSON* json = value._json; 469 | 470 | if (json == NULL || cJSON_IsInvalid(json)) { 471 | return "undefined"; 472 | } else if (cJSON_IsBool(json)) { 473 | return "boolean"; 474 | } else if (cJSON_IsNull(json)) { 475 | return "null"; // TODO: should this return "object" to be more JS like? 476 | } else if (cJSON_IsNumber(json)) { 477 | return "number"; 478 | } else if (cJSON_IsString(json)) { 479 | return "string"; 480 | } else if (cJSON_IsArray(json)) { 481 | return "array"; // TODO: should this return "object" to be more JS like? 482 | } else if (cJSON_IsObject(json)) { 483 | return "object"; 484 | } else { 485 | return "unknown"; 486 | } 487 | } 488 | 489 | void JSONVar::replaceJson(struct cJSON* json) 490 | { 491 | cJSON* old = _json; 492 | 493 | _json = json; 494 | 495 | if (old) { 496 | if (_parent) { 497 | if (cJSON_IsObject(_parent)) { 498 | cJSON_ReplaceItemInObjectCaseSensitive(_parent, old->string, _json); 499 | } else if (cJSON_IsArray(_parent)) { 500 | cJSON_ReplaceItemViaPointer(_parent, old, _json); 501 | } 502 | } else { 503 | cJSON_Delete(old); 504 | } 505 | } 506 | } 507 | 508 | //--------------------------------------------------------------------- 509 | 510 | bool JSONVar::hasPropertyEqual(const char* key, const char* value) const { 511 | if (!cJSON_IsObject(_json)) { 512 | return false; 513 | } 514 | 515 | cJSON* json = cJSON_GetObjectItemCaseSensitive(_json, key); 516 | return json != NULL && strcmp(value, json->valuestring) == 0; 517 | } 518 | 519 | //--------------------------------------------------------------------- 520 | 521 | bool JSONVar::hasPropertyEqual(const char* key, const JSONVar& value) const { 522 | return this->hasPropertyEqual(key, (const char*)value); 523 | } 524 | 525 | //--------------------------------------------------------------------- 526 | 527 | bool JSONVar::hasPropertyEqual(const String& key, const String& value) const { 528 | return this->hasPropertyEqual(key.c_str(), value.c_str()); 529 | } 530 | 531 | //--------------------------------------------------------------------- 532 | 533 | bool JSONVar::hasPropertyEqual(const String& key, const JSONVar& value) const { 534 | return this->hasPropertyEqual(key.c_str(), (const char*)value); 535 | } 536 | 537 | //--------------------------------------------------------------------- 538 | 539 | JSONVar JSONVar::filter(const char* key, const char* value) const { 540 | cJSON* item; 541 | cJSON* test; 542 | cJSON* json = cJSON_CreateArray(); 543 | 544 | if(cJSON_IsObject(_json)){ 545 | test = cJSON_GetObjectItem(_json, key); 546 | 547 | if(test != NULL && strcmp(value, test->valuestring) == 0){ 548 | return (*this); 549 | } 550 | } 551 | 552 | for (int i = 0; i < cJSON_GetArraySize(_json); i++) { 553 | item = cJSON_GetArrayItem(_json, i); 554 | 555 | if (item == NULL) { 556 | continue; 557 | } 558 | 559 | test = cJSON_GetObjectItem(item, key); 560 | 561 | if(test != NULL && strcmp(value, test->valuestring) == 0){ 562 | cJSON_AddItemToArray(json, cJSON_Duplicate(item,true)); 563 | } 564 | } 565 | 566 | if(cJSON_GetArraySize(json) == 0){ 567 | return JSONVar(NULL, NULL); 568 | } 569 | 570 | if(cJSON_GetArraySize(json) == 1){ 571 | return JSONVar(cJSON_GetArrayItem(json, 0), _json); 572 | } 573 | 574 | return JSONVar(json, _json); 575 | } 576 | 577 | JSONVar JSONVar::filter(const char* key, const JSONVar& value) const { 578 | return this->filter(key, (const char*)value); 579 | } 580 | 581 | JSONVar JSONVar::filter(const String& key, const String& value) const { 582 | return this->filter(key.c_str(), value.c_str()); 583 | } 584 | 585 | JSONVar JSONVar::filter(const String& key, const JSONVar& value) const { 586 | return this->filter(key.c_str(), (const char*)value); 587 | } 588 | 589 | JSONVar undefined; 590 | -------------------------------------------------------------------------------- /src/JSONVar.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of the Arduino_JSON library. 3 | Copyright (c) 2019 Arduino SA. All rights reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef _JSON_VAR_H_ 21 | #define _JSON_VAR_H_ 22 | 23 | #include 24 | 25 | struct cJSON; 26 | 27 | #define typeof typeof_ 28 | #define null nullptr 29 | 30 | class JSONVar : public Printable { 31 | public: 32 | JSONVar(); 33 | JSONVar(bool b); 34 | JSONVar(char i); 35 | JSONVar(unsigned char i); 36 | JSONVar(short i); 37 | JSONVar(unsigned short i); 38 | JSONVar(int i); 39 | JSONVar(unsigned int i); 40 | JSONVar(long l); 41 | JSONVar(unsigned long ul); 42 | JSONVar(double d); 43 | JSONVar(const char* s); 44 | JSONVar(const String& s); 45 | JSONVar(const JSONVar& v); 46 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 47 | JSONVar(JSONVar&& v); 48 | #endif 49 | JSONVar(nullptr_t); 50 | virtual ~JSONVar(); 51 | 52 | virtual size_t printTo(Print& p) const; 53 | 54 | operator bool() const; 55 | operator char() const; 56 | operator unsigned char() const; 57 | operator short() const; 58 | operator unsigned short() const; 59 | operator int() const; 60 | operator unsigned int() const; 61 | operator long () const; 62 | operator unsigned long () const; 63 | operator double() const; 64 | operator const char* () const; 65 | operator const String () const; 66 | 67 | void operator=(const JSONVar& v); 68 | #if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) 69 | JSONVar& operator=(JSONVar&& v); 70 | #endif 71 | void operator=(bool b); 72 | void operator=(char i); 73 | void operator=(unsigned char i); 74 | void operator=(short i); 75 | void operator=(unsigned short i); 76 | void operator=(int i); 77 | void operator=(unsigned int i); 78 | void operator=(long l); 79 | void operator=(unsigned long ul); 80 | void operator=(double d); 81 | void operator=(const char* s); 82 | void operator=(const String& s); 83 | void operator=(nullptr_t); 84 | 85 | bool operator==(const JSONVar& v) const; 86 | bool operator==(nullptr_t) const; 87 | 88 | JSONVar operator[](const char* key); 89 | JSONVar operator[](const String& key); 90 | JSONVar operator[](int index); 91 | JSONVar operator[](const JSONVar& key); 92 | 93 | int length() const; 94 | JSONVar keys() const; 95 | bool hasOwnProperty(const char* key) const; 96 | bool hasOwnProperty(const String& key) const; 97 | 98 | bool hasPropertyEqual(const char* key, const char* value) const; 99 | bool hasPropertyEqual(const char* key, const JSONVar& value) const; 100 | bool hasPropertyEqual(const String& key, const String& value) const; 101 | bool hasPropertyEqual(const String& key, const JSONVar& value) const; 102 | 103 | JSONVar filter(const char* key, const char* value) const; 104 | JSONVar filter(const char* key, const JSONVar& value) const; 105 | JSONVar filter(const String& key, const String& value) const; 106 | JSONVar filter(const String& key, const JSONVar& value) const; 107 | 108 | static JSONVar parse(const char* s); 109 | static JSONVar parse(const String& s); 110 | static String stringify(const JSONVar& value); 111 | static String typeof_(const JSONVar& value); 112 | 113 | private: 114 | JSONVar(struct cJSON* json, struct cJSON* parent); 115 | 116 | void replaceJson(struct cJSON* json); 117 | 118 | private: 119 | struct cJSON* _json; 120 | struct cJSON* _parent; 121 | }; 122 | 123 | extern JSONVar undefined; 124 | 125 | #endif 126 | -------------------------------------------------------------------------------- /src/cjson/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2017 Dave Gamble and cJSON contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /src/cjson/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 "cJSON.h" 60 | 61 | /* define our own boolean type */ 62 | #ifdef true 63 | #undef true 64 | #endif 65 | #define true ((cJSON_bool)1) 66 | 67 | #ifdef false 68 | #undef false 69 | #endif 70 | #define false ((cJSON_bool)0) 71 | 72 | /* define isnan and isinf for ANSI C, if in C99 or above, isnan and isinf has been defined in math.h */ 73 | #ifndef isinf 74 | #define isinf(d) (isnan((d - d)) && !isnan(d)) 75 | #endif 76 | #ifndef isnan 77 | #define isnan(d) (d != d) 78 | #endif 79 | 80 | #ifndef NAN 81 | #ifdef _WIN32 82 | #define NAN sqrt(-1.0) 83 | #else 84 | #define NAN 0.0/0.0 85 | #endif 86 | #endif 87 | 88 | typedef struct { 89 | const unsigned char *json; 90 | size_t position; 91 | } error; 92 | static error global_error = { NULL, 0 }; 93 | 94 | CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) 95 | { 96 | return (const char*) (global_error.json + global_error.position); 97 | } 98 | 99 | CJSON_PUBLIC(char *) cJSON_GetStringValue(const cJSON * const item) 100 | { 101 | if (!cJSON_IsString(item)) 102 | { 103 | return NULL; 104 | } 105 | 106 | return item->valuestring; 107 | } 108 | 109 | CJSON_PUBLIC(double) cJSON_GetNumberValue(const cJSON * const item) 110 | { 111 | if (!cJSON_IsNumber(item)) 112 | { 113 | return (double) NAN; 114 | } 115 | 116 | return item->valuedouble; 117 | } 118 | 119 | /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ 120 | #if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 7) || (CJSON_VERSION_PATCH != 14) 121 | #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. 122 | #endif 123 | 124 | CJSON_PUBLIC(const char*) cJSON_Version(void) 125 | { 126 | static char version[15]; 127 | sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); 128 | 129 | return version; 130 | } 131 | 132 | /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ 133 | static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) 134 | { 135 | if ((string1 == NULL) || (string2 == NULL)) 136 | { 137 | return 1; 138 | } 139 | 140 | if (string1 == string2) 141 | { 142 | return 0; 143 | } 144 | 145 | for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) 146 | { 147 | if (*string1 == '\0') 148 | { 149 | return 0; 150 | } 151 | } 152 | 153 | return tolower(*string1) - tolower(*string2); 154 | } 155 | 156 | typedef struct internal_hooks 157 | { 158 | void *(CJSON_CDECL *allocate)(size_t size); 159 | void (CJSON_CDECL *deallocate)(void *pointer); 160 | void *(CJSON_CDECL *reallocate)(void *pointer, size_t size); 161 | } internal_hooks; 162 | 163 | #if defined(_MSC_VER) 164 | /* work around MSVC error C2322: '...' address of dllimport '...' is not static */ 165 | static void * CJSON_CDECL internal_malloc(size_t size) 166 | { 167 | return malloc(size); 168 | } 169 | static void CJSON_CDECL internal_free(void *pointer) 170 | { 171 | free(pointer); 172 | } 173 | static void * CJSON_CDECL internal_realloc(void *pointer, size_t size) 174 | { 175 | return realloc(pointer, size); 176 | } 177 | #else 178 | #define internal_malloc malloc 179 | #define internal_free free 180 | #define internal_realloc realloc 181 | #endif 182 | 183 | /* strlen of character literals resolved at compile time */ 184 | #define static_strlen(string_literal) (sizeof(string_literal) - sizeof("")) 185 | 186 | static internal_hooks global_hooks = { internal_malloc, internal_free, internal_realloc }; 187 | 188 | static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) 189 | { 190 | size_t length = 0; 191 | unsigned char *copy = NULL; 192 | 193 | if (string == NULL) 194 | { 195 | return NULL; 196 | } 197 | 198 | length = strlen((const char*)string) + sizeof(""); 199 | copy = (unsigned char*)hooks->allocate(length); 200 | if (copy == NULL) 201 | { 202 | return NULL; 203 | } 204 | memcpy(copy, string, length); 205 | 206 | return copy; 207 | } 208 | 209 | CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) 210 | { 211 | if (hooks == NULL) 212 | { 213 | /* Reset hooks */ 214 | global_hooks.allocate = malloc; 215 | global_hooks.deallocate = free; 216 | global_hooks.reallocate = realloc; 217 | return; 218 | } 219 | 220 | global_hooks.allocate = malloc; 221 | if (hooks->malloc_fn != NULL) 222 | { 223 | global_hooks.allocate = hooks->malloc_fn; 224 | } 225 | 226 | global_hooks.deallocate = free; 227 | if (hooks->free_fn != NULL) 228 | { 229 | global_hooks.deallocate = hooks->free_fn; 230 | } 231 | 232 | /* use realloc only if both free and malloc are used */ 233 | global_hooks.reallocate = NULL; 234 | if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) 235 | { 236 | global_hooks.reallocate = realloc; 237 | } 238 | } 239 | 240 | /* Internal constructor. */ 241 | static cJSON *cJSON_New_Item(const internal_hooks * const hooks) 242 | { 243 | cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); 244 | if (node) 245 | { 246 | memset(node, '\0', sizeof(cJSON)); 247 | } 248 | 249 | return node; 250 | } 251 | 252 | /* Delete a cJSON structure. */ 253 | CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) 254 | { 255 | cJSON *next = NULL; 256 | while (item != NULL) 257 | { 258 | next = item->next; 259 | if (!(item->type & cJSON_IsReference) && (item->child != NULL)) 260 | { 261 | cJSON_Delete(item->child); 262 | } 263 | if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) 264 | { 265 | global_hooks.deallocate(item->valuestring); 266 | } 267 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 268 | { 269 | global_hooks.deallocate(item->string); 270 | } 271 | global_hooks.deallocate(item); 272 | item = next; 273 | } 274 | } 275 | 276 | /* get the decimal point character of the current locale */ 277 | static unsigned char get_decimal_point(void) 278 | { 279 | #ifdef ENABLE_LOCALES 280 | struct lconv *lconv = localeconv(); 281 | return (unsigned char) lconv->decimal_point[0]; 282 | #else 283 | return '.'; 284 | #endif 285 | } 286 | 287 | typedef struct 288 | { 289 | const unsigned char *content; 290 | size_t length; 291 | size_t offset; 292 | size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ 293 | internal_hooks hooks; 294 | } parse_buffer; 295 | 296 | /* check if the given size is left to read in a given parse buffer (starting with 1) */ 297 | #define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) 298 | /* check if the buffer can be accessed at the given index (starting with 0) */ 299 | #define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) 300 | #define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) 301 | /* get a pointer to the buffer at the position */ 302 | #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) 303 | 304 | /* Parse the input text to generate a number, and populate the result into item. */ 305 | static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) 306 | { 307 | double number = 0; 308 | unsigned char *after_end = NULL; 309 | unsigned char number_c_string[64]; 310 | unsigned char decimal_point = get_decimal_point(); 311 | size_t i = 0; 312 | 313 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 314 | { 315 | return false; 316 | } 317 | 318 | /* copy the number into a temporary buffer and replace '.' with the decimal point 319 | * of the current locale (for strtod) 320 | * This also takes care of '\0' not necessarily being available for marking the end of the input */ 321 | for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) 322 | { 323 | switch (buffer_at_offset(input_buffer)[i]) 324 | { 325 | case '0': 326 | case '1': 327 | case '2': 328 | case '3': 329 | case '4': 330 | case '5': 331 | case '6': 332 | case '7': 333 | case '8': 334 | case '9': 335 | case '+': 336 | case '-': 337 | case 'e': 338 | case 'E': 339 | number_c_string[i] = buffer_at_offset(input_buffer)[i]; 340 | break; 341 | 342 | case '.': 343 | number_c_string[i] = decimal_point; 344 | break; 345 | 346 | default: 347 | goto loop_end; 348 | } 349 | } 350 | loop_end: 351 | number_c_string[i] = '\0'; 352 | 353 | number = strtod((const char*)number_c_string, (char**)&after_end); 354 | if (number_c_string == after_end) 355 | { 356 | return false; /* parse_error */ 357 | } 358 | 359 | item->valuedouble = number; 360 | 361 | /* use saturation in case of overflow */ 362 | if (number >= INT_MAX) 363 | { 364 | item->valueint = INT_MAX; 365 | } 366 | else if (number <= (double)INT_MIN) 367 | { 368 | item->valueint = INT_MIN; 369 | } 370 | else 371 | { 372 | item->valueint = (int)number; 373 | } 374 | 375 | item->type = cJSON_Number; 376 | 377 | input_buffer->offset += (size_t)(after_end - number_c_string); 378 | return true; 379 | } 380 | 381 | /* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ 382 | CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) 383 | { 384 | if (number >= INT_MAX) 385 | { 386 | object->valueint = INT_MAX; 387 | } 388 | else if (number <= (double)INT_MIN) 389 | { 390 | object->valueint = INT_MIN; 391 | } 392 | else 393 | { 394 | object->valueint = (int)number; 395 | } 396 | 397 | return object->valuedouble = number; 398 | } 399 | 400 | CJSON_PUBLIC(char*) cJSON_SetValuestring(cJSON *object, const char *valuestring) 401 | { 402 | char *copy = NULL; 403 | /* if object's type is not cJSON_String or is cJSON_IsReference, it should not set valuestring */ 404 | if (!(object->type & cJSON_String) || (object->type & cJSON_IsReference)) 405 | { 406 | return NULL; 407 | } 408 | if (strlen(valuestring) <= strlen(object->valuestring)) 409 | { 410 | strcpy(object->valuestring, valuestring); 411 | return object->valuestring; 412 | } 413 | copy = (char*) cJSON_strdup((const unsigned char*)valuestring, &global_hooks); 414 | if (copy == NULL) 415 | { 416 | return NULL; 417 | } 418 | if (object->valuestring != NULL) 419 | { 420 | cJSON_free(object->valuestring); 421 | } 422 | object->valuestring = copy; 423 | 424 | return copy; 425 | } 426 | 427 | typedef struct 428 | { 429 | unsigned char *buffer; 430 | size_t length; 431 | size_t offset; 432 | size_t depth; /* current nesting depth (for formatted printing) */ 433 | cJSON_bool noalloc; 434 | cJSON_bool format; /* is this print a formatted print */ 435 | internal_hooks hooks; 436 | } printbuffer; 437 | 438 | /* realloc printbuffer if necessary to have at least "needed" bytes more */ 439 | static unsigned char* ensure(printbuffer * const p, size_t needed) 440 | { 441 | unsigned char *newbuffer = NULL; 442 | size_t newsize = 0; 443 | 444 | if ((p == NULL) || (p->buffer == NULL)) 445 | { 446 | return NULL; 447 | } 448 | 449 | if ((p->length > 0) && (p->offset >= p->length)) 450 | { 451 | /* make sure that offset is valid */ 452 | return NULL; 453 | } 454 | 455 | if (needed > INT_MAX) 456 | { 457 | /* sizes bigger than INT_MAX are currently not supported */ 458 | return NULL; 459 | } 460 | 461 | needed += p->offset + 1; 462 | if (needed <= p->length) 463 | { 464 | return p->buffer + p->offset; 465 | } 466 | 467 | if (p->noalloc) { 468 | return NULL; 469 | } 470 | 471 | /* calculate new buffer size */ 472 | if (needed > (INT_MAX / 2)) 473 | { 474 | /* overflow of int, use INT_MAX if possible */ 475 | if (needed <= INT_MAX) 476 | { 477 | newsize = INT_MAX; 478 | } 479 | else 480 | { 481 | return NULL; 482 | } 483 | } 484 | else 485 | { 486 | newsize = needed * 2; 487 | } 488 | 489 | if (p->hooks.reallocate != NULL) 490 | { 491 | /* reallocate with realloc if available */ 492 | newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); 493 | if (newbuffer == NULL) 494 | { 495 | p->hooks.deallocate(p->buffer); 496 | p->length = 0; 497 | p->buffer = NULL; 498 | 499 | return NULL; 500 | } 501 | } 502 | else 503 | { 504 | /* otherwise reallocate manually */ 505 | newbuffer = (unsigned char*)p->hooks.allocate(newsize); 506 | if (!newbuffer) 507 | { 508 | p->hooks.deallocate(p->buffer); 509 | p->length = 0; 510 | p->buffer = NULL; 511 | 512 | return NULL; 513 | } 514 | if (newbuffer) 515 | { 516 | memcpy(newbuffer, p->buffer, p->offset + 1); 517 | } 518 | p->hooks.deallocate(p->buffer); 519 | } 520 | p->length = newsize; 521 | p->buffer = newbuffer; 522 | 523 | return newbuffer + p->offset; 524 | } 525 | 526 | /* calculate the new length of the string in a printbuffer and update the offset */ 527 | static void update_offset(printbuffer * const buffer) 528 | { 529 | const unsigned char *buffer_pointer = NULL; 530 | if ((buffer == NULL) || (buffer->buffer == NULL)) 531 | { 532 | return; 533 | } 534 | buffer_pointer = buffer->buffer + buffer->offset; 535 | 536 | buffer->offset += strlen((const char*)buffer_pointer); 537 | } 538 | 539 | /* securely comparison of floating-point variables */ 540 | static cJSON_bool compare_double(double a, double b) 541 | { 542 | double maxVal = fabs(a) > fabs(b) ? fabs(a) : fabs(b); 543 | return (fabs(a - b) <= maxVal * DBL_EPSILON); 544 | } 545 | 546 | /* Render the number nicely from the given item into a string. */ 547 | static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) 548 | { 549 | unsigned char *output_pointer = NULL; 550 | double d = item->valuedouble; 551 | int length = 0; 552 | size_t i = 0; 553 | unsigned char number_buffer[26] = {0}; /* temporary buffer to print the number into */ 554 | unsigned char decimal_point = get_decimal_point(); 555 | double test = 0.0; 556 | 557 | if (output_buffer == NULL) 558 | { 559 | return false; 560 | } 561 | 562 | /* This checks for NaN and Infinity */ 563 | if (isnan(d) || isinf(d)) 564 | { 565 | length = sprintf((char*)number_buffer, "null"); 566 | } 567 | else 568 | { 569 | #ifdef __AVR__ 570 | (void)test; 571 | 572 | // zero the buffer 573 | memset(number_buffer, 0x00, sizeof(number_buffer)); 574 | 575 | // add the integer part 576 | ltoa((long)d, (char*)number_buffer, 10); 577 | length = strlen((char*)number_buffer); 578 | 579 | // calculate the number of decimal points (up to 9) 580 | long decimal = (long)((d - (long)d) * 1000000000L); 581 | 582 | if (decimal < 0) { 583 | // negative decimal, make it positive 584 | decimal *= -1; 585 | } 586 | 587 | // trim the trailing zeros 588 | while (decimal && (decimal % 10) == 0) { 589 | decimal /= 10; 590 | } 591 | 592 | if (decimal) { 593 | // add the decimal part 594 | number_buffer[length] = decimal_point; 595 | 596 | ltoa(decimal, (char*)&number_buffer[length + 1], 10); 597 | 598 | length = strlen((char*)number_buffer); 599 | } 600 | #else 601 | /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ 602 | length = sprintf((char*)number_buffer, "%1.15g", d); 603 | 604 | /* Check whether the original double can be recovered */ 605 | if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) 606 | { 607 | /* If not, print with 17 decimal places of precision */ 608 | length = sprintf((char*)number_buffer, "%1.17g", d); 609 | } 610 | #endif 611 | } 612 | 613 | /* sprintf failed or buffer overrun occurred */ 614 | if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) 615 | { 616 | return false; 617 | } 618 | 619 | /* reserve appropriate space in the output */ 620 | output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); 621 | if (output_pointer == NULL) 622 | { 623 | return false; 624 | } 625 | 626 | /* copy the printed number to the output and replace locale 627 | * dependent decimal point with '.' */ 628 | for (i = 0; i < ((size_t)length); i++) 629 | { 630 | if (number_buffer[i] == decimal_point) 631 | { 632 | output_pointer[i] = '.'; 633 | continue; 634 | } 635 | 636 | output_pointer[i] = number_buffer[i]; 637 | } 638 | output_pointer[i] = '\0'; 639 | 640 | output_buffer->offset += (size_t)length; 641 | 642 | return true; 643 | } 644 | 645 | /* parse 4 digit hexadecimal number */ 646 | static unsigned parse_hex4(const unsigned char * const input) 647 | { 648 | unsigned int h = 0; 649 | size_t i = 0; 650 | 651 | for (i = 0; i < 4; i++) 652 | { 653 | /* parse digit */ 654 | if ((input[i] >= '0') && (input[i] <= '9')) 655 | { 656 | h += (unsigned int) input[i] - '0'; 657 | } 658 | else if ((input[i] >= 'A') && (input[i] <= 'F')) 659 | { 660 | h += (unsigned int) 10 + input[i] - 'A'; 661 | } 662 | else if ((input[i] >= 'a') && (input[i] <= 'f')) 663 | { 664 | h += (unsigned int) 10 + input[i] - 'a'; 665 | } 666 | else /* invalid */ 667 | { 668 | return 0; 669 | } 670 | 671 | if (i < 3) 672 | { 673 | /* shift left to make place for the next nibble */ 674 | h = h << 4; 675 | } 676 | } 677 | 678 | return h; 679 | } 680 | 681 | /* converts a UTF-16 literal to UTF-8 682 | * A literal can be one or two sequences of the form \uXXXX */ 683 | static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) 684 | { 685 | long unsigned int codepoint = 0; 686 | unsigned int first_code = 0; 687 | const unsigned char *first_sequence = input_pointer; 688 | unsigned char utf8_length = 0; 689 | unsigned char utf8_position = 0; 690 | unsigned char sequence_length = 0; 691 | unsigned char first_byte_mark = 0; 692 | 693 | if ((input_end - first_sequence) < 6) 694 | { 695 | /* input ends unexpectedly */ 696 | goto fail; 697 | } 698 | 699 | /* get the first utf16 sequence */ 700 | first_code = parse_hex4(first_sequence + 2); 701 | 702 | /* check that the code is valid */ 703 | if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) 704 | { 705 | goto fail; 706 | } 707 | 708 | /* UTF16 surrogate pair */ 709 | if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) 710 | { 711 | const unsigned char *second_sequence = first_sequence + 6; 712 | unsigned int second_code = 0; 713 | sequence_length = 12; /* \uXXXX\uXXXX */ 714 | 715 | if ((input_end - second_sequence) < 6) 716 | { 717 | /* input ends unexpectedly */ 718 | goto fail; 719 | } 720 | 721 | if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) 722 | { 723 | /* missing second half of the surrogate pair */ 724 | goto fail; 725 | } 726 | 727 | /* get the second utf16 sequence */ 728 | second_code = parse_hex4(second_sequence + 2); 729 | /* check that the code is valid */ 730 | if ((second_code < 0xDC00) || (second_code > 0xDFFF)) 731 | { 732 | /* invalid second half of the surrogate pair */ 733 | goto fail; 734 | } 735 | 736 | 737 | /* calculate the unicode codepoint from the surrogate pair */ 738 | codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); 739 | } 740 | else 741 | { 742 | sequence_length = 6; /* \uXXXX */ 743 | codepoint = first_code; 744 | } 745 | 746 | /* encode as UTF-8 747 | * takes at maximum 4 bytes to encode: 748 | * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ 749 | if (codepoint < 0x80) 750 | { 751 | /* normal ascii, encoding 0xxxxxxx */ 752 | utf8_length = 1; 753 | } 754 | else if (codepoint < 0x800) 755 | { 756 | /* two bytes, encoding 110xxxxx 10xxxxxx */ 757 | utf8_length = 2; 758 | first_byte_mark = 0xC0; /* 11000000 */ 759 | } 760 | else if (codepoint < 0x10000) 761 | { 762 | /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ 763 | utf8_length = 3; 764 | first_byte_mark = 0xE0; /* 11100000 */ 765 | } 766 | else if (codepoint <= 0x10FFFF) 767 | { 768 | /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ 769 | utf8_length = 4; 770 | first_byte_mark = 0xF0; /* 11110000 */ 771 | } 772 | else 773 | { 774 | /* invalid unicode codepoint */ 775 | goto fail; 776 | } 777 | 778 | /* encode as utf8 */ 779 | for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) 780 | { 781 | /* 10xxxxxx */ 782 | (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); 783 | codepoint >>= 6; 784 | } 785 | /* encode first byte */ 786 | if (utf8_length > 1) 787 | { 788 | (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); 789 | } 790 | else 791 | { 792 | (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); 793 | } 794 | 795 | *output_pointer += utf8_length; 796 | 797 | return sequence_length; 798 | 799 | fail: 800 | return 0; 801 | } 802 | 803 | /* Parse the input text into an unescaped cinput, and populate item. */ 804 | static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) 805 | { 806 | const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; 807 | const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; 808 | unsigned char *output_pointer = NULL; 809 | unsigned char *output = NULL; 810 | 811 | /* not a string */ 812 | if (buffer_at_offset(input_buffer)[0] != '\"') 813 | { 814 | goto fail; 815 | } 816 | 817 | { 818 | /* calculate approximate size of the output (overestimate) */ 819 | size_t allocation_length = 0; 820 | size_t skipped_bytes = 0; 821 | while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) 822 | { 823 | /* is escape sequence */ 824 | if (input_end[0] == '\\') 825 | { 826 | if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) 827 | { 828 | /* prevent buffer overflow when last input character is a backslash */ 829 | goto fail; 830 | } 831 | skipped_bytes++; 832 | input_end++; 833 | } 834 | input_end++; 835 | } 836 | if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) 837 | { 838 | goto fail; /* string ended unexpectedly */ 839 | } 840 | 841 | /* This is at most how much we need for the output */ 842 | allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; 843 | output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); 844 | if (output == NULL) 845 | { 846 | goto fail; /* allocation failure */ 847 | } 848 | } 849 | 850 | output_pointer = output; 851 | /* loop through the string literal */ 852 | while (input_pointer < input_end) 853 | { 854 | if (*input_pointer != '\\') 855 | { 856 | *output_pointer++ = *input_pointer++; 857 | } 858 | /* escape sequence */ 859 | else 860 | { 861 | unsigned char sequence_length = 2; 862 | if ((input_end - input_pointer) < 1) 863 | { 864 | goto fail; 865 | } 866 | 867 | switch (input_pointer[1]) 868 | { 869 | case 'b': 870 | *output_pointer++ = '\b'; 871 | break; 872 | case 'f': 873 | *output_pointer++ = '\f'; 874 | break; 875 | case 'n': 876 | *output_pointer++ = '\n'; 877 | break; 878 | case 'r': 879 | *output_pointer++ = '\r'; 880 | break; 881 | case 't': 882 | *output_pointer++ = '\t'; 883 | break; 884 | case '\"': 885 | case '\\': 886 | case '/': 887 | *output_pointer++ = input_pointer[1]; 888 | break; 889 | 890 | /* UTF-16 literal */ 891 | case 'u': 892 | sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); 893 | if (sequence_length == 0) 894 | { 895 | /* failed to convert UTF16-literal to UTF-8 */ 896 | goto fail; 897 | } 898 | break; 899 | 900 | default: 901 | goto fail; 902 | } 903 | input_pointer += sequence_length; 904 | } 905 | } 906 | 907 | /* zero terminate the output */ 908 | *output_pointer = '\0'; 909 | 910 | item->type = cJSON_String; 911 | item->valuestring = (char*)output; 912 | 913 | input_buffer->offset = (size_t) (input_end - input_buffer->content); 914 | input_buffer->offset++; 915 | 916 | return true; 917 | 918 | fail: 919 | if (output != NULL) 920 | { 921 | input_buffer->hooks.deallocate(output); 922 | } 923 | 924 | if (input_pointer != NULL) 925 | { 926 | input_buffer->offset = (size_t)(input_pointer - input_buffer->content); 927 | } 928 | 929 | return false; 930 | } 931 | 932 | /* Render the cstring provided to an escaped version that can be printed. */ 933 | static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) 934 | { 935 | const unsigned char *input_pointer = NULL; 936 | unsigned char *output = NULL; 937 | unsigned char *output_pointer = NULL; 938 | size_t output_length = 0; 939 | /* numbers of additional characters needed for escaping */ 940 | size_t escape_characters = 0; 941 | 942 | if (output_buffer == NULL) 943 | { 944 | return false; 945 | } 946 | 947 | /* empty string */ 948 | if (input == NULL) 949 | { 950 | output = ensure(output_buffer, sizeof("\"\"")); 951 | if (output == NULL) 952 | { 953 | return false; 954 | } 955 | strcpy((char*)output, "\"\""); 956 | 957 | return true; 958 | } 959 | 960 | /* set "flag" to 1 if something needs to be escaped */ 961 | for (input_pointer = input; *input_pointer; input_pointer++) 962 | { 963 | switch (*input_pointer) 964 | { 965 | case '\"': 966 | case '\\': 967 | case '\b': 968 | case '\f': 969 | case '\n': 970 | case '\r': 971 | case '\t': 972 | /* one character escape sequence */ 973 | escape_characters++; 974 | break; 975 | default: 976 | if (*input_pointer < 32) 977 | { 978 | /* UTF-16 escape sequence uXXXX */ 979 | escape_characters += 5; 980 | } 981 | break; 982 | } 983 | } 984 | output_length = (size_t)(input_pointer - input) + escape_characters; 985 | 986 | output = ensure(output_buffer, output_length + sizeof("\"\"")); 987 | if (output == NULL) 988 | { 989 | return false; 990 | } 991 | 992 | /* no characters have to be escaped */ 993 | if (escape_characters == 0) 994 | { 995 | output[0] = '\"'; 996 | memcpy(output + 1, input, output_length); 997 | output[output_length + 1] = '\"'; 998 | output[output_length + 2] = '\0'; 999 | 1000 | return true; 1001 | } 1002 | 1003 | output[0] = '\"'; 1004 | output_pointer = output + 1; 1005 | /* copy the string */ 1006 | for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) 1007 | { 1008 | if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) 1009 | { 1010 | /* normal character, copy */ 1011 | *output_pointer = *input_pointer; 1012 | } 1013 | else 1014 | { 1015 | /* character needs to be escaped */ 1016 | *output_pointer++ = '\\'; 1017 | switch (*input_pointer) 1018 | { 1019 | case '\\': 1020 | *output_pointer = '\\'; 1021 | break; 1022 | case '\"': 1023 | *output_pointer = '\"'; 1024 | break; 1025 | case '\b': 1026 | *output_pointer = 'b'; 1027 | break; 1028 | case '\f': 1029 | *output_pointer = 'f'; 1030 | break; 1031 | case '\n': 1032 | *output_pointer = 'n'; 1033 | break; 1034 | case '\r': 1035 | *output_pointer = 'r'; 1036 | break; 1037 | case '\t': 1038 | *output_pointer = 't'; 1039 | break; 1040 | default: 1041 | /* escape and print as unicode codepoint */ 1042 | sprintf((char*)output_pointer, "u%04x", *input_pointer); 1043 | output_pointer += 4; 1044 | break; 1045 | } 1046 | } 1047 | } 1048 | output[output_length + 1] = '\"'; 1049 | output[output_length + 2] = '\0'; 1050 | 1051 | return true; 1052 | } 1053 | 1054 | /* Invoke print_string_ptr (which is useful) on an item. */ 1055 | static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) 1056 | { 1057 | return print_string_ptr((unsigned char*)item->valuestring, p); 1058 | } 1059 | 1060 | /* Predeclare these prototypes. */ 1061 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); 1062 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); 1063 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); 1064 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); 1065 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); 1066 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); 1067 | 1068 | /* Utility to jump whitespace and cr/lf */ 1069 | static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) 1070 | { 1071 | if ((buffer == NULL) || (buffer->content == NULL)) 1072 | { 1073 | return NULL; 1074 | } 1075 | 1076 | if (cannot_access_at_index(buffer, 0)) 1077 | { 1078 | return buffer; 1079 | } 1080 | 1081 | while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) 1082 | { 1083 | buffer->offset++; 1084 | } 1085 | 1086 | if (buffer->offset == buffer->length) 1087 | { 1088 | buffer->offset--; 1089 | } 1090 | 1091 | return buffer; 1092 | } 1093 | 1094 | /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ 1095 | static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) 1096 | { 1097 | if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) 1098 | { 1099 | return NULL; 1100 | } 1101 | 1102 | if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) 1103 | { 1104 | buffer->offset += 3; 1105 | } 1106 | 1107 | return buffer; 1108 | } 1109 | 1110 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) 1111 | { 1112 | size_t buffer_length; 1113 | 1114 | if (NULL == value) 1115 | { 1116 | return NULL; 1117 | } 1118 | 1119 | /* Adding null character size due to require_null_terminated. */ 1120 | buffer_length = strlen(value) + sizeof(""); 1121 | 1122 | return cJSON_ParseWithLengthOpts(value, buffer_length, return_parse_end, require_null_terminated); 1123 | } 1124 | 1125 | /* Parse an object - create a new root, and populate. */ 1126 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated) 1127 | { 1128 | parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; 1129 | cJSON *item = NULL; 1130 | 1131 | /* reset error position */ 1132 | global_error.json = NULL; 1133 | global_error.position = 0; 1134 | 1135 | if (value == NULL || 0 == buffer_length) 1136 | { 1137 | goto fail; 1138 | } 1139 | 1140 | buffer.content = (const unsigned char*)value; 1141 | buffer.length = buffer_length; 1142 | buffer.offset = 0; 1143 | buffer.hooks = global_hooks; 1144 | 1145 | item = cJSON_New_Item(&global_hooks); 1146 | if (item == NULL) /* memory fail */ 1147 | { 1148 | goto fail; 1149 | } 1150 | 1151 | if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) 1152 | { 1153 | /* parse failure. ep is set. */ 1154 | goto fail; 1155 | } 1156 | 1157 | /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ 1158 | if (require_null_terminated) 1159 | { 1160 | buffer_skip_whitespace(&buffer); 1161 | if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') 1162 | { 1163 | goto fail; 1164 | } 1165 | } 1166 | if (return_parse_end) 1167 | { 1168 | *return_parse_end = (const char*)buffer_at_offset(&buffer); 1169 | } 1170 | 1171 | return item; 1172 | 1173 | fail: 1174 | if (item != NULL) 1175 | { 1176 | cJSON_Delete(item); 1177 | } 1178 | 1179 | if (value != NULL) 1180 | { 1181 | error local_error; 1182 | local_error.json = (const unsigned char*)value; 1183 | local_error.position = 0; 1184 | 1185 | if (buffer.offset < buffer.length) 1186 | { 1187 | local_error.position = buffer.offset; 1188 | } 1189 | else if (buffer.length > 0) 1190 | { 1191 | local_error.position = buffer.length - 1; 1192 | } 1193 | 1194 | if (return_parse_end != NULL) 1195 | { 1196 | *return_parse_end = (const char*)local_error.json + local_error.position; 1197 | } 1198 | 1199 | global_error = local_error; 1200 | } 1201 | 1202 | return NULL; 1203 | } 1204 | 1205 | /* Default options for cJSON_Parse */ 1206 | CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) 1207 | { 1208 | return cJSON_ParseWithOpts(value, 0, 0); 1209 | } 1210 | 1211 | CJSON_PUBLIC(cJSON *) cJSON_ParseWithLength(const char *value, size_t buffer_length) 1212 | { 1213 | return cJSON_ParseWithLengthOpts(value, buffer_length, 0, 0); 1214 | } 1215 | 1216 | #define cjson_min(a, b) (((a) < (b)) ? (a) : (b)) 1217 | 1218 | static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) 1219 | { 1220 | static const size_t default_buffer_size = 256; 1221 | printbuffer buffer[1]; 1222 | unsigned char *printed = NULL; 1223 | 1224 | memset(buffer, 0, sizeof(buffer)); 1225 | 1226 | /* create buffer */ 1227 | buffer->buffer = (unsigned char*) hooks->allocate(default_buffer_size); 1228 | buffer->length = default_buffer_size; 1229 | buffer->format = format; 1230 | buffer->hooks = *hooks; 1231 | if (buffer->buffer == NULL) 1232 | { 1233 | goto fail; 1234 | } 1235 | 1236 | /* print the value */ 1237 | if (!print_value(item, buffer)) 1238 | { 1239 | goto fail; 1240 | } 1241 | update_offset(buffer); 1242 | 1243 | /* check if reallocate is available */ 1244 | if (hooks->reallocate != NULL) 1245 | { 1246 | printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->offset + 1); 1247 | if (printed == NULL) { 1248 | goto fail; 1249 | } 1250 | buffer->buffer = NULL; 1251 | } 1252 | else /* otherwise copy the JSON over to a new buffer */ 1253 | { 1254 | printed = (unsigned char*) hooks->allocate(buffer->offset + 1); 1255 | if (printed == NULL) 1256 | { 1257 | goto fail; 1258 | } 1259 | memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); 1260 | printed[buffer->offset] = '\0'; /* just to be sure */ 1261 | 1262 | /* free the buffer */ 1263 | hooks->deallocate(buffer->buffer); 1264 | } 1265 | 1266 | return printed; 1267 | 1268 | fail: 1269 | if (buffer->buffer != NULL) 1270 | { 1271 | hooks->deallocate(buffer->buffer); 1272 | } 1273 | 1274 | if (printed != NULL) 1275 | { 1276 | hooks->deallocate(printed); 1277 | } 1278 | 1279 | return NULL; 1280 | } 1281 | 1282 | /* Render a cJSON item/entity/structure to text. */ 1283 | CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) 1284 | { 1285 | return (char*)print(item, true, &global_hooks); 1286 | } 1287 | 1288 | CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) 1289 | { 1290 | return (char*)print(item, false, &global_hooks); 1291 | } 1292 | 1293 | CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) 1294 | { 1295 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1296 | 1297 | if (prebuffer < 0) 1298 | { 1299 | return NULL; 1300 | } 1301 | 1302 | p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); 1303 | if (!p.buffer) 1304 | { 1305 | return NULL; 1306 | } 1307 | 1308 | p.length = (size_t)prebuffer; 1309 | p.offset = 0; 1310 | p.noalloc = false; 1311 | p.format = fmt; 1312 | p.hooks = global_hooks; 1313 | 1314 | if (!print_value(item, &p)) 1315 | { 1316 | global_hooks.deallocate(p.buffer); 1317 | return NULL; 1318 | } 1319 | 1320 | return (char*)p.buffer; 1321 | } 1322 | 1323 | CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format) 1324 | { 1325 | printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; 1326 | 1327 | if ((length < 0) || (buffer == NULL)) 1328 | { 1329 | return false; 1330 | } 1331 | 1332 | p.buffer = (unsigned char*)buffer; 1333 | p.length = (size_t)length; 1334 | p.offset = 0; 1335 | p.noalloc = true; 1336 | p.format = format; 1337 | p.hooks = global_hooks; 1338 | 1339 | return print_value(item, &p); 1340 | } 1341 | 1342 | /* Parser core - when encountering text, process appropriately. */ 1343 | static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) 1344 | { 1345 | if ((input_buffer == NULL) || (input_buffer->content == NULL)) 1346 | { 1347 | return false; /* no input */ 1348 | } 1349 | 1350 | /* parse the different types of values */ 1351 | /* null */ 1352 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) 1353 | { 1354 | item->type = cJSON_NULL; 1355 | input_buffer->offset += 4; 1356 | return true; 1357 | } 1358 | /* false */ 1359 | if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) 1360 | { 1361 | item->type = cJSON_False; 1362 | input_buffer->offset += 5; 1363 | return true; 1364 | } 1365 | /* true */ 1366 | if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) 1367 | { 1368 | item->type = cJSON_True; 1369 | item->valueint = 1; 1370 | input_buffer->offset += 4; 1371 | return true; 1372 | } 1373 | /* string */ 1374 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) 1375 | { 1376 | return parse_string(item, input_buffer); 1377 | } 1378 | /* number */ 1379 | 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')))) 1380 | { 1381 | return parse_number(item, input_buffer); 1382 | } 1383 | /* array */ 1384 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) 1385 | { 1386 | return parse_array(item, input_buffer); 1387 | } 1388 | /* object */ 1389 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) 1390 | { 1391 | return parse_object(item, input_buffer); 1392 | } 1393 | 1394 | return false; 1395 | } 1396 | 1397 | /* Render a value to text. */ 1398 | static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) 1399 | { 1400 | unsigned char *output = NULL; 1401 | 1402 | if ((item == NULL) || (output_buffer == NULL)) 1403 | { 1404 | return false; 1405 | } 1406 | 1407 | switch ((item->type) & 0xFF) 1408 | { 1409 | case cJSON_NULL: 1410 | output = ensure(output_buffer, 5); 1411 | if (output == NULL) 1412 | { 1413 | return false; 1414 | } 1415 | strcpy((char*)output, "null"); 1416 | return true; 1417 | 1418 | case cJSON_False: 1419 | output = ensure(output_buffer, 6); 1420 | if (output == NULL) 1421 | { 1422 | return false; 1423 | } 1424 | strcpy((char*)output, "false"); 1425 | return true; 1426 | 1427 | case cJSON_True: 1428 | output = ensure(output_buffer, 5); 1429 | if (output == NULL) 1430 | { 1431 | return false; 1432 | } 1433 | strcpy((char*)output, "true"); 1434 | return true; 1435 | 1436 | case cJSON_Number: 1437 | return print_number(item, output_buffer); 1438 | 1439 | case cJSON_Raw: 1440 | { 1441 | size_t raw_length = 0; 1442 | if (item->valuestring == NULL) 1443 | { 1444 | return false; 1445 | } 1446 | 1447 | raw_length = strlen(item->valuestring) + sizeof(""); 1448 | output = ensure(output_buffer, raw_length); 1449 | if (output == NULL) 1450 | { 1451 | return false; 1452 | } 1453 | memcpy(output, item->valuestring, raw_length); 1454 | return true; 1455 | } 1456 | 1457 | case cJSON_String: 1458 | return print_string(item, output_buffer); 1459 | 1460 | case cJSON_Array: 1461 | return print_array(item, output_buffer); 1462 | 1463 | case cJSON_Object: 1464 | return print_object(item, output_buffer); 1465 | 1466 | default: 1467 | return false; 1468 | } 1469 | } 1470 | 1471 | /* Build an array from input text. */ 1472 | static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) 1473 | { 1474 | cJSON *head = NULL; /* head of the linked list */ 1475 | cJSON *current_item = NULL; 1476 | 1477 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1478 | { 1479 | return false; /* to deeply nested */ 1480 | } 1481 | input_buffer->depth++; 1482 | 1483 | if (buffer_at_offset(input_buffer)[0] != '[') 1484 | { 1485 | /* not an array */ 1486 | goto fail; 1487 | } 1488 | 1489 | input_buffer->offset++; 1490 | buffer_skip_whitespace(input_buffer); 1491 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) 1492 | { 1493 | /* empty array */ 1494 | goto success; 1495 | } 1496 | 1497 | /* check if we skipped to the end of the buffer */ 1498 | if (cannot_access_at_index(input_buffer, 0)) 1499 | { 1500 | input_buffer->offset--; 1501 | goto fail; 1502 | } 1503 | 1504 | /* step back to character in front of the first element */ 1505 | input_buffer->offset--; 1506 | /* loop through the comma separated array elements */ 1507 | do 1508 | { 1509 | /* allocate next item */ 1510 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1511 | if (new_item == NULL) 1512 | { 1513 | goto fail; /* allocation failure */ 1514 | } 1515 | 1516 | /* attach next item to list */ 1517 | if (head == NULL) 1518 | { 1519 | /* start the linked list */ 1520 | current_item = head = new_item; 1521 | } 1522 | else 1523 | { 1524 | /* add to the end and advance */ 1525 | current_item->next = new_item; 1526 | new_item->prev = current_item; 1527 | current_item = new_item; 1528 | } 1529 | 1530 | /* parse next value */ 1531 | input_buffer->offset++; 1532 | buffer_skip_whitespace(input_buffer); 1533 | if (!parse_value(current_item, input_buffer)) 1534 | { 1535 | goto fail; /* failed to parse value */ 1536 | } 1537 | buffer_skip_whitespace(input_buffer); 1538 | } 1539 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1540 | 1541 | if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') 1542 | { 1543 | goto fail; /* expected end of array */ 1544 | } 1545 | 1546 | success: 1547 | input_buffer->depth--; 1548 | 1549 | if (head != NULL) { 1550 | head->prev = current_item; 1551 | } 1552 | 1553 | item->type = cJSON_Array; 1554 | item->child = head; 1555 | 1556 | input_buffer->offset++; 1557 | 1558 | return true; 1559 | 1560 | fail: 1561 | if (head != NULL) 1562 | { 1563 | cJSON_Delete(head); 1564 | } 1565 | 1566 | return false; 1567 | } 1568 | 1569 | /* Render an array to text */ 1570 | static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) 1571 | { 1572 | unsigned char *output_pointer = NULL; 1573 | size_t length = 0; 1574 | cJSON *current_element = item->child; 1575 | 1576 | if (output_buffer == NULL) 1577 | { 1578 | return false; 1579 | } 1580 | 1581 | /* Compose the output array. */ 1582 | /* opening square bracket */ 1583 | output_pointer = ensure(output_buffer, 1); 1584 | if (output_pointer == NULL) 1585 | { 1586 | return false; 1587 | } 1588 | 1589 | *output_pointer = '['; 1590 | output_buffer->offset++; 1591 | output_buffer->depth++; 1592 | 1593 | while (current_element != NULL) 1594 | { 1595 | if (!print_value(current_element, output_buffer)) 1596 | { 1597 | return false; 1598 | } 1599 | update_offset(output_buffer); 1600 | if (current_element->next) 1601 | { 1602 | length = (size_t) (output_buffer->format ? 2 : 1); 1603 | output_pointer = ensure(output_buffer, length + 1); 1604 | if (output_pointer == NULL) 1605 | { 1606 | return false; 1607 | } 1608 | *output_pointer++ = ','; 1609 | if(output_buffer->format) 1610 | { 1611 | *output_pointer++ = ' '; 1612 | } 1613 | *output_pointer = '\0'; 1614 | output_buffer->offset += length; 1615 | } 1616 | current_element = current_element->next; 1617 | } 1618 | 1619 | output_pointer = ensure(output_buffer, 2); 1620 | if (output_pointer == NULL) 1621 | { 1622 | return false; 1623 | } 1624 | *output_pointer++ = ']'; 1625 | *output_pointer = '\0'; 1626 | output_buffer->depth--; 1627 | 1628 | return true; 1629 | } 1630 | 1631 | /* Build an object from the text. */ 1632 | static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) 1633 | { 1634 | cJSON *head = NULL; /* linked list head */ 1635 | cJSON *current_item = NULL; 1636 | 1637 | if (input_buffer->depth >= CJSON_NESTING_LIMIT) 1638 | { 1639 | return false; /* to deeply nested */ 1640 | } 1641 | input_buffer->depth++; 1642 | 1643 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) 1644 | { 1645 | goto fail; /* not an object */ 1646 | } 1647 | 1648 | input_buffer->offset++; 1649 | buffer_skip_whitespace(input_buffer); 1650 | if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) 1651 | { 1652 | goto success; /* empty object */ 1653 | } 1654 | 1655 | /* check if we skipped to the end of the buffer */ 1656 | if (cannot_access_at_index(input_buffer, 0)) 1657 | { 1658 | input_buffer->offset--; 1659 | goto fail; 1660 | } 1661 | 1662 | /* step back to character in front of the first element */ 1663 | input_buffer->offset--; 1664 | /* loop through the comma separated array elements */ 1665 | do 1666 | { 1667 | /* allocate next item */ 1668 | cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); 1669 | if (new_item == NULL) 1670 | { 1671 | goto fail; /* allocation failure */ 1672 | } 1673 | 1674 | /* attach next item to list */ 1675 | if (head == NULL) 1676 | { 1677 | /* start the linked list */ 1678 | current_item = head = new_item; 1679 | } 1680 | else 1681 | { 1682 | /* add to the end and advance */ 1683 | current_item->next = new_item; 1684 | new_item->prev = current_item; 1685 | current_item = new_item; 1686 | } 1687 | 1688 | /* parse the name of the child */ 1689 | input_buffer->offset++; 1690 | buffer_skip_whitespace(input_buffer); 1691 | if (!parse_string(current_item, input_buffer)) 1692 | { 1693 | goto fail; /* failed to parse name */ 1694 | } 1695 | buffer_skip_whitespace(input_buffer); 1696 | 1697 | /* swap valuestring and string, because we parsed the name */ 1698 | current_item->string = current_item->valuestring; 1699 | current_item->valuestring = NULL; 1700 | 1701 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) 1702 | { 1703 | goto fail; /* invalid object */ 1704 | } 1705 | 1706 | /* parse the value */ 1707 | input_buffer->offset++; 1708 | buffer_skip_whitespace(input_buffer); 1709 | if (!parse_value(current_item, input_buffer)) 1710 | { 1711 | goto fail; /* failed to parse value */ 1712 | } 1713 | buffer_skip_whitespace(input_buffer); 1714 | } 1715 | while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); 1716 | 1717 | if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) 1718 | { 1719 | goto fail; /* expected end of object */ 1720 | } 1721 | 1722 | success: 1723 | input_buffer->depth--; 1724 | 1725 | if (head != NULL) { 1726 | head->prev = current_item; 1727 | } 1728 | 1729 | item->type = cJSON_Object; 1730 | item->child = head; 1731 | 1732 | input_buffer->offset++; 1733 | return true; 1734 | 1735 | fail: 1736 | if (head != NULL) 1737 | { 1738 | cJSON_Delete(head); 1739 | } 1740 | 1741 | return false; 1742 | } 1743 | 1744 | /* Render an object to text. */ 1745 | static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) 1746 | { 1747 | unsigned char *output_pointer = NULL; 1748 | size_t length = 0; 1749 | cJSON *current_item = item->child; 1750 | 1751 | if (output_buffer == NULL) 1752 | { 1753 | return false; 1754 | } 1755 | 1756 | /* Compose the output: */ 1757 | length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ 1758 | output_pointer = ensure(output_buffer, length + 1); 1759 | if (output_pointer == NULL) 1760 | { 1761 | return false; 1762 | } 1763 | 1764 | *output_pointer++ = '{'; 1765 | output_buffer->depth++; 1766 | if (output_buffer->format) 1767 | { 1768 | *output_pointer++ = '\n'; 1769 | } 1770 | output_buffer->offset += length; 1771 | 1772 | while (current_item) 1773 | { 1774 | if (output_buffer->format) 1775 | { 1776 | size_t i; 1777 | output_pointer = ensure(output_buffer, output_buffer->depth); 1778 | if (output_pointer == NULL) 1779 | { 1780 | return false; 1781 | } 1782 | for (i = 0; i < output_buffer->depth; i++) 1783 | { 1784 | *output_pointer++ = '\t'; 1785 | } 1786 | output_buffer->offset += output_buffer->depth; 1787 | } 1788 | 1789 | /* print key */ 1790 | if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) 1791 | { 1792 | return false; 1793 | } 1794 | update_offset(output_buffer); 1795 | 1796 | length = (size_t) (output_buffer->format ? 2 : 1); 1797 | output_pointer = ensure(output_buffer, length); 1798 | if (output_pointer == NULL) 1799 | { 1800 | return false; 1801 | } 1802 | *output_pointer++ = ':'; 1803 | if (output_buffer->format) 1804 | { 1805 | *output_pointer++ = '\t'; 1806 | } 1807 | output_buffer->offset += length; 1808 | 1809 | /* print value */ 1810 | if (!print_value(current_item, output_buffer)) 1811 | { 1812 | return false; 1813 | } 1814 | update_offset(output_buffer); 1815 | 1816 | /* print comma if not last */ 1817 | length = ((size_t)(output_buffer->format ? 1 : 0) + (size_t)(current_item->next ? 1 : 0)); 1818 | output_pointer = ensure(output_buffer, length + 1); 1819 | if (output_pointer == NULL) 1820 | { 1821 | return false; 1822 | } 1823 | if (current_item->next) 1824 | { 1825 | *output_pointer++ = ','; 1826 | } 1827 | 1828 | if (output_buffer->format) 1829 | { 1830 | *output_pointer++ = '\n'; 1831 | } 1832 | *output_pointer = '\0'; 1833 | output_buffer->offset += length; 1834 | 1835 | current_item = current_item->next; 1836 | } 1837 | 1838 | output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); 1839 | if (output_pointer == NULL) 1840 | { 1841 | return false; 1842 | } 1843 | if (output_buffer->format) 1844 | { 1845 | size_t i; 1846 | for (i = 0; i < (output_buffer->depth - 1); i++) 1847 | { 1848 | *output_pointer++ = '\t'; 1849 | } 1850 | } 1851 | *output_pointer++ = '}'; 1852 | *output_pointer = '\0'; 1853 | output_buffer->depth--; 1854 | 1855 | return true; 1856 | } 1857 | 1858 | /* Get Array size/item / object item. */ 1859 | CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) 1860 | { 1861 | cJSON *child = NULL; 1862 | size_t size = 0; 1863 | 1864 | if (array == NULL) 1865 | { 1866 | return 0; 1867 | } 1868 | 1869 | child = array->child; 1870 | 1871 | while(child != NULL) 1872 | { 1873 | size++; 1874 | child = child->next; 1875 | } 1876 | 1877 | /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ 1878 | 1879 | return (int)size; 1880 | } 1881 | 1882 | static cJSON* get_array_item(const cJSON *array, size_t index) 1883 | { 1884 | cJSON *current_child = NULL; 1885 | 1886 | if (array == NULL) 1887 | { 1888 | return NULL; 1889 | } 1890 | 1891 | current_child = array->child; 1892 | while ((current_child != NULL) && (index > 0)) 1893 | { 1894 | index--; 1895 | current_child = current_child->next; 1896 | } 1897 | 1898 | return current_child; 1899 | } 1900 | 1901 | CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) 1902 | { 1903 | if (index < 0) 1904 | { 1905 | return NULL; 1906 | } 1907 | 1908 | return get_array_item(array, (size_t)index); 1909 | } 1910 | 1911 | static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) 1912 | { 1913 | cJSON *current_element = NULL; 1914 | 1915 | if ((object == NULL) || (name == NULL)) 1916 | { 1917 | return NULL; 1918 | } 1919 | 1920 | current_element = object->child; 1921 | if (case_sensitive) 1922 | { 1923 | while ((current_element != NULL) && (current_element->string != NULL) && (strcmp(name, current_element->string) != 0)) 1924 | { 1925 | current_element = current_element->next; 1926 | } 1927 | } 1928 | else 1929 | { 1930 | while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) 1931 | { 1932 | current_element = current_element->next; 1933 | } 1934 | } 1935 | 1936 | if ((current_element == NULL) || (current_element->string == NULL)) { 1937 | return NULL; 1938 | } 1939 | 1940 | return current_element; 1941 | } 1942 | 1943 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) 1944 | { 1945 | return get_object_item(object, string, false); 1946 | } 1947 | 1948 | CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) 1949 | { 1950 | return get_object_item(object, string, true); 1951 | } 1952 | 1953 | CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) 1954 | { 1955 | return cJSON_GetObjectItem(object, string) ? 1 : 0; 1956 | } 1957 | 1958 | /* Utility for array list handling. */ 1959 | static void suffix_object(cJSON *prev, cJSON *item) 1960 | { 1961 | prev->next = item; 1962 | item->prev = prev; 1963 | } 1964 | 1965 | /* Utility for handling references. */ 1966 | static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) 1967 | { 1968 | cJSON *reference = NULL; 1969 | if (item == NULL) 1970 | { 1971 | return NULL; 1972 | } 1973 | 1974 | reference = cJSON_New_Item(hooks); 1975 | if (reference == NULL) 1976 | { 1977 | return NULL; 1978 | } 1979 | 1980 | memcpy(reference, item, sizeof(cJSON)); 1981 | reference->string = NULL; 1982 | reference->type |= cJSON_IsReference; 1983 | reference->next = reference->prev = NULL; 1984 | return reference; 1985 | } 1986 | 1987 | static cJSON_bool add_item_to_array(cJSON *array, cJSON *item) 1988 | { 1989 | cJSON *child = NULL; 1990 | 1991 | if ((item == NULL) || (array == NULL) || (array == item)) 1992 | { 1993 | return false; 1994 | } 1995 | 1996 | child = array->child; 1997 | /* 1998 | * To find the last item in array quickly, we use prev in array 1999 | */ 2000 | if (child == NULL) 2001 | { 2002 | /* list is empty, start new one */ 2003 | array->child = item; 2004 | item->prev = item; 2005 | item->next = NULL; 2006 | } 2007 | else 2008 | { 2009 | /* append to the end */ 2010 | if (child->prev) 2011 | { 2012 | suffix_object(child->prev, item); 2013 | array->child->prev = item; 2014 | } 2015 | } 2016 | 2017 | return true; 2018 | } 2019 | 2020 | /* Add item to array/object. */ 2021 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToArray(cJSON *array, cJSON *item) 2022 | { 2023 | return add_item_to_array(array, item); 2024 | } 2025 | 2026 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2027 | #pragma GCC diagnostic push 2028 | #endif 2029 | #ifdef __GNUC__ 2030 | #pragma GCC diagnostic ignored "-Wcast-qual" 2031 | #endif 2032 | /* helper function to cast away const */ 2033 | static void* cast_away_const(const void* string) 2034 | { 2035 | return (void*)string; 2036 | } 2037 | #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) 2038 | #pragma GCC diagnostic pop 2039 | #endif 2040 | 2041 | 2042 | 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) 2043 | { 2044 | char *new_key = NULL; 2045 | int new_type = cJSON_Invalid; 2046 | 2047 | if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)) 2048 | { 2049 | return false; 2050 | } 2051 | 2052 | if (constant_key) 2053 | { 2054 | new_key = (char*)cast_away_const(string); 2055 | new_type = item->type | cJSON_StringIsConst; 2056 | } 2057 | else 2058 | { 2059 | new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks); 2060 | if (new_key == NULL) 2061 | { 2062 | return false; 2063 | } 2064 | 2065 | new_type = item->type & ~cJSON_StringIsConst; 2066 | } 2067 | 2068 | if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) 2069 | { 2070 | hooks->deallocate(item->string); 2071 | } 2072 | 2073 | item->string = new_key; 2074 | item->type = new_type; 2075 | 2076 | return add_item_to_array(object, item); 2077 | } 2078 | 2079 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) 2080 | { 2081 | return add_item_to_object(object, string, item, &global_hooks, false); 2082 | } 2083 | 2084 | /* Add an item to an object with constant string as key */ 2085 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) 2086 | { 2087 | return add_item_to_object(object, string, item, &global_hooks, true); 2088 | } 2089 | 2090 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) 2091 | { 2092 | if (array == NULL) 2093 | { 2094 | return false; 2095 | } 2096 | 2097 | return add_item_to_array(array, create_reference(item, &global_hooks)); 2098 | } 2099 | 2100 | CJSON_PUBLIC(cJSON_bool) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) 2101 | { 2102 | if ((object == NULL) || (string == NULL)) 2103 | { 2104 | return false; 2105 | } 2106 | 2107 | return add_item_to_object(object, string, create_reference(item, &global_hooks), &global_hooks, false); 2108 | } 2109 | 2110 | CJSON_PUBLIC(cJSON*) cJSON_AddNullToObject(cJSON * const object, const char * const name) 2111 | { 2112 | cJSON *null = cJSON_CreateNull(); 2113 | if (add_item_to_object(object, name, null, &global_hooks, false)) 2114 | { 2115 | return null; 2116 | } 2117 | 2118 | cJSON_Delete(null); 2119 | return NULL; 2120 | } 2121 | 2122 | CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name) 2123 | { 2124 | cJSON *true_item = cJSON_CreateTrue(); 2125 | if (add_item_to_object(object, name, true_item, &global_hooks, false)) 2126 | { 2127 | return true_item; 2128 | } 2129 | 2130 | cJSON_Delete(true_item); 2131 | return NULL; 2132 | } 2133 | 2134 | CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name) 2135 | { 2136 | cJSON *false_item = cJSON_CreateFalse(); 2137 | if (add_item_to_object(object, name, false_item, &global_hooks, false)) 2138 | { 2139 | return false_item; 2140 | } 2141 | 2142 | cJSON_Delete(false_item); 2143 | return NULL; 2144 | } 2145 | 2146 | CJSON_PUBLIC(cJSON*) cJSON_AddBoolToObject(cJSON * const object, const char * const name, const cJSON_bool boolean) 2147 | { 2148 | cJSON *bool_item = cJSON_CreateBool(boolean); 2149 | if (add_item_to_object(object, name, bool_item, &global_hooks, false)) 2150 | { 2151 | return bool_item; 2152 | } 2153 | 2154 | cJSON_Delete(bool_item); 2155 | return NULL; 2156 | } 2157 | 2158 | CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number) 2159 | { 2160 | cJSON *number_item = cJSON_CreateNumber(number); 2161 | if (add_item_to_object(object, name, number_item, &global_hooks, false)) 2162 | { 2163 | return number_item; 2164 | } 2165 | 2166 | cJSON_Delete(number_item); 2167 | return NULL; 2168 | } 2169 | 2170 | CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string) 2171 | { 2172 | cJSON *string_item = cJSON_CreateString(string); 2173 | if (add_item_to_object(object, name, string_item, &global_hooks, false)) 2174 | { 2175 | return string_item; 2176 | } 2177 | 2178 | cJSON_Delete(string_item); 2179 | return NULL; 2180 | } 2181 | 2182 | CJSON_PUBLIC(cJSON*) cJSON_AddRawToObject(cJSON * const object, const char * const name, const char * const raw) 2183 | { 2184 | cJSON *raw_item = cJSON_CreateRaw(raw); 2185 | if (add_item_to_object(object, name, raw_item, &global_hooks, false)) 2186 | { 2187 | return raw_item; 2188 | } 2189 | 2190 | cJSON_Delete(raw_item); 2191 | return NULL; 2192 | } 2193 | 2194 | CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name) 2195 | { 2196 | cJSON *object_item = cJSON_CreateObject(); 2197 | if (add_item_to_object(object, name, object_item, &global_hooks, false)) 2198 | { 2199 | return object_item; 2200 | } 2201 | 2202 | cJSON_Delete(object_item); 2203 | return NULL; 2204 | } 2205 | 2206 | CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name) 2207 | { 2208 | cJSON *array = cJSON_CreateArray(); 2209 | if (add_item_to_object(object, name, array, &global_hooks, false)) 2210 | { 2211 | return array; 2212 | } 2213 | 2214 | cJSON_Delete(array); 2215 | return NULL; 2216 | } 2217 | 2218 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) 2219 | { 2220 | if ((parent == NULL) || (item == NULL)) 2221 | { 2222 | return NULL; 2223 | } 2224 | 2225 | if (item != parent->child) 2226 | { 2227 | /* not the first element */ 2228 | item->prev->next = item->next; 2229 | } 2230 | if (item->next != NULL) 2231 | { 2232 | /* not the last element */ 2233 | item->next->prev = item->prev; 2234 | } 2235 | 2236 | if (item == parent->child) 2237 | { 2238 | /* first element */ 2239 | parent->child = item->next; 2240 | } 2241 | else if (item->next == NULL) 2242 | { 2243 | /* last element */ 2244 | parent->child->prev = item->prev; 2245 | } 2246 | 2247 | /* make sure the detached item doesn't point anywhere anymore */ 2248 | item->prev = NULL; 2249 | item->next = NULL; 2250 | 2251 | return item; 2252 | } 2253 | 2254 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) 2255 | { 2256 | if (which < 0) 2257 | { 2258 | return NULL; 2259 | } 2260 | 2261 | return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); 2262 | } 2263 | 2264 | CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) 2265 | { 2266 | cJSON_Delete(cJSON_DetachItemFromArray(array, which)); 2267 | } 2268 | 2269 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) 2270 | { 2271 | cJSON *to_detach = cJSON_GetObjectItem(object, string); 2272 | 2273 | return cJSON_DetachItemViaPointer(object, to_detach); 2274 | } 2275 | 2276 | CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) 2277 | { 2278 | cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); 2279 | 2280 | return cJSON_DetachItemViaPointer(object, to_detach); 2281 | } 2282 | 2283 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) 2284 | { 2285 | cJSON_Delete(cJSON_DetachItemFromObject(object, string)); 2286 | } 2287 | 2288 | CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) 2289 | { 2290 | cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); 2291 | } 2292 | 2293 | /* Replace array/object items with new ones. */ 2294 | CJSON_PUBLIC(cJSON_bool) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) 2295 | { 2296 | cJSON *after_inserted = NULL; 2297 | 2298 | if (which < 0) 2299 | { 2300 | return false; 2301 | } 2302 | 2303 | after_inserted = get_array_item(array, (size_t)which); 2304 | if (after_inserted == NULL) 2305 | { 2306 | return add_item_to_array(array, newitem); 2307 | } 2308 | 2309 | newitem->next = after_inserted; 2310 | newitem->prev = after_inserted->prev; 2311 | after_inserted->prev = newitem; 2312 | if (after_inserted == array->child) 2313 | { 2314 | array->child = newitem; 2315 | } 2316 | else 2317 | { 2318 | newitem->prev->next = newitem; 2319 | } 2320 | return true; 2321 | } 2322 | 2323 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) 2324 | { 2325 | if ((parent == NULL) || (replacement == NULL) || (item == NULL)) 2326 | { 2327 | return false; 2328 | } 2329 | 2330 | if (replacement == item) 2331 | { 2332 | return true; 2333 | } 2334 | 2335 | replacement->next = item->next; 2336 | replacement->prev = item->prev; 2337 | 2338 | if (replacement->next != NULL) 2339 | { 2340 | replacement->next->prev = replacement; 2341 | } 2342 | if (parent->child == item) 2343 | { 2344 | if (parent->child->prev == parent->child) 2345 | { 2346 | replacement->prev = replacement; 2347 | } 2348 | parent->child = replacement; 2349 | } 2350 | else 2351 | { /* 2352 | * To find the last item in array quickly, we use prev in array. 2353 | * We can't modify the last item's next pointer where this item was the parent's child 2354 | */ 2355 | if (replacement->prev != NULL) 2356 | { 2357 | replacement->prev->next = replacement; 2358 | } 2359 | if (replacement->next == NULL) 2360 | { 2361 | parent->child->prev = replacement; 2362 | } 2363 | } 2364 | 2365 | item->next = NULL; 2366 | item->prev = NULL; 2367 | cJSON_Delete(item); 2368 | 2369 | return true; 2370 | } 2371 | 2372 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) 2373 | { 2374 | if (which < 0) 2375 | { 2376 | return false; 2377 | } 2378 | 2379 | return cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); 2380 | } 2381 | 2382 | static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) 2383 | { 2384 | if ((replacement == NULL) || (string == NULL)) 2385 | { 2386 | return false; 2387 | } 2388 | 2389 | /* replace the name in the replacement */ 2390 | if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) 2391 | { 2392 | cJSON_free(replacement->string); 2393 | } 2394 | replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2395 | replacement->type &= ~cJSON_StringIsConst; 2396 | 2397 | return cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); 2398 | } 2399 | 2400 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) 2401 | { 2402 | return replace_item_in_object(object, string, newitem, false); 2403 | } 2404 | 2405 | CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) 2406 | { 2407 | return replace_item_in_object(object, string, newitem, true); 2408 | } 2409 | 2410 | /* Create basic types: */ 2411 | CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) 2412 | { 2413 | cJSON *item = cJSON_New_Item(&global_hooks); 2414 | if(item) 2415 | { 2416 | item->type = cJSON_NULL; 2417 | } 2418 | 2419 | return item; 2420 | } 2421 | 2422 | CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) 2423 | { 2424 | cJSON *item = cJSON_New_Item(&global_hooks); 2425 | if(item) 2426 | { 2427 | item->type = cJSON_True; 2428 | } 2429 | 2430 | return item; 2431 | } 2432 | 2433 | CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) 2434 | { 2435 | cJSON *item = cJSON_New_Item(&global_hooks); 2436 | if(item) 2437 | { 2438 | item->type = cJSON_False; 2439 | } 2440 | 2441 | return item; 2442 | } 2443 | 2444 | CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean) 2445 | { 2446 | cJSON *item = cJSON_New_Item(&global_hooks); 2447 | if(item) 2448 | { 2449 | item->type = boolean ? cJSON_True : cJSON_False; 2450 | } 2451 | 2452 | return item; 2453 | } 2454 | 2455 | CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) 2456 | { 2457 | cJSON *item = cJSON_New_Item(&global_hooks); 2458 | if(item) 2459 | { 2460 | item->type = cJSON_Number; 2461 | item->valuedouble = num; 2462 | 2463 | /* use saturation in case of overflow */ 2464 | if (num >= INT_MAX) 2465 | { 2466 | item->valueint = INT_MAX; 2467 | } 2468 | else if (num <= (double)INT_MIN) 2469 | { 2470 | item->valueint = INT_MIN; 2471 | } 2472 | else 2473 | { 2474 | item->valueint = (int)num; 2475 | } 2476 | } 2477 | 2478 | return item; 2479 | } 2480 | 2481 | CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) 2482 | { 2483 | cJSON *item = cJSON_New_Item(&global_hooks); 2484 | if(item) 2485 | { 2486 | item->type = cJSON_String; 2487 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); 2488 | if(!item->valuestring) 2489 | { 2490 | cJSON_Delete(item); 2491 | return NULL; 2492 | } 2493 | } 2494 | 2495 | return item; 2496 | } 2497 | 2498 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string) 2499 | { 2500 | cJSON *item = cJSON_New_Item(&global_hooks); 2501 | if (item != NULL) 2502 | { 2503 | item->type = cJSON_String | cJSON_IsReference; 2504 | item->valuestring = (char*)cast_away_const(string); 2505 | } 2506 | 2507 | return item; 2508 | } 2509 | 2510 | CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child) 2511 | { 2512 | cJSON *item = cJSON_New_Item(&global_hooks); 2513 | if (item != NULL) { 2514 | item->type = cJSON_Object | cJSON_IsReference; 2515 | item->child = (cJSON*)cast_away_const(child); 2516 | } 2517 | 2518 | return item; 2519 | } 2520 | 2521 | CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child) { 2522 | cJSON *item = cJSON_New_Item(&global_hooks); 2523 | if (item != NULL) { 2524 | item->type = cJSON_Array | cJSON_IsReference; 2525 | item->child = (cJSON*)cast_away_const(child); 2526 | } 2527 | 2528 | return item; 2529 | } 2530 | 2531 | CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) 2532 | { 2533 | cJSON *item = cJSON_New_Item(&global_hooks); 2534 | if(item) 2535 | { 2536 | item->type = cJSON_Raw; 2537 | item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); 2538 | if(!item->valuestring) 2539 | { 2540 | cJSON_Delete(item); 2541 | return NULL; 2542 | } 2543 | } 2544 | 2545 | return item; 2546 | } 2547 | 2548 | CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) 2549 | { 2550 | cJSON *item = cJSON_New_Item(&global_hooks); 2551 | if(item) 2552 | { 2553 | item->type=cJSON_Array; 2554 | } 2555 | 2556 | return item; 2557 | } 2558 | 2559 | CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) 2560 | { 2561 | cJSON *item = cJSON_New_Item(&global_hooks); 2562 | if (item) 2563 | { 2564 | item->type = cJSON_Object; 2565 | } 2566 | 2567 | return item; 2568 | } 2569 | 2570 | /* Create Arrays: */ 2571 | CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) 2572 | { 2573 | size_t i = 0; 2574 | cJSON *n = NULL; 2575 | cJSON *p = NULL; 2576 | cJSON *a = NULL; 2577 | 2578 | if ((count < 0) || (numbers == NULL)) 2579 | { 2580 | return NULL; 2581 | } 2582 | 2583 | a = cJSON_CreateArray(); 2584 | for(i = 0; a && (i < (size_t)count); i++) 2585 | { 2586 | n = cJSON_CreateNumber(numbers[i]); 2587 | if (!n) 2588 | { 2589 | cJSON_Delete(a); 2590 | return NULL; 2591 | } 2592 | if(!i) 2593 | { 2594 | a->child = n; 2595 | } 2596 | else 2597 | { 2598 | suffix_object(p, n); 2599 | } 2600 | p = n; 2601 | } 2602 | a->child->prev = n; 2603 | 2604 | return a; 2605 | } 2606 | 2607 | CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) 2608 | { 2609 | size_t i = 0; 2610 | cJSON *n = NULL; 2611 | cJSON *p = NULL; 2612 | cJSON *a = NULL; 2613 | 2614 | if ((count < 0) || (numbers == NULL)) 2615 | { 2616 | return NULL; 2617 | } 2618 | 2619 | a = cJSON_CreateArray(); 2620 | 2621 | for(i = 0; a && (i < (size_t)count); i++) 2622 | { 2623 | n = cJSON_CreateNumber((double)numbers[i]); 2624 | if(!n) 2625 | { 2626 | cJSON_Delete(a); 2627 | return NULL; 2628 | } 2629 | if(!i) 2630 | { 2631 | a->child = n; 2632 | } 2633 | else 2634 | { 2635 | suffix_object(p, n); 2636 | } 2637 | p = n; 2638 | } 2639 | a->child->prev = n; 2640 | 2641 | return a; 2642 | } 2643 | 2644 | CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) 2645 | { 2646 | size_t i = 0; 2647 | cJSON *n = NULL; 2648 | cJSON *p = NULL; 2649 | cJSON *a = NULL; 2650 | 2651 | if ((count < 0) || (numbers == NULL)) 2652 | { 2653 | return NULL; 2654 | } 2655 | 2656 | a = cJSON_CreateArray(); 2657 | 2658 | for(i = 0;a && (i < (size_t)count); i++) 2659 | { 2660 | n = cJSON_CreateNumber(numbers[i]); 2661 | if(!n) 2662 | { 2663 | cJSON_Delete(a); 2664 | return NULL; 2665 | } 2666 | if(!i) 2667 | { 2668 | a->child = n; 2669 | } 2670 | else 2671 | { 2672 | suffix_object(p, n); 2673 | } 2674 | p = n; 2675 | } 2676 | a->child->prev = n; 2677 | 2678 | return a; 2679 | } 2680 | 2681 | CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char *const *strings, int count) 2682 | { 2683 | size_t i = 0; 2684 | cJSON *n = NULL; 2685 | cJSON *p = NULL; 2686 | cJSON *a = NULL; 2687 | 2688 | if ((count < 0) || (strings == NULL)) 2689 | { 2690 | return NULL; 2691 | } 2692 | 2693 | a = cJSON_CreateArray(); 2694 | 2695 | for (i = 0; a && (i < (size_t)count); i++) 2696 | { 2697 | n = cJSON_CreateString(strings[i]); 2698 | if(!n) 2699 | { 2700 | cJSON_Delete(a); 2701 | return NULL; 2702 | } 2703 | if(!i) 2704 | { 2705 | a->child = n; 2706 | } 2707 | else 2708 | { 2709 | suffix_object(p,n); 2710 | } 2711 | p = n; 2712 | } 2713 | a->child->prev = n; 2714 | 2715 | return a; 2716 | } 2717 | 2718 | /* Duplication */ 2719 | CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) 2720 | { 2721 | cJSON *newitem = NULL; 2722 | cJSON *child = NULL; 2723 | cJSON *next = NULL; 2724 | cJSON *newchild = NULL; 2725 | 2726 | /* Bail on bad ptr */ 2727 | if (!item) 2728 | { 2729 | goto fail; 2730 | } 2731 | /* Create new item */ 2732 | newitem = cJSON_New_Item(&global_hooks); 2733 | if (!newitem) 2734 | { 2735 | goto fail; 2736 | } 2737 | /* Copy over all vars */ 2738 | newitem->type = item->type & (~cJSON_IsReference); 2739 | newitem->valueint = item->valueint; 2740 | newitem->valuedouble = item->valuedouble; 2741 | if (item->valuestring) 2742 | { 2743 | newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); 2744 | if (!newitem->valuestring) 2745 | { 2746 | goto fail; 2747 | } 2748 | } 2749 | if (item->string) 2750 | { 2751 | newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); 2752 | if (!newitem->string) 2753 | { 2754 | goto fail; 2755 | } 2756 | } 2757 | /* If non-recursive, then we're done! */ 2758 | if (!recurse) 2759 | { 2760 | return newitem; 2761 | } 2762 | /* Walk the ->next chain for the child. */ 2763 | child = item->child; 2764 | while (child != NULL) 2765 | { 2766 | newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ 2767 | if (!newchild) 2768 | { 2769 | goto fail; 2770 | } 2771 | if (next != NULL) 2772 | { 2773 | /* If newitem->child already set, then crosswire ->prev and ->next and move on */ 2774 | next->next = newchild; 2775 | newchild->prev = next; 2776 | next = newchild; 2777 | } 2778 | else 2779 | { 2780 | /* Set newitem->child and move to it */ 2781 | newitem->child = newchild; 2782 | next = newchild; 2783 | } 2784 | child = child->next; 2785 | } 2786 | if (newitem && newitem->child) 2787 | { 2788 | newitem->child->prev = newchild; 2789 | } 2790 | 2791 | return newitem; 2792 | 2793 | fail: 2794 | if (newitem != NULL) 2795 | { 2796 | cJSON_Delete(newitem); 2797 | } 2798 | 2799 | return NULL; 2800 | } 2801 | 2802 | static void skip_oneline_comment(char **input) 2803 | { 2804 | *input += static_strlen("//"); 2805 | 2806 | for (; (*input)[0] != '\0'; ++(*input)) 2807 | { 2808 | if ((*input)[0] == '\n') { 2809 | *input += static_strlen("\n"); 2810 | return; 2811 | } 2812 | } 2813 | } 2814 | 2815 | static void skip_multiline_comment(char **input) 2816 | { 2817 | *input += static_strlen("/*"); 2818 | 2819 | for (; (*input)[0] != '\0'; ++(*input)) 2820 | { 2821 | if (((*input)[0] == '*') && ((*input)[1] == '/')) 2822 | { 2823 | *input += static_strlen("*/"); 2824 | return; 2825 | } 2826 | } 2827 | } 2828 | 2829 | static void minify_string(char **input, char **output) { 2830 | (*output)[0] = (*input)[0]; 2831 | *input += static_strlen("\""); 2832 | *output += static_strlen("\""); 2833 | 2834 | 2835 | for (; (*input)[0] != '\0'; (void)++(*input), ++(*output)) { 2836 | (*output)[0] = (*input)[0]; 2837 | 2838 | if ((*input)[0] == '\"') { 2839 | (*output)[0] = '\"'; 2840 | *input += static_strlen("\""); 2841 | *output += static_strlen("\""); 2842 | return; 2843 | } else if (((*input)[0] == '\\') && ((*input)[1] == '\"')) { 2844 | (*output)[1] = (*input)[1]; 2845 | *input += static_strlen("\""); 2846 | *output += static_strlen("\""); 2847 | } 2848 | } 2849 | } 2850 | 2851 | CJSON_PUBLIC(void) cJSON_Minify(char *json) 2852 | { 2853 | char *into = json; 2854 | 2855 | if (json == NULL) 2856 | { 2857 | return; 2858 | } 2859 | 2860 | while (json[0] != '\0') 2861 | { 2862 | switch (json[0]) 2863 | { 2864 | case ' ': 2865 | case '\t': 2866 | case '\r': 2867 | case '\n': 2868 | json++; 2869 | break; 2870 | 2871 | case '/': 2872 | if (json[1] == '/') 2873 | { 2874 | skip_oneline_comment(&json); 2875 | } 2876 | else if (json[1] == '*') 2877 | { 2878 | skip_multiline_comment(&json); 2879 | } else { 2880 | json++; 2881 | } 2882 | break; 2883 | 2884 | case '\"': 2885 | minify_string(&json, (char**)&into); 2886 | break; 2887 | 2888 | default: 2889 | into[0] = json[0]; 2890 | json++; 2891 | into++; 2892 | } 2893 | } 2894 | 2895 | /* and null-terminate. */ 2896 | *into = '\0'; 2897 | } 2898 | 2899 | CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) 2900 | { 2901 | if (item == NULL) 2902 | { 2903 | return false; 2904 | } 2905 | 2906 | return (item->type & 0xFF) == cJSON_Invalid; 2907 | } 2908 | 2909 | CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) 2910 | { 2911 | if (item == NULL) 2912 | { 2913 | return false; 2914 | } 2915 | 2916 | return (item->type & 0xFF) == cJSON_False; 2917 | } 2918 | 2919 | CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) 2920 | { 2921 | if (item == NULL) 2922 | { 2923 | return false; 2924 | } 2925 | 2926 | return (item->type & 0xff) == cJSON_True; 2927 | } 2928 | 2929 | 2930 | CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) 2931 | { 2932 | if (item == NULL) 2933 | { 2934 | return false; 2935 | } 2936 | 2937 | return (item->type & (cJSON_True | cJSON_False)) != 0; 2938 | } 2939 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) 2940 | { 2941 | if (item == NULL) 2942 | { 2943 | return false; 2944 | } 2945 | 2946 | return (item->type & 0xFF) == cJSON_NULL; 2947 | } 2948 | 2949 | CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) 2950 | { 2951 | if (item == NULL) 2952 | { 2953 | return false; 2954 | } 2955 | 2956 | return (item->type & 0xFF) == cJSON_Number; 2957 | } 2958 | 2959 | CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) 2960 | { 2961 | if (item == NULL) 2962 | { 2963 | return false; 2964 | } 2965 | 2966 | return (item->type & 0xFF) == cJSON_String; 2967 | } 2968 | 2969 | CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) 2970 | { 2971 | if (item == NULL) 2972 | { 2973 | return false; 2974 | } 2975 | 2976 | return (item->type & 0xFF) == cJSON_Array; 2977 | } 2978 | 2979 | CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) 2980 | { 2981 | if (item == NULL) 2982 | { 2983 | return false; 2984 | } 2985 | 2986 | return (item->type & 0xFF) == cJSON_Object; 2987 | } 2988 | 2989 | CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) 2990 | { 2991 | if (item == NULL) 2992 | { 2993 | return false; 2994 | } 2995 | 2996 | return (item->type & 0xFF) == cJSON_Raw; 2997 | } 2998 | 2999 | CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) 3000 | { 3001 | if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) 3002 | { 3003 | return false; 3004 | } 3005 | 3006 | /* check if type is valid */ 3007 | switch (a->type & 0xFF) 3008 | { 3009 | case cJSON_False: 3010 | case cJSON_True: 3011 | case cJSON_NULL: 3012 | case cJSON_Number: 3013 | case cJSON_String: 3014 | case cJSON_Raw: 3015 | case cJSON_Array: 3016 | case cJSON_Object: 3017 | break; 3018 | 3019 | default: 3020 | return false; 3021 | } 3022 | 3023 | /* identical objects are equal */ 3024 | if (a == b) 3025 | { 3026 | return true; 3027 | } 3028 | 3029 | switch (a->type & 0xFF) 3030 | { 3031 | /* in these cases and equal type is enough */ 3032 | case cJSON_False: 3033 | case cJSON_True: 3034 | case cJSON_NULL: 3035 | return true; 3036 | 3037 | case cJSON_Number: 3038 | if (compare_double(a->valuedouble, b->valuedouble)) 3039 | { 3040 | return true; 3041 | } 3042 | return false; 3043 | 3044 | case cJSON_String: 3045 | case cJSON_Raw: 3046 | if ((a->valuestring == NULL) || (b->valuestring == NULL)) 3047 | { 3048 | return false; 3049 | } 3050 | if (strcmp(a->valuestring, b->valuestring) == 0) 3051 | { 3052 | return true; 3053 | } 3054 | 3055 | return false; 3056 | 3057 | case cJSON_Array: 3058 | { 3059 | cJSON *a_element = a->child; 3060 | cJSON *b_element = b->child; 3061 | 3062 | for (; (a_element != NULL) && (b_element != NULL);) 3063 | { 3064 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3065 | { 3066 | return false; 3067 | } 3068 | 3069 | a_element = a_element->next; 3070 | b_element = b_element->next; 3071 | } 3072 | 3073 | /* one of the arrays is longer than the other */ 3074 | if (a_element != b_element) { 3075 | return false; 3076 | } 3077 | 3078 | return true; 3079 | } 3080 | 3081 | case cJSON_Object: 3082 | { 3083 | cJSON *a_element = NULL; 3084 | cJSON *b_element = NULL; 3085 | cJSON_ArrayForEach(a_element, a) 3086 | { 3087 | /* TODO This has O(n^2) runtime, which is horrible! */ 3088 | b_element = get_object_item(b, a_element->string, case_sensitive); 3089 | if (b_element == NULL) 3090 | { 3091 | return false; 3092 | } 3093 | 3094 | if (!cJSON_Compare(a_element, b_element, case_sensitive)) 3095 | { 3096 | return false; 3097 | } 3098 | } 3099 | 3100 | /* doing this twice, once on a and b to prevent true comparison if a subset of b 3101 | * TODO: Do this the proper way, this is just a fix for now */ 3102 | cJSON_ArrayForEach(b_element, b) 3103 | { 3104 | a_element = get_object_item(a, b_element->string, case_sensitive); 3105 | if (a_element == NULL) 3106 | { 3107 | return false; 3108 | } 3109 | 3110 | if (!cJSON_Compare(b_element, a_element, case_sensitive)) 3111 | { 3112 | return false; 3113 | } 3114 | } 3115 | 3116 | return true; 3117 | } 3118 | 3119 | default: 3120 | return false; 3121 | } 3122 | } 3123 | 3124 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size) 3125 | { 3126 | return global_hooks.allocate(size); 3127 | } 3128 | 3129 | CJSON_PUBLIC(void) cJSON_free(void *object) 3130 | { 3131 | global_hooks.deallocate(object); 3132 | } -------------------------------------------------------------------------------- /src/cjson/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 14 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 adress 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 | /* Macro for iterating over an array or object */ 283 | #define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) 284 | 285 | /* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ 286 | CJSON_PUBLIC(void *) cJSON_malloc(size_t size); 287 | CJSON_PUBLIC(void) cJSON_free(void *object); 288 | 289 | #ifdef __cplusplus 290 | } 291 | #endif 292 | 293 | #endif --------------------------------------------------------------------------------