├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Makefile ├── Makefile.ps5 ├── Makefile.win ├── README.md ├── dl.c ├── dl.h ├── main.c ├── parson.c ├── parson.h ├── sha1.c ├── sha1.h ├── sha256.c └── sha256.h /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | paths-ignore: 6 | - "**/*.md" 7 | - '**/*.txt' 8 | pull_request: 9 | paths-ignore: 10 | - "**/*.md" 11 | - '**/*.txt' 12 | workflow_dispatch: 13 | 14 | concurrency: 15 | group: ${{ github.ref }}-${{ github.event_name }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | steps: 22 | 23 | - name: Checkout 24 | uses: actions/checkout@v3 25 | 26 | - name: Install dependencies 27 | run: | 28 | sudo apt update 29 | sudo apt install build-essential clang-18 lld-18 wget libcurl4-openssl-dev mingw-w64 mingw-w64-x86-64-dev 30 | 31 | - name: Download cURL for Windows 32 | run: wget https://curl.se/windows/dl-8.8.0_3/curl-8.8.0_3-win64-mingw.zip 33 | 34 | - name: Extract curl for Windows 35 | run: unzip curl-8.8.0_3-win64-mingw.zip 36 | 37 | - name: Install toolchain for PS5 38 | run: | 39 | wget https://github.com/ps5-payload-dev/pacbrew-repo/releases/latest/download/ps5-payload-dev.tar.gz 40 | sudo tar xf ps5-payload-dev.tar.gz -C / 41 | 42 | - name: Build Linux 43 | run: | 44 | make 45 | 46 | - name: Build Win64 47 | run: | 48 | export CURL_PATH=curl-8.8.0_3-win64-mingw 49 | make -f Makefile.win 50 | 51 | - name: Build PS5 52 | run: | 53 | export PS5_PAYLOAD_SDK=/opt/ps5-payload-sdk 54 | make -f Makefile.ps5 55 | 56 | - name: Prepare artifacts 57 | run: | 58 | mkdir fetchpkg-win64 59 | cp *.exe fetchpkg-win64/ 60 | cp curl-8.8.0_3-win64-mingw/bin/libcurl-x64.dll fetchpkg-win64/ 61 | 62 | - name: Upload Linux 63 | uses: actions/upload-artifact@v4 64 | with: 65 | name: Linux-x86_64 66 | path: ./fetchpkg 67 | if-no-files-found: error 68 | 69 | - name: Upload Windows 70 | uses: actions/upload-artifact@v4 71 | with: 72 | name: Win-x86_64 73 | path: fetchpkg-win64/ 74 | if-no-files-found: error 75 | 76 | - name: Upload PS5 77 | uses: actions/upload-artifact@v4 78 | with: 79 | name: PS5 80 | path: ./fetchpkg.elf 81 | if-no-files-found: error 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.elf 3 | *.exe 4 | fetchpkg 5 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 John Törnblom 2 | # 3 | # This file is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, but 9 | # WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | # General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; see the file COPYING. If not see 15 | # . 16 | 17 | CFLAGS := -O2 -Wall -Werror 18 | LDADD := -lcurl 19 | 20 | ELF := fetchpkg 21 | all: $(ELF) 22 | 23 | $(ELF): main.c dl.c parson.c sha256.c sha1.c 24 | $(CC) $(CFLAGS) -o $@ $^ $(LDADD) 25 | 26 | clean: 27 | rm -f $(ELF) 28 | -------------------------------------------------------------------------------- /Makefile.ps5: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 John Törnblom 2 | # 3 | # This file is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, but 9 | # WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | # General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; see the file COPYING. If not see 15 | # . 16 | 17 | PS5_HOST ?= ps5 18 | 19 | ifdef PS5_PAYLOAD_SDK 20 | include $(PS5_PAYLOAD_SDK)/toolchain/prospero.mk 21 | else 22 | $(error PS5_PAYLOAD_SDK is undefined) 23 | endif 24 | 25 | CFLAGS := -O1 -Wall -Werror -Wno-unreachable-code-generic-assoc 26 | CFLAGS += `$(PS5_PAYLOAD_SDK)/bin/prospero-curl-config --cflags` 27 | 28 | LDADD := `$(PS5_PAYLOAD_SDK)/bin/prospero-curl-config --libs` 29 | 30 | ELF := fetchpkg.elf 31 | 32 | all: $(ELF) 33 | 34 | $(ELF): main.c dl.c parson.c sha256.c sha1.c 35 | $(CC) $(CFLAGS) -o $@ $(LDADD) $^ 36 | 37 | clean: 38 | rm -f $(ELF) 39 | 40 | upload: $(ELF) 41 | curl -T $^ ftp://$(PS5_HOST):2121/data/$^ 42 | -------------------------------------------------------------------------------- /Makefile.win: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 John Törnblom 2 | # 3 | # This file is free software; you can redistribute it and/or modify it 4 | # under the terms of the GNU General Public License as published by 5 | # the Free Software Foundation; either version 3 of the License, or 6 | # (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, but 9 | # WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 | # General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; see the file COPYING. If not see 15 | # . 16 | 17 | CC := x86_64-w64-mingw32-gcc 18 | 19 | CURL_PATH ?= curl-8.8.0_3-win64-mingw 20 | 21 | CFLAGS := -O2 -Wall -D_FILE_OFFSET_BITS=64 22 | CFLAGS += -I$(CURL_PATH)/include -L$(CURL_PATH)/lib 23 | LDADD := -lcurl -lws2_32 -lwinmm 24 | 25 | EXE := fetchpkg.exe 26 | 27 | all: $(EXE) 28 | 29 | $(EXE): main.c dl.c parson.c sha256.c sha1.c 30 | $(CC) $(CFLAGS) -o $@ $^ $(LDADD) 31 | 32 | clean: 33 | rm -f $(EXE) 34 | 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fetchpkg 2 | This is a simple [cURL][curl]-based tool for downloading official Sony 3 | Playstation 4 & 5 game updates. It is available for GNU/Linux, Windows (64bit), 4 | and jailbroken PS5s. Game updates that are plit across multiple files are merged 5 | automatically during download. If you are behind a firewall, you can download 6 | updates via a proxy server, which is convenient when running on a jailbroken 7 | PS5 that are shielded of from the internet. 8 | 9 | 10 | ## Usage 11 | ```console 12 | john@localhost:ps5-payload-dev/fetchpkg$ ./fetchpkg [-p PROXY] [-o PATH] URL 13 | ``` 14 | where URL is the address to a JSON-formatted manifest, e.g., the PS4 title 15 | [Uncharted: The Lost Legacy (v1.09)][CUSA09564]. 16 | 17 | ## PS5 usage example 18 | To run fetchpkg on the PS5, you need to load it with an ELF loader that provides 19 | a command line interface, e.g., [shsrv][shsrv], and the means to transfer the ELF 20 | to the ps5, e.g., [ftpsrv][ftpsrv]. The following commands will upload the ELF file 21 | to /data, connect to shsrv, and download a pkg file to /mnt/usb0 via a proxy server: 22 | ```console 23 | john@localhost:ps5-payload-dev/fetchpkg$ curl -T fetchpkg.elf ftp://ps5:2121/data/fetchpkg.elf 24 | john@localhost:ps5-payload-dev/fetchpkg$ telnet ps5 2323 25 | Welcome to shsrv.elf running on... 26 | ... 27 | /$ /data/fetchpkg.elf -p http://proxy:8080 -o /mnt/usb0/temp.pkg URL 28 | ``` 29 | 30 | ## Building 31 | See the [gihub CI action workflow][workflow]. 32 | 33 | ## Reporting Bugs 34 | If you encounter problems with fetchpkg, please [file a github issue][issues]. 35 | If you plan on sending pull requests which affect more than a few lines of code, 36 | please file an issue before you start to work on you changes. This will allow us 37 | to discuss the solution properly before you commit time and effort. 38 | 39 | ## License 40 | fetchpkg is licensed under the GPLv3+, and uses [cURL][curl] togeather with 41 | [parson][parsonurl], both published under MIT-like licences. See thier 42 | websites for further details. 43 | 44 | [shsrv]: https://github.com/ps5-payload-dev/shsrv 45 | [ftpsrv]: https://github.com/ps5-payload-dev/ftpsrv 46 | [curl]: https://curl.se 47 | [parsonurl]: http://kgabis.github.io/parson 48 | [issues]: https://github.com/ps5-payload-dev/fetchpkg/issues/new 49 | [workflow]: https://github.com/ps5-payload-dev/fetchpkg/blob/master/.github/workflows/ci.yml 50 | [CUSA09564]: http://gs2.ww.prod.dl.playstation.net/gs2/ppkgo/prod/CUSA09564_00/9/f_f981fc66c3e96296bbb5aab1a93ef0615f7e91a15ef5b824689715494c33c0fb/f/EP9000-CUSA09564_00-UNCHD4LOSTLEGACY-A0109-V0100.json 51 | -------------------------------------------------------------------------------- /dl.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2024 John Törnblom 2 | 3 | This program is free software; you can redistribute it and/or modify it 4 | under the terms of the GNU General Public License as published by the 5 | Free Software Foundation; either version 3, or (at your option) any 6 | later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; see the file COPYING. If not, see 15 | . */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | #include "dl.h" 25 | #include "parson.h" 26 | #include "sha1.h" 27 | #include "sha256.h" 28 | 29 | 30 | static const char cacert[] = "-----BEGIN CERTIFICATE-----\n"\ 31 | "MIID0jCCArqgAwIBAgIBADANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJKUDEp\n"\ 32 | "MCcGA1UEChMgU29ueSBDb21wdXRlciBFbnRlcnRhaW5tZW50IEluYy4xGjAYBgNV\n"\ 33 | "BAMTEVNDRUkgRE5BUyBSb290IDA1MB4XDTA0MDcxMjA5MDExOVoXDTM3MTIwNjA5\n"\ 34 | "MDExOVowVDELMAkGA1UEBhMCSlAxKTAnBgNVBAoTIFNvbnkgQ29tcHV0ZXIgRW50\n"\ 35 | "ZXJ0YWlubWVudCBJbmMuMRowGAYDVQQDExFTQ0VJIEROQVMgUm9vdCAwNTCCASIw\n"\ 36 | "DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANmPeza8PwCqlI7esOGIkoSESnIN\n"\ 37 | "g72ZD3Ut63jy7SdothPIvGBqVZWYkIpqJYJd1I4Nh//IpXQCQL0PnJLrh9BBeowq\n"\ 38 | "Muf5NNq3Us80Ihiu9CvNEAEO18g3OFV1TYdSwQ5zUsk33OUeI7h4aBPDVcZXYeHt\n"\ 39 | "dbPLqe4K8igian5prrAD5S6h28t8aAm+qMWRo+bW25B/841XwDGBP7/IxZv8Yoio\n"\ 40 | "rCo80CVYe6lGoU08eeqQiaHI5zAF281DWZSoVfLjJUEWmEnxqr8aOhszRGePi+Ei\n"\ 41 | "7UQjHDuZX9rLhDI1zAND+BA259tn/iwOqVXe20OccJllHJcG4Ecmd98f5qMCAwEA\n"\ 42 | "AaOBrjCBqzAdBgNVHQ4EFgQUxlahM1tPzoN3YgVEhm0gV7Wv2twwfAYDVR0jBHUw\n"\ 43 | "c4AUxlahM1tPzoN3YgVEhm0gV7Wv2tyhWKRWMFQxCzAJBgNVBAYTAkpQMSkwJwYD\n"\ 44 | "VQQKEyBTb255IENvbXB1dGVyIEVudGVydGFpbm1lbnQgSW5jLjEaMBgGA1UEAxMR\n"\ 45 | "U0NFSSBETkFTIFJvb3QgMDWCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUF\n"\ 46 | "AAOCAQEACZPihjwXA27wJ03tEKcHAeFLi8aBw2ysH4GwuH1dWb3UpuznWOB0iQT1\n"\ 47 | "wQocnEFYCJx5XFEnj4aLWpSHLEq/sSO+my+aPoTEsy20ajF+YLYZm0bZxH50CJYh\n"\ 48 | "rkET4C2aC0XvhGp9k1JQ1o0W6+cFT5LTlXapsq8Btt31t+XDPX7RqGV4WGekt3hM\n"\ 49 | "T7xRc7JWXdAQijIrbYi8mtbM07KEGnPU6IT8C47+0mSurpwLOoWL1tPgo6ePpLNi\n"\ 50 | "c4quUMgh9RXVjeTyXOMmyYdeUm2gt7qErvQONli+6Epmhm0A2khpIMHSpQjTE8gV\n"\ 51 | "rZp42a6+zg1iYy2vFBOmiQ17GRUl0A==\n"\ 52 | "-----END CERTIFICATE-----\n\0"; 53 | 54 | 55 | /** 56 | * 57 | **/ 58 | typedef size_t (dl_data_write_t)(void *ptr, size_t length, size_t nmemb, void *ctx); 59 | 60 | 61 | /** 62 | * 63 | **/ 64 | typedef struct dl_manifest_state { 65 | char *data; 66 | size_t size; 67 | int error; 68 | } dl_manifest_state_t; 69 | 70 | 71 | /** 72 | * 73 | **/ 74 | typedef struct dl_package_state { 75 | FILE *file; 76 | int error; 77 | size_t remaining; 78 | 79 | SHA256_CTX* sha256; 80 | SHA1_CTX* sha1; 81 | 82 | struct { 83 | dl_progress_t *cb; 84 | void* ctx; 85 | } on_progress; 86 | } dl_package_state_t; 87 | 88 | 89 | /** 90 | * 91 | **/ 92 | static size_t 93 | dl_manifest_write(void *ptr, size_t length, size_t nmemb, void *ctx) { 94 | dl_manifest_state_t *state = (dl_manifest_state_t*)ctx; 95 | size_t size = length * nmemb; 96 | 97 | if(!(state->data=realloc(state->data, state->size + size + 1))) { 98 | state->error = errno; 99 | return 0; 100 | } 101 | 102 | memcpy(state->data + state->size, ptr, size); 103 | state->size += size; 104 | state->data[state->size] = 0; 105 | 106 | return size; 107 | } 108 | 109 | 110 | /** 111 | * 112 | **/ 113 | static size_t 114 | dl_package_write(void *ptr, size_t length, size_t nmemb, void *ctx) { 115 | dl_package_state_t *state = (dl_package_state_t*)ctx; 116 | int n; 117 | 118 | if(!(n=fwrite(ptr, length, nmemb, state->file))) { 119 | state->error = ferror(state->file); 120 | } 121 | 122 | if(state->sha1) { 123 | sha1_update(state->sha1, ptr, n); 124 | } 125 | if(state->sha256) { 126 | sha256_update(state->sha256, ptr, n); 127 | } 128 | 129 | if(n <= state->remaining) { 130 | state->remaining -= n; 131 | } else { 132 | state->remaining = 0; 133 | } 134 | 135 | if(state->on_progress.cb && 136 | state->on_progress.cb(state->on_progress.ctx, 137 | ftello(state->file), 138 | state->remaining)) { 139 | return 0; 140 | } 141 | 142 | return n; 143 | } 144 | 145 | 146 | /** 147 | * 148 | **/ 149 | static int 150 | dl_fetch(const char* url, dl_data_write_t* cb, void* ctx) { 151 | char buf[CURL_ERROR_SIZE]; 152 | struct curl_blob ca = {0}; 153 | const char* proxy; 154 | int error = 0; 155 | CURL *curl; 156 | 157 | curl_global_init(CURL_GLOBAL_DEFAULT); 158 | if(!(curl=curl_easy_init())) { 159 | fprintf(stderr, "dl_fetch: curl_easy_init() failed\n"); 160 | return -1; 161 | } 162 | 163 | ca.data = (void*)cacert; 164 | ca.len = strlen(cacert); 165 | ca.flags = CURL_BLOB_COPY; 166 | 167 | curl_easy_setopt(curl, CURLOPT_URL, url); 168 | curl_easy_setopt(curl, CURLOPT_CAINFO_BLOB, &ca); 169 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb); 170 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, ctx); 171 | curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/5.0"); 172 | curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); 173 | curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); 174 | curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, buf); 175 | 176 | if((proxy=getenv("CURL_PROXY"))) { 177 | curl_easy_setopt(curl, CURLOPT_PROXY, proxy); 178 | } 179 | 180 | if((error=curl_easy_perform(curl))) { 181 | fprintf(stderr, "curl_easy_perform: %s\n", buf); 182 | error = -1; 183 | } 184 | 185 | curl_easy_cleanup(curl); 186 | curl_global_cleanup(); 187 | 188 | return error; 189 | } 190 | 191 | 192 | /** 193 | * 194 | **/ 195 | static JSON_Value* 196 | dl_manifest(const char *url) { 197 | dl_manifest_state_t state = {0}; 198 | JSON_Value *json = 0; 199 | 200 | if(!dl_fetch(url, dl_manifest_write, &state)) { 201 | if(state.error) { 202 | fprintf(stderr, "dl_manifest: %s\n", strerror(state.error)); 203 | } else if(!(json=json_parse_string(state.data))) { 204 | fprintf(stderr, "dl_manifest: json_tokener_parse() failed\n"); 205 | } 206 | } 207 | 208 | if(state.data) { 209 | free(state.data); 210 | } 211 | 212 | return json; 213 | } 214 | 215 | 216 | /** 217 | * 218 | **/ 219 | static int 220 | dl_package_piece(dl_package_state_t* state, const char *url, uint8_t* hash, 221 | size_t hash_size) { 222 | SHA256_CTX sha256; 223 | SHA1_CTX sha1; 224 | 225 | state->sha1 = 0; 226 | state->sha256 = 0; 227 | 228 | if(hash_size == SHA256_BLOCK_SIZE) { 229 | sha256_init(&sha256); 230 | state->sha256 = &sha256; 231 | } else if(hash_size == SHA1_BLOCK_SIZE) { 232 | sha1_init(&sha1); 233 | state->sha1 = &sha1; 234 | } 235 | 236 | if(dl_fetch(url, dl_package_write, state)) { 237 | return -1; 238 | } 239 | 240 | if(state->error) { 241 | fprintf(stderr, "dl_package_piece: %s\n", strerror(state->error)); 242 | return state->error; 243 | } 244 | 245 | if(hash_size == SHA256_BLOCK_SIZE) { 246 | sha256_final(&sha256, hash); 247 | } else if(hash_size == SHA1_BLOCK_SIZE) { 248 | sha1_final(&sha1, hash); 249 | } 250 | 251 | return 0; 252 | } 253 | 254 | static void 255 | hexdump(const void *bin, size_t size) { 256 | const char* str = (const char*)bin; 257 | 258 | printf("0x"); 259 | for(int i=0; i. */ 16 | 17 | #pragma once 18 | 19 | #include 20 | 21 | 22 | /** 23 | * 24 | **/ 25 | typedef int (dl_progress_t)(void *ctx, size_t written, size_t remaining); 26 | 27 | 28 | /** 29 | * 30 | **/ 31 | int dl_package(const char* manifest_url, const char* path, 32 | dl_progress_t* cb, void* ctx); 33 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) 2024 John Törnblom 2 | 3 | This program is free software; you can redistribute it and/or modify it 4 | under the terms of the GNU General Public License as published by the 5 | Free Software Foundation; either version 3, or (at your option) any 6 | later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program; see the file COPYING. If not, see 15 | . */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "dl.h" 25 | 26 | 27 | #define MiB(x) (x / (1024*1024)) 28 | 29 | 30 | /** 31 | * 32 | **/ 33 | static const char* 34 | basename(const char *path) { 35 | const char* ptr = path; 36 | 37 | while(path && *path) { 38 | if(*path == '/') { 39 | ptr = path+1; 40 | } 41 | path++; 42 | } 43 | 44 | return ptr; 45 | } 46 | 47 | 48 | /** 49 | * 50 | **/ 51 | static int 52 | endswith(const char *str, const char* suffix) { 53 | size_t str_len = strlen(str); 54 | size_t suffix_len = strlen(suffix); 55 | 56 | if(str_len < suffix_len) { 57 | return 0; 58 | } 59 | 60 | return strcmp(str+str_len-suffix_len, suffix) == 0; 61 | } 62 | 63 | 64 | /** 65 | * 66 | **/ 67 | static int 68 | on_progress(void* ctx, size_t written, size_t remaining) { 69 | const char* filename = (const char*)ctx; 70 | static time_t start_time = 0; 71 | static time_t prev_time = 0; 72 | time_t now = time(0); 73 | 74 | if(start_time == 0) { 75 | start_time = prev_time = now; 76 | } 77 | 78 | if(prev_time < now) { 79 | double progress = 100.0 * written / (written + remaining); 80 | double speed = MiB((double)written / (now - start_time)); 81 | 82 | fprintf(stdout, "filename: %s | progress: %6.2f%% | avg speed: %6.2f MiB/s\r", 83 | filename, progress, speed); 84 | fflush(stdout); 85 | 86 | prev_time = now; 87 | } 88 | 89 | return 0; 90 | } 91 | 92 | 93 | int main(int argc, char *argv[]) { 94 | char output[PATH_MAX] = {0}; 95 | char url[PATH_MAX] = {0}; 96 | char buf[PATH_MAX]; 97 | int opt; 98 | 99 | while((opt=getopt(argc, argv, "p:o:")) != -1) { 100 | switch (opt) { 101 | case 'p': 102 | sprintf(buf, "CURL_PROXY=%s", optarg); 103 | putenv(buf); 104 | break; 105 | 106 | case 'o': 107 | strncpy(output, optarg, sizeof(output)-1); 108 | break; 109 | 110 | default: 111 | fprintf(stderr, "Usage: %s [-p PROXY] [-o PATH] URL\n", argv[0]); 112 | exit(EXIT_FAILURE); 113 | } 114 | } 115 | 116 | if(optind >= argc) { 117 | fprintf(stderr, "Usage: %s [-p PROXY] [-o PATH] URL\n", argv[0]); 118 | exit(EXIT_FAILURE); 119 | } 120 | 121 | printf("Starting download...\n"); 122 | 123 | strncpy(url, argv[optind], sizeof(url)-1); 124 | if(endswith(url, "_sc.pkg") || endswith(url, "-DP.pkg")) { 125 | url[strlen(url)-7] = 0; 126 | strcat(url, ".json"); 127 | 128 | } else if(endswith(url, "_0.pkg")) { 129 | url[strlen(url)-6] = 0; 130 | strcat(url, ".json"); 131 | } 132 | 133 | if(!output[0]) { 134 | strcpy(output, basename(url)); 135 | if(endswith(output, ".json")) { 136 | output[strlen(output)-5] = 0; 137 | strcat(output, ".pkg"); 138 | } 139 | } 140 | 141 | if(dl_package(url, output, on_progress, (void*)basename(output))) { 142 | return -1; 143 | } 144 | 145 | puts("\nDone"); 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /parson.c: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-License-Identifier: MIT 3 | 4 | Parson 1.5.3 (https://github.com/kgabis/parson) 5 | Copyright (c) 2012 - 2023 Krzysztof Gabis 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | */ 25 | #ifdef _MSC_VER 26 | #ifndef _CRT_SECURE_NO_WARNINGS 27 | #define _CRT_SECURE_NO_WARNINGS 28 | #endif /* _CRT_SECURE_NO_WARNINGS */ 29 | #endif /* _MSC_VER */ 30 | 31 | #include "parson.h" 32 | 33 | #define PARSON_IMPL_VERSION_MAJOR 1 34 | #define PARSON_IMPL_VERSION_MINOR 5 35 | #define PARSON_IMPL_VERSION_PATCH 3 36 | 37 | #if (PARSON_VERSION_MAJOR != PARSON_IMPL_VERSION_MAJOR)\ 38 | || (PARSON_VERSION_MINOR != PARSON_IMPL_VERSION_MINOR)\ 39 | || (PARSON_VERSION_PATCH != PARSON_IMPL_VERSION_PATCH) 40 | #error "parson version mismatch between parson.c and parson.h" 41 | #endif 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | /* Apparently sscanf is not implemented in some "standard" libraries, so don't use it, if you 52 | * don't have to. */ 53 | #ifdef sscanf 54 | #undef sscanf 55 | #define sscanf THINK_TWICE_ABOUT_USING_SSCANF 56 | #endif 57 | 58 | /* strcpy is unsafe */ 59 | #ifdef strcpy 60 | #undef strcpy 61 | #endif 62 | #define strcpy USE_MEMCPY_INSTEAD_OF_STRCPY 63 | 64 | #define STARTING_CAPACITY 16 65 | #define MAX_NESTING 2048 66 | 67 | #ifndef PARSON_DEFAULT_FLOAT_FORMAT 68 | #define PARSON_DEFAULT_FLOAT_FORMAT "%1.17g" /* do not increase precision without incresing NUM_BUF_SIZE */ 69 | #endif 70 | 71 | #ifndef PARSON_NUM_BUF_SIZE 72 | #define PARSON_NUM_BUF_SIZE 64 /* double printed with "%1.17g" shouldn't be longer than 25 bytes so let's be paranoid and use 64 */ 73 | #endif 74 | 75 | #ifndef PARSON_INDENT_STR 76 | #define PARSON_INDENT_STR " " 77 | #endif 78 | 79 | #define SIZEOF_TOKEN(a) (sizeof(a) - 1) 80 | #define SKIP_CHAR(str) ((*str)++) 81 | #define SKIP_WHITESPACES(str) while (isspace((unsigned char)(**str))) { SKIP_CHAR(str); } 82 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) 83 | 84 | #undef malloc 85 | #undef free 86 | 87 | #if defined(isnan) && defined(isinf) 88 | #define IS_NUMBER_INVALID(x) (isnan((x)) || isinf((x))) 89 | #else 90 | #define IS_NUMBER_INVALID(x) (((x) * 0.0) != 0.0) 91 | #endif 92 | 93 | #define OBJECT_INVALID_IX ((size_t)-1) 94 | 95 | static JSON_Malloc_Function parson_malloc = malloc; 96 | static JSON_Free_Function parson_free = free; 97 | 98 | static int parson_escape_slashes = 1; 99 | 100 | static char *parson_float_format = NULL; 101 | 102 | static JSON_Number_Serialization_Function parson_number_serialization_function = NULL; 103 | 104 | #define IS_CONT(b) (((unsigned char)(b) & 0xC0) == 0x80) /* is utf-8 continuation byte */ 105 | 106 | typedef int parson_bool_t; 107 | 108 | #define PARSON_TRUE 1 109 | #define PARSON_FALSE 0 110 | 111 | typedef struct json_string { 112 | char *chars; 113 | size_t length; 114 | } JSON_String; 115 | 116 | /* Type definitions */ 117 | typedef union json_value_value { 118 | JSON_String string; 119 | double number; 120 | JSON_Object *object; 121 | JSON_Array *array; 122 | int boolean; 123 | int null; 124 | } JSON_Value_Value; 125 | 126 | struct json_value_t { 127 | JSON_Value *parent; 128 | JSON_Value_Type type; 129 | JSON_Value_Value value; 130 | }; 131 | 132 | struct json_object_t { 133 | JSON_Value *wrapping_value; 134 | size_t *cells; 135 | unsigned long *hashes; 136 | char **names; 137 | JSON_Value **values; 138 | size_t *cell_ixs; 139 | size_t count; 140 | size_t item_capacity; 141 | size_t cell_capacity; 142 | }; 143 | 144 | struct json_array_t { 145 | JSON_Value *wrapping_value; 146 | JSON_Value **items; 147 | size_t count; 148 | size_t capacity; 149 | }; 150 | 151 | /* Various */ 152 | static char * read_file(const char *filename); 153 | static void remove_comments(char *string, const char *start_token, const char *end_token); 154 | static char * parson_strndup(const char *string, size_t n); 155 | static char * parson_strdup(const char *string); 156 | static int parson_sprintf(char * s, const char * format, ...); 157 | 158 | static int hex_char_to_int(char c); 159 | static JSON_Status parse_utf16_hex(const char *string, unsigned int *result); 160 | static int num_bytes_in_utf8_sequence(unsigned char c); 161 | static JSON_Status verify_utf8_sequence(const unsigned char *string, int *len); 162 | static parson_bool_t is_valid_utf8(const char *string, size_t string_len); 163 | static parson_bool_t is_decimal(const char *string, size_t length); 164 | static unsigned long hash_string(const char *string, size_t n); 165 | 166 | /* JSON Object */ 167 | static JSON_Object * json_object_make(JSON_Value *wrapping_value); 168 | static JSON_Status json_object_init(JSON_Object *object, size_t capacity); 169 | static void json_object_deinit(JSON_Object *object, parson_bool_t free_keys, parson_bool_t free_values); 170 | static JSON_Status json_object_grow_and_rehash(JSON_Object *object); 171 | static size_t json_object_get_cell_ix(const JSON_Object *object, const char *key, size_t key_len, unsigned long hash, parson_bool_t *out_found); 172 | static JSON_Status json_object_add(JSON_Object *object, char *name, JSON_Value *value); 173 | static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len); 174 | static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, parson_bool_t free_value); 175 | static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, parson_bool_t free_value); 176 | static void json_object_free(JSON_Object *object); 177 | 178 | /* JSON Array */ 179 | static JSON_Array * json_array_make(JSON_Value *wrapping_value); 180 | static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value); 181 | static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity); 182 | static void json_array_free(JSON_Array *array); 183 | 184 | /* JSON Value */ 185 | static JSON_Value * json_value_init_string_no_copy(char *string, size_t length); 186 | static const JSON_String * json_value_get_string_desc(const JSON_Value *value); 187 | 188 | /* Parser */ 189 | static JSON_Status skip_quotes(const char **string); 190 | static JSON_Status parse_utf16(const char **unprocessed, char **processed); 191 | static char * process_string(const char *input, size_t input_len, size_t *output_len); 192 | static char * get_quoted_string(const char **string, size_t *output_string_len); 193 | static JSON_Value * parse_object_value(const char **string, size_t nesting); 194 | static JSON_Value * parse_array_value(const char **string, size_t nesting); 195 | static JSON_Value * parse_string_value(const char **string); 196 | static JSON_Value * parse_boolean_value(const char **string); 197 | static JSON_Value * parse_number_value(const char **string); 198 | static JSON_Value * parse_null_value(const char **string); 199 | static JSON_Value * parse_value(const char **string, size_t nesting); 200 | 201 | /* Serialization */ 202 | static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf); 203 | static int json_serialize_string(const char *string, size_t len, char *buf); 204 | 205 | /* Various */ 206 | static char * read_file(const char * filename) { 207 | FILE *fp = fopen(filename, "r"); 208 | size_t size_to_read = 0; 209 | size_t size_read = 0; 210 | long pos; 211 | char *file_contents; 212 | if (!fp) { 213 | return NULL; 214 | } 215 | fseek(fp, 0L, SEEK_END); 216 | pos = ftell(fp); 217 | if (pos < 0) { 218 | fclose(fp); 219 | return NULL; 220 | } 221 | size_to_read = pos; 222 | rewind(fp); 223 | file_contents = (char*)parson_malloc(sizeof(char) * (size_to_read + 1)); 224 | if (!file_contents) { 225 | fclose(fp); 226 | return NULL; 227 | } 228 | size_read = fread(file_contents, 1, size_to_read, fp); 229 | if (size_read == 0 || ferror(fp)) { 230 | fclose(fp); 231 | parson_free(file_contents); 232 | return NULL; 233 | } 234 | fclose(fp); 235 | file_contents[size_read] = '\0'; 236 | return file_contents; 237 | } 238 | 239 | static void remove_comments(char *string, const char *start_token, const char *end_token) { 240 | parson_bool_t in_string = PARSON_FALSE, escaped = PARSON_FALSE; 241 | size_t i; 242 | char *ptr = NULL, current_char; 243 | size_t start_token_len = strlen(start_token); 244 | size_t end_token_len = strlen(end_token); 245 | if (start_token_len == 0 || end_token_len == 0) { 246 | return; 247 | } 248 | while ((current_char = *string) != '\0') { 249 | if (current_char == '\\' && !escaped) { 250 | escaped = PARSON_TRUE; 251 | string++; 252 | continue; 253 | } else if (current_char == '\"' && !escaped) { 254 | in_string = !in_string; 255 | } else if (!in_string && strncmp(string, start_token, start_token_len) == 0) { 256 | for(i = 0; i < start_token_len; i++) { 257 | string[i] = ' '; 258 | } 259 | string = string + start_token_len; 260 | ptr = strstr(string, end_token); 261 | if (!ptr) { 262 | return; 263 | } 264 | for (i = 0; i < (ptr - string) + end_token_len; i++) { 265 | string[i] = ' '; 266 | } 267 | string = ptr + end_token_len - 1; 268 | } 269 | escaped = PARSON_FALSE; 270 | string++; 271 | } 272 | } 273 | 274 | static char * parson_strndup(const char *string, size_t n) { 275 | /* We expect the caller has validated that 'n' fits within the input buffer. */ 276 | char *output_string = (char*)parson_malloc(n + 1); 277 | if (!output_string) { 278 | return NULL; 279 | } 280 | output_string[n] = '\0'; 281 | memcpy(output_string, string, n); 282 | return output_string; 283 | } 284 | 285 | static char * parson_strdup(const char *string) { 286 | return parson_strndup(string, strlen(string)); 287 | } 288 | 289 | static int parson_sprintf(char * s, const char * format, ...) { 290 | int result; 291 | va_list args; 292 | va_start(args, format); 293 | 294 | #if defined(__APPLE__) && defined(__clang__) 295 | #pragma clang diagnostic push 296 | #pragma clang diagnostic ignored "-Wdeprecated-declarations" 297 | #endif 298 | result = vsprintf(s, format, args); 299 | #if defined(__APPLE__) && defined(__clang__) 300 | #pragma clang diagnostic pop 301 | #endif 302 | 303 | va_end(args); 304 | return result; 305 | 306 | } 307 | 308 | static int hex_char_to_int(char c) { 309 | if (c >= '0' && c <= '9') { 310 | return c - '0'; 311 | } else if (c >= 'a' && c <= 'f') { 312 | return c - 'a' + 10; 313 | } else if (c >= 'A' && c <= 'F') { 314 | return c - 'A' + 10; 315 | } 316 | return -1; 317 | } 318 | 319 | static JSON_Status parse_utf16_hex(const char *s, unsigned int *result) { 320 | int x1, x2, x3, x4; 321 | if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0' || s[3] == '\0') { 322 | return JSONFailure; 323 | } 324 | x1 = hex_char_to_int(s[0]); 325 | x2 = hex_char_to_int(s[1]); 326 | x3 = hex_char_to_int(s[2]); 327 | x4 = hex_char_to_int(s[3]); 328 | if (x1 == -1 || x2 == -1 || x3 == -1 || x4 == -1) { 329 | return JSONFailure; 330 | } 331 | *result = (unsigned int)((x1 << 12) | (x2 << 8) | (x3 << 4) | x4); 332 | return JSONSuccess; 333 | } 334 | 335 | static int num_bytes_in_utf8_sequence(unsigned char c) { 336 | if (c == 0xC0 || c == 0xC1 || c > 0xF4 || IS_CONT(c)) { 337 | return 0; 338 | } else if ((c & 0x80) == 0) { /* 0xxxxxxx */ 339 | return 1; 340 | } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx */ 341 | return 2; 342 | } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx */ 343 | return 3; 344 | } else if ((c & 0xF8) == 0xF0) { /* 11110xxx */ 345 | return 4; 346 | } 347 | return 0; /* won't happen */ 348 | } 349 | 350 | static JSON_Status verify_utf8_sequence(const unsigned char *string, int *len) { 351 | unsigned int cp = 0; 352 | *len = num_bytes_in_utf8_sequence(string[0]); 353 | 354 | if (*len == 1) { 355 | cp = string[0]; 356 | } else if (*len == 2 && IS_CONT(string[1])) { 357 | cp = string[0] & 0x1F; 358 | cp = (cp << 6) | (string[1] & 0x3F); 359 | } else if (*len == 3 && IS_CONT(string[1]) && IS_CONT(string[2])) { 360 | cp = ((unsigned char)string[0]) & 0xF; 361 | cp = (cp << 6) | (string[1] & 0x3F); 362 | cp = (cp << 6) | (string[2] & 0x3F); 363 | } else if (*len == 4 && IS_CONT(string[1]) && IS_CONT(string[2]) && IS_CONT(string[3])) { 364 | cp = string[0] & 0x7; 365 | cp = (cp << 6) | (string[1] & 0x3F); 366 | cp = (cp << 6) | (string[2] & 0x3F); 367 | cp = (cp << 6) | (string[3] & 0x3F); 368 | } else { 369 | return JSONFailure; 370 | } 371 | 372 | /* overlong encodings */ 373 | if ((cp < 0x80 && *len > 1) || 374 | (cp < 0x800 && *len > 2) || 375 | (cp < 0x10000 && *len > 3)) { 376 | return JSONFailure; 377 | } 378 | 379 | /* invalid unicode */ 380 | if (cp > 0x10FFFF) { 381 | return JSONFailure; 382 | } 383 | 384 | /* surrogate halves */ 385 | if (cp >= 0xD800 && cp <= 0xDFFF) { 386 | return JSONFailure; 387 | } 388 | 389 | return JSONSuccess; 390 | } 391 | 392 | static int is_valid_utf8(const char *string, size_t string_len) { 393 | int len = 0; 394 | const char *string_end = string + string_len; 395 | while (string < string_end) { 396 | if (verify_utf8_sequence((const unsigned char*)string, &len) != JSONSuccess) { 397 | return PARSON_FALSE; 398 | } 399 | string += len; 400 | } 401 | return PARSON_TRUE; 402 | } 403 | 404 | static parson_bool_t is_decimal(const char *string, size_t length) { 405 | if (length > 1 && string[0] == '0' && string[1] != '.') { 406 | return PARSON_FALSE; 407 | } 408 | if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { 409 | return PARSON_FALSE; 410 | } 411 | while (length--) { 412 | if (strchr("xX", string[length])) { 413 | return PARSON_FALSE; 414 | } 415 | } 416 | return PARSON_TRUE; 417 | } 418 | 419 | static unsigned long hash_string(const char *string, size_t n) { 420 | #ifdef PARSON_FORCE_HASH_COLLISIONS 421 | (void)string; 422 | (void)n; 423 | return 0; 424 | #else 425 | unsigned long hash = 5381; 426 | unsigned char c; 427 | size_t i = 0; 428 | for (i = 0; i < n; i++) { 429 | c = string[i]; 430 | if (c == '\0') { 431 | break; 432 | } 433 | hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ 434 | } 435 | return hash; 436 | #endif 437 | } 438 | 439 | /* JSON Object */ 440 | static JSON_Object * json_object_make(JSON_Value *wrapping_value) { 441 | JSON_Status res = JSONFailure; 442 | JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); 443 | if (new_obj == NULL) { 444 | return NULL; 445 | } 446 | new_obj->wrapping_value = wrapping_value; 447 | res = json_object_init(new_obj, 0); 448 | if (res != JSONSuccess) { 449 | parson_free(new_obj); 450 | return NULL; 451 | } 452 | return new_obj; 453 | } 454 | 455 | static JSON_Status json_object_init(JSON_Object *object, size_t capacity) { 456 | unsigned int i = 0; 457 | 458 | object->cells = NULL; 459 | object->names = NULL; 460 | object->values = NULL; 461 | object->cell_ixs = NULL; 462 | object->hashes = NULL; 463 | 464 | object->count = 0; 465 | object->cell_capacity = capacity; 466 | object->item_capacity = (unsigned int)(capacity * 7/10); 467 | 468 | if (capacity == 0) { 469 | return JSONSuccess; 470 | } 471 | 472 | object->cells = (size_t*)parson_malloc(object->cell_capacity * sizeof(*object->cells)); 473 | object->names = (char**)parson_malloc(object->item_capacity * sizeof(*object->names)); 474 | object->values = (JSON_Value**)parson_malloc(object->item_capacity * sizeof(*object->values)); 475 | object->cell_ixs = (size_t*)parson_malloc(object->item_capacity * sizeof(*object->cell_ixs)); 476 | object->hashes = (unsigned long*)parson_malloc(object->item_capacity * sizeof(*object->hashes)); 477 | if (object->cells == NULL 478 | || object->names == NULL 479 | || object->values == NULL 480 | || object->cell_ixs == NULL 481 | || object->hashes == NULL) { 482 | goto error; 483 | } 484 | for (i = 0; i < object->cell_capacity; i++) { 485 | object->cells[i] = OBJECT_INVALID_IX; 486 | } 487 | return JSONSuccess; 488 | error: 489 | parson_free(object->cells); 490 | parson_free(object->names); 491 | parson_free(object->values); 492 | parson_free(object->cell_ixs); 493 | parson_free(object->hashes); 494 | return JSONFailure; 495 | } 496 | 497 | static void json_object_deinit(JSON_Object *object, parson_bool_t free_keys, parson_bool_t free_values) { 498 | unsigned int i = 0; 499 | for (i = 0; i < object->count; i++) { 500 | if (free_keys) { 501 | parson_free(object->names[i]); 502 | } 503 | if (free_values) { 504 | json_value_free(object->values[i]); 505 | } 506 | } 507 | 508 | object->count = 0; 509 | object->item_capacity = 0; 510 | object->cell_capacity = 0; 511 | 512 | parson_free(object->cells); 513 | parson_free(object->names); 514 | parson_free(object->values); 515 | parson_free(object->cell_ixs); 516 | parson_free(object->hashes); 517 | 518 | object->cells = NULL; 519 | object->names = NULL; 520 | object->values = NULL; 521 | object->cell_ixs = NULL; 522 | object->hashes = NULL; 523 | } 524 | 525 | static JSON_Status json_object_grow_and_rehash(JSON_Object *object) { 526 | JSON_Value *wrapping_value = NULL; 527 | JSON_Object new_object; 528 | char *key = NULL; 529 | JSON_Value *value = NULL; 530 | unsigned int i = 0; 531 | size_t new_capacity = MAX(object->cell_capacity * 2, STARTING_CAPACITY); 532 | JSON_Status res = json_object_init(&new_object, new_capacity); 533 | if (res != JSONSuccess) { 534 | return JSONFailure; 535 | } 536 | 537 | wrapping_value = json_object_get_wrapping_value(object); 538 | new_object.wrapping_value = wrapping_value; 539 | 540 | for (i = 0; i < object->count; i++) { 541 | key = object->names[i]; 542 | value = object->values[i]; 543 | res = json_object_add(&new_object, key, value); 544 | if (res != JSONSuccess) { 545 | json_object_deinit(&new_object, PARSON_FALSE, PARSON_FALSE); 546 | return JSONFailure; 547 | } 548 | value->parent = wrapping_value; 549 | } 550 | json_object_deinit(object, PARSON_FALSE, PARSON_FALSE); 551 | *object = new_object; 552 | return JSONSuccess; 553 | } 554 | 555 | static size_t json_object_get_cell_ix(const JSON_Object *object, const char *key, size_t key_len, unsigned long hash, parson_bool_t *out_found) { 556 | size_t cell_ix = hash & (object->cell_capacity - 1); 557 | size_t cell = 0; 558 | size_t ix = 0; 559 | unsigned int i = 0; 560 | unsigned long hash_to_check = 0; 561 | const char *key_to_check = NULL; 562 | size_t key_to_check_len = 0; 563 | 564 | *out_found = PARSON_FALSE; 565 | 566 | for (i = 0; i < object->cell_capacity; i++) { 567 | ix = (cell_ix + i) & (object->cell_capacity - 1); 568 | cell = object->cells[ix]; 569 | if (cell == OBJECT_INVALID_IX) { 570 | return ix; 571 | } 572 | hash_to_check = object->hashes[cell]; 573 | if (hash != hash_to_check) { 574 | continue; 575 | } 576 | key_to_check = object->names[cell]; 577 | key_to_check_len = strlen(key_to_check); 578 | if (key_to_check_len == key_len && strncmp(key, key_to_check, key_len) == 0) { 579 | *out_found = PARSON_TRUE; 580 | return ix; 581 | } 582 | } 583 | return OBJECT_INVALID_IX; 584 | } 585 | 586 | static JSON_Status json_object_add(JSON_Object *object, char *name, JSON_Value *value) { 587 | unsigned long hash = 0; 588 | parson_bool_t found = PARSON_FALSE; 589 | size_t cell_ix = 0; 590 | JSON_Status res = JSONFailure; 591 | 592 | if (!object || !name || !value) { 593 | return JSONFailure; 594 | } 595 | 596 | hash = hash_string(name, strlen(name)); 597 | found = PARSON_FALSE; 598 | cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); 599 | if (found) { 600 | return JSONFailure; 601 | } 602 | 603 | if (object->count >= object->item_capacity) { 604 | res = json_object_grow_and_rehash(object); 605 | if (res != JSONSuccess) { 606 | return JSONFailure; 607 | } 608 | cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); 609 | } 610 | 611 | object->names[object->count] = name; 612 | object->cells[cell_ix] = object->count; 613 | object->values[object->count] = value; 614 | object->cell_ixs[object->count] = cell_ix; 615 | object->hashes[object->count] = hash; 616 | object->count++; 617 | value->parent = json_object_get_wrapping_value(object); 618 | 619 | return JSONSuccess; 620 | } 621 | 622 | static JSON_Value * json_object_getn_value(const JSON_Object *object, const char *name, size_t name_len) { 623 | unsigned long hash = 0; 624 | parson_bool_t found = PARSON_FALSE; 625 | size_t cell_ix = 0; 626 | size_t item_ix = 0; 627 | if (!object || !name) { 628 | return NULL; 629 | } 630 | hash = hash_string(name, name_len); 631 | found = PARSON_FALSE; 632 | cell_ix = json_object_get_cell_ix(object, name, name_len, hash, &found); 633 | if (!found) { 634 | return NULL; 635 | } 636 | item_ix = object->cells[cell_ix]; 637 | return object->values[item_ix]; 638 | } 639 | 640 | static JSON_Status json_object_remove_internal(JSON_Object *object, const char *name, parson_bool_t free_value) { 641 | unsigned long hash = 0; 642 | parson_bool_t found = PARSON_FALSE; 643 | size_t cell = 0; 644 | size_t item_ix = 0; 645 | size_t last_item_ix = 0; 646 | size_t i = 0; 647 | size_t j = 0; 648 | size_t x = 0; 649 | size_t k = 0; 650 | JSON_Value *val = NULL; 651 | 652 | if (object == NULL) { 653 | return JSONFailure; 654 | } 655 | 656 | hash = hash_string(name, strlen(name)); 657 | found = PARSON_FALSE; 658 | cell = json_object_get_cell_ix(object, name, strlen(name), hash, &found); 659 | if (!found) { 660 | return JSONFailure; 661 | } 662 | 663 | item_ix = object->cells[cell]; 664 | if (free_value) { 665 | val = object->values[item_ix]; 666 | json_value_free(val); 667 | val = NULL; 668 | } 669 | 670 | parson_free(object->names[item_ix]); 671 | last_item_ix = object->count - 1; 672 | if (item_ix < last_item_ix) { 673 | object->names[item_ix] = object->names[last_item_ix]; 674 | object->values[item_ix] = object->values[last_item_ix]; 675 | object->cell_ixs[item_ix] = object->cell_ixs[last_item_ix]; 676 | object->hashes[item_ix] = object->hashes[last_item_ix]; 677 | object->cells[object->cell_ixs[item_ix]] = item_ix; 678 | } 679 | object->count--; 680 | 681 | i = cell; 682 | j = i; 683 | for (x = 0; x < (object->cell_capacity - 1); x++) { 684 | j = (j + 1) & (object->cell_capacity - 1); 685 | if (object->cells[j] == OBJECT_INVALID_IX) { 686 | break; 687 | } 688 | k = object->hashes[object->cells[j]] & (object->cell_capacity - 1); 689 | if ((j > i && (k <= i || k > j)) 690 | || (j < i && (k <= i && k > j))) { 691 | object->cell_ixs[object->cells[j]] = i; 692 | object->cells[i] = object->cells[j]; 693 | i = j; 694 | } 695 | } 696 | object->cells[i] = OBJECT_INVALID_IX; 697 | return JSONSuccess; 698 | } 699 | 700 | static JSON_Status json_object_dotremove_internal(JSON_Object *object, const char *name, parson_bool_t free_value) { 701 | JSON_Value *temp_value = NULL; 702 | JSON_Object *temp_object = NULL; 703 | const char *dot_pos = strchr(name, '.'); 704 | if (!dot_pos) { 705 | return json_object_remove_internal(object, name, free_value); 706 | } 707 | temp_value = json_object_getn_value(object, name, dot_pos - name); 708 | if (json_value_get_type(temp_value) != JSONObject) { 709 | return JSONFailure; 710 | } 711 | temp_object = json_value_get_object(temp_value); 712 | return json_object_dotremove_internal(temp_object, dot_pos + 1, free_value); 713 | } 714 | 715 | static void json_object_free(JSON_Object *object) { 716 | json_object_deinit(object, PARSON_TRUE, PARSON_TRUE); 717 | parson_free(object); 718 | } 719 | 720 | /* JSON Array */ 721 | static JSON_Array * json_array_make(JSON_Value *wrapping_value) { 722 | JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); 723 | if (new_array == NULL) { 724 | return NULL; 725 | } 726 | new_array->wrapping_value = wrapping_value; 727 | new_array->items = (JSON_Value**)NULL; 728 | new_array->capacity = 0; 729 | new_array->count = 0; 730 | return new_array; 731 | } 732 | 733 | static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value) { 734 | if (array->count >= array->capacity) { 735 | size_t new_capacity = MAX(array->capacity * 2, STARTING_CAPACITY); 736 | if (json_array_resize(array, new_capacity) != JSONSuccess) { 737 | return JSONFailure; 738 | } 739 | } 740 | value->parent = json_array_get_wrapping_value(array); 741 | array->items[array->count] = value; 742 | array->count++; 743 | return JSONSuccess; 744 | } 745 | 746 | static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity) { 747 | JSON_Value **new_items = NULL; 748 | if (new_capacity == 0) { 749 | return JSONFailure; 750 | } 751 | new_items = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*)); 752 | if (new_items == NULL) { 753 | return JSONFailure; 754 | } 755 | if (array->items != NULL && array->count > 0) { 756 | memcpy(new_items, array->items, array->count * sizeof(JSON_Value*)); 757 | } 758 | parson_free(array->items); 759 | array->items = new_items; 760 | array->capacity = new_capacity; 761 | return JSONSuccess; 762 | } 763 | 764 | static void json_array_free(JSON_Array *array) { 765 | size_t i; 766 | for (i = 0; i < array->count; i++) { 767 | json_value_free(array->items[i]); 768 | } 769 | parson_free(array->items); 770 | parson_free(array); 771 | } 772 | 773 | /* JSON Value */ 774 | static JSON_Value * json_value_init_string_no_copy(char *string, size_t length) { 775 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 776 | if (!new_value) { 777 | return NULL; 778 | } 779 | new_value->parent = NULL; 780 | new_value->type = JSONString; 781 | new_value->value.string.chars = string; 782 | new_value->value.string.length = length; 783 | return new_value; 784 | } 785 | 786 | /* Parser */ 787 | static JSON_Status skip_quotes(const char **string) { 788 | if (**string != '\"') { 789 | return JSONFailure; 790 | } 791 | SKIP_CHAR(string); 792 | while (**string != '\"') { 793 | if (**string == '\0') { 794 | return JSONFailure; 795 | } else if (**string == '\\') { 796 | SKIP_CHAR(string); 797 | if (**string == '\0') { 798 | return JSONFailure; 799 | } 800 | } 801 | SKIP_CHAR(string); 802 | } 803 | SKIP_CHAR(string); 804 | return JSONSuccess; 805 | } 806 | 807 | static JSON_Status parse_utf16(const char **unprocessed, char **processed) { 808 | unsigned int cp, lead, trail; 809 | char *processed_ptr = *processed; 810 | const char *unprocessed_ptr = *unprocessed; 811 | JSON_Status status = JSONFailure; 812 | unprocessed_ptr++; /* skips u */ 813 | status = parse_utf16_hex(unprocessed_ptr, &cp); 814 | if (status != JSONSuccess) { 815 | return JSONFailure; 816 | } 817 | if (cp < 0x80) { 818 | processed_ptr[0] = (char)cp; /* 0xxxxxxx */ 819 | } else if (cp < 0x800) { 820 | processed_ptr[0] = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */ 821 | processed_ptr[1] = ((cp) & 0x3F) | 0x80; /* 10xxxxxx */ 822 | processed_ptr += 1; 823 | } else if (cp < 0xD800 || cp > 0xDFFF) { 824 | processed_ptr[0] = ((cp >> 12) & 0x0F) | 0xE0; /* 1110xxxx */ 825 | processed_ptr[1] = ((cp >> 6) & 0x3F) | 0x80; /* 10xxxxxx */ 826 | processed_ptr[2] = ((cp) & 0x3F) | 0x80; /* 10xxxxxx */ 827 | processed_ptr += 2; 828 | } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */ 829 | lead = cp; 830 | unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */ 831 | if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u') { 832 | return JSONFailure; 833 | } 834 | status = parse_utf16_hex(unprocessed_ptr, &trail); 835 | if (status != JSONSuccess || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ 836 | return JSONFailure; 837 | } 838 | cp = ((((lead - 0xD800) & 0x3FF) << 10) | ((trail - 0xDC00) & 0x3FF)) + 0x010000; 839 | processed_ptr[0] = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */ 840 | processed_ptr[1] = (((cp >> 12) & 0x3F) | 0x80); /* 10xxxxxx */ 841 | processed_ptr[2] = (((cp >> 6) & 0x3F) | 0x80); /* 10xxxxxx */ 842 | processed_ptr[3] = (((cp) & 0x3F) | 0x80); /* 10xxxxxx */ 843 | processed_ptr += 3; 844 | } else { /* trail surrogate before lead surrogate */ 845 | return JSONFailure; 846 | } 847 | unprocessed_ptr += 3; 848 | *processed = processed_ptr; 849 | *unprocessed = unprocessed_ptr; 850 | return JSONSuccess; 851 | } 852 | 853 | 854 | /* Copies and processes passed string up to supplied length. 855 | Example: "\u006Corem ipsum" -> lorem ipsum */ 856 | static char* process_string(const char *input, size_t input_len, size_t *output_len) { 857 | const char *input_ptr = input; 858 | size_t initial_size = (input_len + 1) * sizeof(char); 859 | size_t final_size = 0; 860 | char *output = NULL, *output_ptr = NULL, *resized_output = NULL; 861 | output = (char*)parson_malloc(initial_size); 862 | if (output == NULL) { 863 | goto error; 864 | } 865 | output_ptr = output; 866 | while ((*input_ptr != '\0') && (size_t)(input_ptr - input) < input_len) { 867 | if (*input_ptr == '\\') { 868 | input_ptr++; 869 | switch (*input_ptr) { 870 | case '\"': *output_ptr = '\"'; break; 871 | case '\\': *output_ptr = '\\'; break; 872 | case '/': *output_ptr = '/'; break; 873 | case 'b': *output_ptr = '\b'; break; 874 | case 'f': *output_ptr = '\f'; break; 875 | case 'n': *output_ptr = '\n'; break; 876 | case 'r': *output_ptr = '\r'; break; 877 | case 't': *output_ptr = '\t'; break; 878 | case 'u': 879 | if (parse_utf16(&input_ptr, &output_ptr) != JSONSuccess) { 880 | goto error; 881 | } 882 | break; 883 | default: 884 | goto error; 885 | } 886 | } else if ((unsigned char)*input_ptr < 0x20) { 887 | goto error; /* 0x00-0x19 are invalid characters for json string (http://www.ietf.org/rfc/rfc4627.txt) */ 888 | } else { 889 | *output_ptr = *input_ptr; 890 | } 891 | output_ptr++; 892 | input_ptr++; 893 | } 894 | *output_ptr = '\0'; 895 | /* resize to new length */ 896 | final_size = (size_t)(output_ptr-output) + 1; 897 | /* todo: don't resize if final_size == initial_size */ 898 | resized_output = (char*)parson_malloc(final_size); 899 | if (resized_output == NULL) { 900 | goto error; 901 | } 902 | memcpy(resized_output, output, final_size); 903 | *output_len = final_size - 1; 904 | parson_free(output); 905 | return resized_output; 906 | error: 907 | parson_free(output); 908 | return NULL; 909 | } 910 | 911 | /* Return processed contents of a string between quotes and 912 | skips passed argument to a matching quote. */ 913 | static char * get_quoted_string(const char **string, size_t *output_string_len) { 914 | const char *string_start = *string; 915 | size_t input_string_len = 0; 916 | JSON_Status status = skip_quotes(string); 917 | if (status != JSONSuccess) { 918 | return NULL; 919 | } 920 | input_string_len = *string - string_start - 2; /* length without quotes */ 921 | return process_string(string_start + 1, input_string_len, output_string_len); 922 | } 923 | 924 | static JSON_Value * parse_value(const char **string, size_t nesting) { 925 | if (nesting > MAX_NESTING) { 926 | return NULL; 927 | } 928 | SKIP_WHITESPACES(string); 929 | switch (**string) { 930 | case '{': 931 | return parse_object_value(string, nesting + 1); 932 | case '[': 933 | return parse_array_value(string, nesting + 1); 934 | case '\"': 935 | return parse_string_value(string); 936 | case 'f': case 't': 937 | return parse_boolean_value(string); 938 | case '-': 939 | case '0': case '1': case '2': case '3': case '4': 940 | case '5': case '6': case '7': case '8': case '9': 941 | return parse_number_value(string); 942 | case 'n': 943 | return parse_null_value(string); 944 | default: 945 | return NULL; 946 | } 947 | } 948 | 949 | static JSON_Value * parse_object_value(const char **string, size_t nesting) { 950 | JSON_Status status = JSONFailure; 951 | JSON_Value *output_value = NULL, *new_value = NULL; 952 | JSON_Object *output_object = NULL; 953 | char *new_key = NULL; 954 | 955 | output_value = json_value_init_object(); 956 | if (output_value == NULL) { 957 | return NULL; 958 | } 959 | if (**string != '{') { 960 | json_value_free(output_value); 961 | return NULL; 962 | } 963 | output_object = json_value_get_object(output_value); 964 | SKIP_CHAR(string); 965 | SKIP_WHITESPACES(string); 966 | if (**string == '}') { /* empty object */ 967 | SKIP_CHAR(string); 968 | return output_value; 969 | } 970 | while (**string != '\0') { 971 | size_t key_len = 0; 972 | new_key = get_quoted_string(string, &key_len); 973 | /* We do not support key names with embedded \0 chars */ 974 | if (!new_key) { 975 | json_value_free(output_value); 976 | return NULL; 977 | } 978 | if (key_len != strlen(new_key)) { 979 | parson_free(new_key); 980 | json_value_free(output_value); 981 | return NULL; 982 | } 983 | SKIP_WHITESPACES(string); 984 | if (**string != ':') { 985 | parson_free(new_key); 986 | json_value_free(output_value); 987 | return NULL; 988 | } 989 | SKIP_CHAR(string); 990 | new_value = parse_value(string, nesting); 991 | if (new_value == NULL) { 992 | parson_free(new_key); 993 | json_value_free(output_value); 994 | return NULL; 995 | } 996 | status = json_object_add(output_object, new_key, new_value); 997 | if (status != JSONSuccess) { 998 | parson_free(new_key); 999 | json_value_free(new_value); 1000 | json_value_free(output_value); 1001 | return NULL; 1002 | } 1003 | SKIP_WHITESPACES(string); 1004 | if (**string != ',') { 1005 | break; 1006 | } 1007 | SKIP_CHAR(string); 1008 | SKIP_WHITESPACES(string); 1009 | if (**string == '}') { 1010 | break; 1011 | } 1012 | } 1013 | SKIP_WHITESPACES(string); 1014 | if (**string != '}') { 1015 | json_value_free(output_value); 1016 | return NULL; 1017 | } 1018 | SKIP_CHAR(string); 1019 | return output_value; 1020 | } 1021 | 1022 | static JSON_Value * parse_array_value(const char **string, size_t nesting) { 1023 | JSON_Value *output_value = NULL, *new_array_value = NULL; 1024 | JSON_Array *output_array = NULL; 1025 | output_value = json_value_init_array(); 1026 | if (output_value == NULL) { 1027 | return NULL; 1028 | } 1029 | if (**string != '[') { 1030 | json_value_free(output_value); 1031 | return NULL; 1032 | } 1033 | output_array = json_value_get_array(output_value); 1034 | SKIP_CHAR(string); 1035 | SKIP_WHITESPACES(string); 1036 | if (**string == ']') { /* empty array */ 1037 | SKIP_CHAR(string); 1038 | return output_value; 1039 | } 1040 | while (**string != '\0') { 1041 | new_array_value = parse_value(string, nesting); 1042 | if (new_array_value == NULL) { 1043 | json_value_free(output_value); 1044 | return NULL; 1045 | } 1046 | if (json_array_add(output_array, new_array_value) != JSONSuccess) { 1047 | json_value_free(new_array_value); 1048 | json_value_free(output_value); 1049 | return NULL; 1050 | } 1051 | SKIP_WHITESPACES(string); 1052 | if (**string != ',') { 1053 | break; 1054 | } 1055 | SKIP_CHAR(string); 1056 | SKIP_WHITESPACES(string); 1057 | if (**string == ']') { 1058 | break; 1059 | } 1060 | } 1061 | SKIP_WHITESPACES(string); 1062 | if (**string != ']' || /* Trim array after parsing is over */ 1063 | json_array_resize(output_array, json_array_get_count(output_array)) != JSONSuccess) { 1064 | json_value_free(output_value); 1065 | return NULL; 1066 | } 1067 | SKIP_CHAR(string); 1068 | return output_value; 1069 | } 1070 | 1071 | static JSON_Value * parse_string_value(const char **string) { 1072 | JSON_Value *value = NULL; 1073 | size_t new_string_len = 0; 1074 | char *new_string = get_quoted_string(string, &new_string_len); 1075 | if (new_string == NULL) { 1076 | return NULL; 1077 | } 1078 | value = json_value_init_string_no_copy(new_string, new_string_len); 1079 | if (value == NULL) { 1080 | parson_free(new_string); 1081 | return NULL; 1082 | } 1083 | return value; 1084 | } 1085 | 1086 | static JSON_Value * parse_boolean_value(const char **string) { 1087 | size_t true_token_size = SIZEOF_TOKEN("true"); 1088 | size_t false_token_size = SIZEOF_TOKEN("false"); 1089 | if (strncmp("true", *string, true_token_size) == 0) { 1090 | *string += true_token_size; 1091 | return json_value_init_boolean(1); 1092 | } else if (strncmp("false", *string, false_token_size) == 0) { 1093 | *string += false_token_size; 1094 | return json_value_init_boolean(0); 1095 | } 1096 | return NULL; 1097 | } 1098 | 1099 | static JSON_Value * parse_number_value(const char **string) { 1100 | char *end; 1101 | double number = 0; 1102 | errno = 0; 1103 | number = strtod(*string, &end); 1104 | if (errno == ERANGE && (number <= -HUGE_VAL || number >= HUGE_VAL)) { 1105 | return NULL; 1106 | } 1107 | if ((errno && errno != ERANGE) || !is_decimal(*string, end - *string)) { 1108 | return NULL; 1109 | } 1110 | *string = end; 1111 | return json_value_init_number(number); 1112 | } 1113 | 1114 | static JSON_Value * parse_null_value(const char **string) { 1115 | size_t token_size = SIZEOF_TOKEN("null"); 1116 | if (strncmp("null", *string, token_size) == 0) { 1117 | *string += token_size; 1118 | return json_value_init_null(); 1119 | } 1120 | return NULL; 1121 | } 1122 | 1123 | /* Serialization */ 1124 | 1125 | /* APPEND_STRING() is only called on string literals. 1126 | It's a bit hacky because it makes plenty of assumptions about the external state 1127 | and should eventually be tidied up into a function (same goes for APPEND_INDENT) 1128 | */ 1129 | #define APPEND_STRING(str) do {\ 1130 | written = SIZEOF_TOKEN((str));\ 1131 | if (buf != NULL) {\ 1132 | memcpy(buf, (str), written);\ 1133 | buf[written] = '\0';\ 1134 | buf += written;\ 1135 | }\ 1136 | written_total += written;\ 1137 | } while (0) 1138 | 1139 | #define APPEND_INDENT(level) do {\ 1140 | int level_i = 0;\ 1141 | for (level_i = 0; level_i < (level); level_i++) {\ 1142 | APPEND_STRING(PARSON_INDENT_STR);\ 1143 | }\ 1144 | } while (0) 1145 | 1146 | static int json_serialize_to_buffer_r(const JSON_Value *value, char *buf, int level, parson_bool_t is_pretty, char *num_buf) 1147 | { 1148 | const char *key = NULL, *string = NULL; 1149 | JSON_Value *temp_value = NULL; 1150 | JSON_Array *array = NULL; 1151 | JSON_Object *object = NULL; 1152 | size_t i = 0, count = 0; 1153 | double num = 0.0; 1154 | int written = -1, written_total = 0; 1155 | size_t len = 0; 1156 | 1157 | switch (json_value_get_type(value)) { 1158 | case JSONArray: 1159 | array = json_value_get_array(value); 1160 | count = json_array_get_count(array); 1161 | APPEND_STRING("["); 1162 | if (count > 0 && is_pretty) { 1163 | APPEND_STRING("\n"); 1164 | } 1165 | for (i = 0; i < count; i++) { 1166 | if (is_pretty) { 1167 | APPEND_INDENT(level+1); 1168 | } 1169 | temp_value = json_array_get_value(array, i); 1170 | written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); 1171 | if (written < 0) { 1172 | return -1; 1173 | } 1174 | if (buf != NULL) { 1175 | buf += written; 1176 | } 1177 | written_total += written; 1178 | if (i < (count - 1)) { 1179 | APPEND_STRING(","); 1180 | } 1181 | if (is_pretty) { 1182 | APPEND_STRING("\n"); 1183 | } 1184 | } 1185 | if (count > 0 && is_pretty) { 1186 | APPEND_INDENT(level); 1187 | } 1188 | APPEND_STRING("]"); 1189 | return written_total; 1190 | case JSONObject: 1191 | object = json_value_get_object(value); 1192 | count = json_object_get_count(object); 1193 | APPEND_STRING("{"); 1194 | if (count > 0 && is_pretty) { 1195 | APPEND_STRING("\n"); 1196 | } 1197 | for (i = 0; i < count; i++) { 1198 | key = json_object_get_name(object, i); 1199 | if (key == NULL) { 1200 | return -1; 1201 | } 1202 | if (is_pretty) { 1203 | APPEND_INDENT(level+1); 1204 | } 1205 | /* We do not support key names with embedded \0 chars */ 1206 | written = json_serialize_string(key, strlen(key), buf); 1207 | if (written < 0) { 1208 | return -1; 1209 | } 1210 | if (buf != NULL) { 1211 | buf += written; 1212 | } 1213 | written_total += written; 1214 | APPEND_STRING(":"); 1215 | if (is_pretty) { 1216 | APPEND_STRING(" "); 1217 | } 1218 | temp_value = json_object_get_value_at(object, i); 1219 | written = json_serialize_to_buffer_r(temp_value, buf, level+1, is_pretty, num_buf); 1220 | if (written < 0) { 1221 | return -1; 1222 | } 1223 | if (buf != NULL) { 1224 | buf += written; 1225 | } 1226 | written_total += written; 1227 | if (i < (count - 1)) { 1228 | APPEND_STRING(","); 1229 | } 1230 | if (is_pretty) { 1231 | APPEND_STRING("\n"); 1232 | } 1233 | } 1234 | if (count > 0 && is_pretty) { 1235 | APPEND_INDENT(level); 1236 | } 1237 | APPEND_STRING("}"); 1238 | return written_total; 1239 | case JSONString: 1240 | string = json_value_get_string(value); 1241 | if (string == NULL) { 1242 | return -1; 1243 | } 1244 | len = json_value_get_string_len(value); 1245 | written = json_serialize_string(string, len, buf); 1246 | if (written < 0) { 1247 | return -1; 1248 | } 1249 | if (buf != NULL) { 1250 | buf += written; 1251 | } 1252 | written_total += written; 1253 | return written_total; 1254 | case JSONBoolean: 1255 | if (json_value_get_boolean(value)) { 1256 | APPEND_STRING("true"); 1257 | } else { 1258 | APPEND_STRING("false"); 1259 | } 1260 | return written_total; 1261 | case JSONNumber: 1262 | num = json_value_get_number(value); 1263 | if (buf != NULL) { 1264 | num_buf = buf; 1265 | } 1266 | if (parson_number_serialization_function) { 1267 | written = parson_number_serialization_function(num, num_buf); 1268 | } else { 1269 | const char *float_format = parson_float_format ? parson_float_format : PARSON_DEFAULT_FLOAT_FORMAT; 1270 | written = parson_sprintf(num_buf, float_format, num); 1271 | } 1272 | if (written < 0) { 1273 | return -1; 1274 | } 1275 | if (buf != NULL) { 1276 | buf += written; 1277 | } 1278 | written_total += written; 1279 | return written_total; 1280 | case JSONNull: 1281 | APPEND_STRING("null"); 1282 | return written_total; 1283 | case JSONError: 1284 | return -1; 1285 | default: 1286 | return -1; 1287 | } 1288 | } 1289 | 1290 | static int json_serialize_string(const char *string, size_t len, char *buf) { 1291 | size_t i = 0; 1292 | char c = '\0'; 1293 | int written = -1, written_total = 0; 1294 | APPEND_STRING("\""); 1295 | for (i = 0; i < len; i++) { 1296 | c = string[i]; 1297 | switch (c) { 1298 | case '\"': APPEND_STRING("\\\""); break; 1299 | case '\\': APPEND_STRING("\\\\"); break; 1300 | case '\b': APPEND_STRING("\\b"); break; 1301 | case '\f': APPEND_STRING("\\f"); break; 1302 | case '\n': APPEND_STRING("\\n"); break; 1303 | case '\r': APPEND_STRING("\\r"); break; 1304 | case '\t': APPEND_STRING("\\t"); break; 1305 | case '\x00': APPEND_STRING("\\u0000"); break; 1306 | case '\x01': APPEND_STRING("\\u0001"); break; 1307 | case '\x02': APPEND_STRING("\\u0002"); break; 1308 | case '\x03': APPEND_STRING("\\u0003"); break; 1309 | case '\x04': APPEND_STRING("\\u0004"); break; 1310 | case '\x05': APPEND_STRING("\\u0005"); break; 1311 | case '\x06': APPEND_STRING("\\u0006"); break; 1312 | case '\x07': APPEND_STRING("\\u0007"); break; 1313 | /* '\x08' duplicate: '\b' */ 1314 | /* '\x09' duplicate: '\t' */ 1315 | /* '\x0a' duplicate: '\n' */ 1316 | case '\x0b': APPEND_STRING("\\u000b"); break; 1317 | /* '\x0c' duplicate: '\f' */ 1318 | /* '\x0d' duplicate: '\r' */ 1319 | case '\x0e': APPEND_STRING("\\u000e"); break; 1320 | case '\x0f': APPEND_STRING("\\u000f"); break; 1321 | case '\x10': APPEND_STRING("\\u0010"); break; 1322 | case '\x11': APPEND_STRING("\\u0011"); break; 1323 | case '\x12': APPEND_STRING("\\u0012"); break; 1324 | case '\x13': APPEND_STRING("\\u0013"); break; 1325 | case '\x14': APPEND_STRING("\\u0014"); break; 1326 | case '\x15': APPEND_STRING("\\u0015"); break; 1327 | case '\x16': APPEND_STRING("\\u0016"); break; 1328 | case '\x17': APPEND_STRING("\\u0017"); break; 1329 | case '\x18': APPEND_STRING("\\u0018"); break; 1330 | case '\x19': APPEND_STRING("\\u0019"); break; 1331 | case '\x1a': APPEND_STRING("\\u001a"); break; 1332 | case '\x1b': APPEND_STRING("\\u001b"); break; 1333 | case '\x1c': APPEND_STRING("\\u001c"); break; 1334 | case '\x1d': APPEND_STRING("\\u001d"); break; 1335 | case '\x1e': APPEND_STRING("\\u001e"); break; 1336 | case '\x1f': APPEND_STRING("\\u001f"); break; 1337 | case '/': 1338 | if (parson_escape_slashes) { 1339 | APPEND_STRING("\\/"); /* to make json embeddable in xml\/html */ 1340 | } else { 1341 | APPEND_STRING("/"); 1342 | } 1343 | break; 1344 | default: 1345 | if (buf != NULL) { 1346 | buf[0] = c; 1347 | buf += 1; 1348 | } 1349 | written_total += 1; 1350 | break; 1351 | } 1352 | } 1353 | APPEND_STRING("\""); 1354 | return written_total; 1355 | } 1356 | 1357 | #undef APPEND_STRING 1358 | #undef APPEND_INDENT 1359 | 1360 | /* Parser API */ 1361 | JSON_Value * json_parse_file(const char *filename) { 1362 | char *file_contents = read_file(filename); 1363 | JSON_Value *output_value = NULL; 1364 | if (file_contents == NULL) { 1365 | return NULL; 1366 | } 1367 | output_value = json_parse_string(file_contents); 1368 | parson_free(file_contents); 1369 | return output_value; 1370 | } 1371 | 1372 | JSON_Value * json_parse_file_with_comments(const char *filename) { 1373 | char *file_contents = read_file(filename); 1374 | JSON_Value *output_value = NULL; 1375 | if (file_contents == NULL) { 1376 | return NULL; 1377 | } 1378 | output_value = json_parse_string_with_comments(file_contents); 1379 | parson_free(file_contents); 1380 | return output_value; 1381 | } 1382 | 1383 | JSON_Value * json_parse_string(const char *string) { 1384 | if (string == NULL) { 1385 | return NULL; 1386 | } 1387 | if (string[0] == '\xEF' && string[1] == '\xBB' && string[2] == '\xBF') { 1388 | string = string + 3; /* Support for UTF-8 BOM */ 1389 | } 1390 | return parse_value((const char**)&string, 0); 1391 | } 1392 | 1393 | JSON_Value * json_parse_string_with_comments(const char *string) { 1394 | JSON_Value *result = NULL; 1395 | char *string_mutable_copy = NULL, *string_mutable_copy_ptr = NULL; 1396 | string_mutable_copy = parson_strdup(string); 1397 | if (string_mutable_copy == NULL) { 1398 | return NULL; 1399 | } 1400 | remove_comments(string_mutable_copy, "/*", "*/"); 1401 | remove_comments(string_mutable_copy, "//", "\n"); 1402 | string_mutable_copy_ptr = string_mutable_copy; 1403 | result = parse_value((const char**)&string_mutable_copy_ptr, 0); 1404 | parson_free(string_mutable_copy); 1405 | return result; 1406 | } 1407 | 1408 | /* JSON Object API */ 1409 | 1410 | JSON_Value * json_object_get_value(const JSON_Object *object, const char *name) { 1411 | if (object == NULL || name == NULL) { 1412 | return NULL; 1413 | } 1414 | return json_object_getn_value(object, name, strlen(name)); 1415 | } 1416 | 1417 | const char * json_object_get_string(const JSON_Object *object, const char *name) { 1418 | return json_value_get_string(json_object_get_value(object, name)); 1419 | } 1420 | 1421 | size_t json_object_get_string_len(const JSON_Object *object, const char *name) { 1422 | return json_value_get_string_len(json_object_get_value(object, name)); 1423 | } 1424 | 1425 | double json_object_get_number(const JSON_Object *object, const char *name) { 1426 | return json_value_get_number(json_object_get_value(object, name)); 1427 | } 1428 | 1429 | JSON_Object * json_object_get_object(const JSON_Object *object, const char *name) { 1430 | return json_value_get_object(json_object_get_value(object, name)); 1431 | } 1432 | 1433 | JSON_Array * json_object_get_array(const JSON_Object *object, const char *name) { 1434 | return json_value_get_array(json_object_get_value(object, name)); 1435 | } 1436 | 1437 | int json_object_get_boolean(const JSON_Object *object, const char *name) { 1438 | return json_value_get_boolean(json_object_get_value(object, name)); 1439 | } 1440 | 1441 | JSON_Value * json_object_dotget_value(const JSON_Object *object, const char *name) { 1442 | const char *dot_position = strchr(name, '.'); 1443 | if (!dot_position) { 1444 | return json_object_get_value(object, name); 1445 | } 1446 | object = json_value_get_object(json_object_getn_value(object, name, dot_position - name)); 1447 | return json_object_dotget_value(object, dot_position + 1); 1448 | } 1449 | 1450 | const char * json_object_dotget_string(const JSON_Object *object, const char *name) { 1451 | return json_value_get_string(json_object_dotget_value(object, name)); 1452 | } 1453 | 1454 | size_t json_object_dotget_string_len(const JSON_Object *object, const char *name) { 1455 | return json_value_get_string_len(json_object_dotget_value(object, name)); 1456 | } 1457 | 1458 | double json_object_dotget_number(const JSON_Object *object, const char *name) { 1459 | return json_value_get_number(json_object_dotget_value(object, name)); 1460 | } 1461 | 1462 | JSON_Object * json_object_dotget_object(const JSON_Object *object, const char *name) { 1463 | return json_value_get_object(json_object_dotget_value(object, name)); 1464 | } 1465 | 1466 | JSON_Array * json_object_dotget_array(const JSON_Object *object, const char *name) { 1467 | return json_value_get_array(json_object_dotget_value(object, name)); 1468 | } 1469 | 1470 | int json_object_dotget_boolean(const JSON_Object *object, const char *name) { 1471 | return json_value_get_boolean(json_object_dotget_value(object, name)); 1472 | } 1473 | 1474 | size_t json_object_get_count(const JSON_Object *object) { 1475 | return object ? object->count : 0; 1476 | } 1477 | 1478 | const char * json_object_get_name(const JSON_Object *object, size_t index) { 1479 | if (object == NULL || index >= json_object_get_count(object)) { 1480 | return NULL; 1481 | } 1482 | return object->names[index]; 1483 | } 1484 | 1485 | JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index) { 1486 | if (object == NULL || index >= json_object_get_count(object)) { 1487 | return NULL; 1488 | } 1489 | return object->values[index]; 1490 | } 1491 | 1492 | JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) { 1493 | if (!object) { 1494 | return NULL; 1495 | } 1496 | return object->wrapping_value; 1497 | } 1498 | 1499 | int json_object_has_value (const JSON_Object *object, const char *name) { 1500 | return json_object_get_value(object, name) != NULL; 1501 | } 1502 | 1503 | int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) { 1504 | JSON_Value *val = json_object_get_value(object, name); 1505 | return val != NULL && json_value_get_type(val) == type; 1506 | } 1507 | 1508 | int json_object_dothas_value (const JSON_Object *object, const char *name) { 1509 | return json_object_dotget_value(object, name) != NULL; 1510 | } 1511 | 1512 | int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type) { 1513 | JSON_Value *val = json_object_dotget_value(object, name); 1514 | return val != NULL && json_value_get_type(val) == type; 1515 | } 1516 | 1517 | /* JSON Array API */ 1518 | JSON_Value * json_array_get_value(const JSON_Array *array, size_t index) { 1519 | if (array == NULL || index >= json_array_get_count(array)) { 1520 | return NULL; 1521 | } 1522 | return array->items[index]; 1523 | } 1524 | 1525 | const char * json_array_get_string(const JSON_Array *array, size_t index) { 1526 | return json_value_get_string(json_array_get_value(array, index)); 1527 | } 1528 | 1529 | size_t json_array_get_string_len(const JSON_Array *array, size_t index) { 1530 | return json_value_get_string_len(json_array_get_value(array, index)); 1531 | } 1532 | 1533 | double json_array_get_number(const JSON_Array *array, size_t index) { 1534 | return json_value_get_number(json_array_get_value(array, index)); 1535 | } 1536 | 1537 | JSON_Object * json_array_get_object(const JSON_Array *array, size_t index) { 1538 | return json_value_get_object(json_array_get_value(array, index)); 1539 | } 1540 | 1541 | JSON_Array * json_array_get_array(const JSON_Array *array, size_t index) { 1542 | return json_value_get_array(json_array_get_value(array, index)); 1543 | } 1544 | 1545 | int json_array_get_boolean(const JSON_Array *array, size_t index) { 1546 | return json_value_get_boolean(json_array_get_value(array, index)); 1547 | } 1548 | 1549 | size_t json_array_get_count(const JSON_Array *array) { 1550 | return array ? array->count : 0; 1551 | } 1552 | 1553 | JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) { 1554 | if (!array) { 1555 | return NULL; 1556 | } 1557 | return array->wrapping_value; 1558 | } 1559 | 1560 | /* JSON Value API */ 1561 | JSON_Value_Type json_value_get_type(const JSON_Value *value) { 1562 | return value ? value->type : JSONError; 1563 | } 1564 | 1565 | JSON_Object * json_value_get_object(const JSON_Value *value) { 1566 | return json_value_get_type(value) == JSONObject ? value->value.object : NULL; 1567 | } 1568 | 1569 | JSON_Array * json_value_get_array(const JSON_Value *value) { 1570 | return json_value_get_type(value) == JSONArray ? value->value.array : NULL; 1571 | } 1572 | 1573 | static const JSON_String * json_value_get_string_desc(const JSON_Value *value) { 1574 | return json_value_get_type(value) == JSONString ? &value->value.string : NULL; 1575 | } 1576 | 1577 | const char * json_value_get_string(const JSON_Value *value) { 1578 | const JSON_String *str = json_value_get_string_desc(value); 1579 | return str ? str->chars : NULL; 1580 | } 1581 | 1582 | size_t json_value_get_string_len(const JSON_Value *value) { 1583 | const JSON_String *str = json_value_get_string_desc(value); 1584 | return str ? str->length : 0; 1585 | } 1586 | 1587 | double json_value_get_number(const JSON_Value *value) { 1588 | return json_value_get_type(value) == JSONNumber ? value->value.number : 0; 1589 | } 1590 | 1591 | int json_value_get_boolean(const JSON_Value *value) { 1592 | return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1; 1593 | } 1594 | 1595 | JSON_Value * json_value_get_parent (const JSON_Value *value) { 1596 | return value ? value->parent : NULL; 1597 | } 1598 | 1599 | void json_value_free(JSON_Value *value) { 1600 | switch (json_value_get_type(value)) { 1601 | case JSONObject: 1602 | json_object_free(value->value.object); 1603 | break; 1604 | case JSONString: 1605 | parson_free(value->value.string.chars); 1606 | break; 1607 | case JSONArray: 1608 | json_array_free(value->value.array); 1609 | break; 1610 | default: 1611 | break; 1612 | } 1613 | parson_free(value); 1614 | } 1615 | 1616 | JSON_Value * json_value_init_object(void) { 1617 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1618 | if (!new_value) { 1619 | return NULL; 1620 | } 1621 | new_value->parent = NULL; 1622 | new_value->type = JSONObject; 1623 | new_value->value.object = json_object_make(new_value); 1624 | if (!new_value->value.object) { 1625 | parson_free(new_value); 1626 | return NULL; 1627 | } 1628 | return new_value; 1629 | } 1630 | 1631 | JSON_Value * json_value_init_array(void) { 1632 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1633 | if (!new_value) { 1634 | return NULL; 1635 | } 1636 | new_value->parent = NULL; 1637 | new_value->type = JSONArray; 1638 | new_value->value.array = json_array_make(new_value); 1639 | if (!new_value->value.array) { 1640 | parson_free(new_value); 1641 | return NULL; 1642 | } 1643 | return new_value; 1644 | } 1645 | 1646 | JSON_Value * json_value_init_string(const char *string) { 1647 | if (string == NULL) { 1648 | return NULL; 1649 | } 1650 | return json_value_init_string_with_len(string, strlen(string)); 1651 | } 1652 | 1653 | JSON_Value * json_value_init_string_with_len(const char *string, size_t length) { 1654 | char *copy = NULL; 1655 | JSON_Value *value; 1656 | if (string == NULL) { 1657 | return NULL; 1658 | } 1659 | if (!is_valid_utf8(string, length)) { 1660 | return NULL; 1661 | } 1662 | copy = parson_strndup(string, length); 1663 | if (copy == NULL) { 1664 | return NULL; 1665 | } 1666 | value = json_value_init_string_no_copy(copy, length); 1667 | if (value == NULL) { 1668 | parson_free(copy); 1669 | } 1670 | return value; 1671 | } 1672 | 1673 | JSON_Value * json_value_init_number(double number) { 1674 | JSON_Value *new_value = NULL; 1675 | if (IS_NUMBER_INVALID(number)) { 1676 | return NULL; 1677 | } 1678 | new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1679 | if (new_value == NULL) { 1680 | return NULL; 1681 | } 1682 | new_value->parent = NULL; 1683 | new_value->type = JSONNumber; 1684 | new_value->value.number = number; 1685 | return new_value; 1686 | } 1687 | 1688 | JSON_Value * json_value_init_boolean(int boolean) { 1689 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1690 | if (!new_value) { 1691 | return NULL; 1692 | } 1693 | new_value->parent = NULL; 1694 | new_value->type = JSONBoolean; 1695 | new_value->value.boolean = boolean ? 1 : 0; 1696 | return new_value; 1697 | } 1698 | 1699 | JSON_Value * json_value_init_null(void) { 1700 | JSON_Value *new_value = (JSON_Value*)parson_malloc(sizeof(JSON_Value)); 1701 | if (!new_value) { 1702 | return NULL; 1703 | } 1704 | new_value->parent = NULL; 1705 | new_value->type = JSONNull; 1706 | return new_value; 1707 | } 1708 | 1709 | JSON_Value * json_value_deep_copy(const JSON_Value *value) { 1710 | size_t i = 0; 1711 | JSON_Value *return_value = NULL, *temp_value_copy = NULL, *temp_value = NULL; 1712 | const JSON_String *temp_string = NULL; 1713 | const char *temp_key = NULL; 1714 | char *temp_string_copy = NULL; 1715 | JSON_Array *temp_array = NULL, *temp_array_copy = NULL; 1716 | JSON_Object *temp_object = NULL, *temp_object_copy = NULL; 1717 | JSON_Status res = JSONFailure; 1718 | char *key_copy = NULL; 1719 | 1720 | switch (json_value_get_type(value)) { 1721 | case JSONArray: 1722 | temp_array = json_value_get_array(value); 1723 | return_value = json_value_init_array(); 1724 | if (return_value == NULL) { 1725 | return NULL; 1726 | } 1727 | temp_array_copy = json_value_get_array(return_value); 1728 | for (i = 0; i < json_array_get_count(temp_array); i++) { 1729 | temp_value = json_array_get_value(temp_array, i); 1730 | temp_value_copy = json_value_deep_copy(temp_value); 1731 | if (temp_value_copy == NULL) { 1732 | json_value_free(return_value); 1733 | return NULL; 1734 | } 1735 | if (json_array_add(temp_array_copy, temp_value_copy) != JSONSuccess) { 1736 | json_value_free(return_value); 1737 | json_value_free(temp_value_copy); 1738 | return NULL; 1739 | } 1740 | } 1741 | return return_value; 1742 | case JSONObject: 1743 | temp_object = json_value_get_object(value); 1744 | return_value = json_value_init_object(); 1745 | if (!return_value) { 1746 | return NULL; 1747 | } 1748 | temp_object_copy = json_value_get_object(return_value); 1749 | for (i = 0; i < json_object_get_count(temp_object); i++) { 1750 | temp_key = json_object_get_name(temp_object, i); 1751 | temp_value = json_object_get_value(temp_object, temp_key); 1752 | temp_value_copy = json_value_deep_copy(temp_value); 1753 | if (!temp_value_copy) { 1754 | json_value_free(return_value); 1755 | return NULL; 1756 | } 1757 | key_copy = parson_strdup(temp_key); 1758 | if (!key_copy) { 1759 | json_value_free(temp_value_copy); 1760 | json_value_free(return_value); 1761 | return NULL; 1762 | } 1763 | res = json_object_add(temp_object_copy, key_copy, temp_value_copy); 1764 | if (res != JSONSuccess) { 1765 | parson_free(key_copy); 1766 | json_value_free(temp_value_copy); 1767 | json_value_free(return_value); 1768 | return NULL; 1769 | } 1770 | } 1771 | return return_value; 1772 | case JSONBoolean: 1773 | return json_value_init_boolean(json_value_get_boolean(value)); 1774 | case JSONNumber: 1775 | return json_value_init_number(json_value_get_number(value)); 1776 | case JSONString: 1777 | temp_string = json_value_get_string_desc(value); 1778 | if (temp_string == NULL) { 1779 | return NULL; 1780 | } 1781 | temp_string_copy = parson_strndup(temp_string->chars, temp_string->length); 1782 | if (temp_string_copy == NULL) { 1783 | return NULL; 1784 | } 1785 | return_value = json_value_init_string_no_copy(temp_string_copy, temp_string->length); 1786 | if (return_value == NULL) { 1787 | parson_free(temp_string_copy); 1788 | } 1789 | return return_value; 1790 | case JSONNull: 1791 | return json_value_init_null(); 1792 | case JSONError: 1793 | return NULL; 1794 | default: 1795 | return NULL; 1796 | } 1797 | } 1798 | 1799 | size_t json_serialization_size(const JSON_Value *value) { 1800 | char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ 1801 | int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_FALSE, num_buf); 1802 | return res < 0 ? 0 : (size_t)(res) + 1; 1803 | } 1804 | 1805 | JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) { 1806 | int written = -1; 1807 | size_t needed_size_in_bytes = json_serialization_size(value); 1808 | if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { 1809 | return JSONFailure; 1810 | } 1811 | written = json_serialize_to_buffer_r(value, buf, 0, PARSON_FALSE, NULL); 1812 | if (written < 0) { 1813 | return JSONFailure; 1814 | } 1815 | return JSONSuccess; 1816 | } 1817 | 1818 | JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename) { 1819 | JSON_Status return_code = JSONSuccess; 1820 | FILE *fp = NULL; 1821 | char *serialized_string = json_serialize_to_string(value); 1822 | if (serialized_string == NULL) { 1823 | return JSONFailure; 1824 | } 1825 | fp = fopen(filename, "w"); 1826 | if (fp == NULL) { 1827 | json_free_serialized_string(serialized_string); 1828 | return JSONFailure; 1829 | } 1830 | if (fputs(serialized_string, fp) == EOF) { 1831 | return_code = JSONFailure; 1832 | } 1833 | if (fclose(fp) == EOF) { 1834 | return_code = JSONFailure; 1835 | } 1836 | json_free_serialized_string(serialized_string); 1837 | return return_code; 1838 | } 1839 | 1840 | char * json_serialize_to_string(const JSON_Value *value) { 1841 | JSON_Status serialization_result = JSONFailure; 1842 | size_t buf_size_bytes = json_serialization_size(value); 1843 | char *buf = NULL; 1844 | if (buf_size_bytes == 0) { 1845 | return NULL; 1846 | } 1847 | buf = (char*)parson_malloc(buf_size_bytes); 1848 | if (buf == NULL) { 1849 | return NULL; 1850 | } 1851 | serialization_result = json_serialize_to_buffer(value, buf, buf_size_bytes); 1852 | if (serialization_result != JSONSuccess) { 1853 | json_free_serialized_string(buf); 1854 | return NULL; 1855 | } 1856 | return buf; 1857 | } 1858 | 1859 | size_t json_serialization_size_pretty(const JSON_Value *value) { 1860 | char num_buf[PARSON_NUM_BUF_SIZE]; /* recursively allocating buffer on stack is a bad idea, so let's do it only once */ 1861 | int res = json_serialize_to_buffer_r(value, NULL, 0, PARSON_TRUE, num_buf); 1862 | return res < 0 ? 0 : (size_t)(res) + 1; 1863 | } 1864 | 1865 | JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes) { 1866 | int written = -1; 1867 | size_t needed_size_in_bytes = json_serialization_size_pretty(value); 1868 | if (needed_size_in_bytes == 0 || buf_size_in_bytes < needed_size_in_bytes) { 1869 | return JSONFailure; 1870 | } 1871 | written = json_serialize_to_buffer_r(value, buf, 0, PARSON_TRUE, NULL); 1872 | if (written < 0) { 1873 | return JSONFailure; 1874 | } 1875 | return JSONSuccess; 1876 | } 1877 | 1878 | JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename) { 1879 | JSON_Status return_code = JSONSuccess; 1880 | FILE *fp = NULL; 1881 | char *serialized_string = json_serialize_to_string_pretty(value); 1882 | if (serialized_string == NULL) { 1883 | return JSONFailure; 1884 | } 1885 | fp = fopen(filename, "w"); 1886 | if (fp == NULL) { 1887 | json_free_serialized_string(serialized_string); 1888 | return JSONFailure; 1889 | } 1890 | if (fputs(serialized_string, fp) == EOF) { 1891 | return_code = JSONFailure; 1892 | } 1893 | if (fclose(fp) == EOF) { 1894 | return_code = JSONFailure; 1895 | } 1896 | json_free_serialized_string(serialized_string); 1897 | return return_code; 1898 | } 1899 | 1900 | char * json_serialize_to_string_pretty(const JSON_Value *value) { 1901 | JSON_Status serialization_result = JSONFailure; 1902 | size_t buf_size_bytes = json_serialization_size_pretty(value); 1903 | char *buf = NULL; 1904 | if (buf_size_bytes == 0) { 1905 | return NULL; 1906 | } 1907 | buf = (char*)parson_malloc(buf_size_bytes); 1908 | if (buf == NULL) { 1909 | return NULL; 1910 | } 1911 | serialization_result = json_serialize_to_buffer_pretty(value, buf, buf_size_bytes); 1912 | if (serialization_result != JSONSuccess) { 1913 | json_free_serialized_string(buf); 1914 | return NULL; 1915 | } 1916 | return buf; 1917 | } 1918 | 1919 | void json_free_serialized_string(char *string) { 1920 | parson_free(string); 1921 | } 1922 | 1923 | JSON_Status json_array_remove(JSON_Array *array, size_t ix) { 1924 | size_t to_move_bytes = 0; 1925 | if (array == NULL || ix >= json_array_get_count(array)) { 1926 | return JSONFailure; 1927 | } 1928 | json_value_free(json_array_get_value(array, ix)); 1929 | to_move_bytes = (json_array_get_count(array) - 1 - ix) * sizeof(JSON_Value*); 1930 | memmove(array->items + ix, array->items + ix + 1, to_move_bytes); 1931 | array->count -= 1; 1932 | return JSONSuccess; 1933 | } 1934 | 1935 | JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) { 1936 | if (array == NULL || value == NULL || value->parent != NULL || ix >= json_array_get_count(array)) { 1937 | return JSONFailure; 1938 | } 1939 | json_value_free(json_array_get_value(array, ix)); 1940 | value->parent = json_array_get_wrapping_value(array); 1941 | array->items[ix] = value; 1942 | return JSONSuccess; 1943 | } 1944 | 1945 | JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string) { 1946 | JSON_Value *value = json_value_init_string(string); 1947 | if (value == NULL) { 1948 | return JSONFailure; 1949 | } 1950 | if (json_array_replace_value(array, i, value) != JSONSuccess) { 1951 | json_value_free(value); 1952 | return JSONFailure; 1953 | } 1954 | return JSONSuccess; 1955 | } 1956 | 1957 | JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len) { 1958 | JSON_Value *value = json_value_init_string_with_len(string, len); 1959 | if (value == NULL) { 1960 | return JSONFailure; 1961 | } 1962 | if (json_array_replace_value(array, i, value) != JSONSuccess) { 1963 | json_value_free(value); 1964 | return JSONFailure; 1965 | } 1966 | return JSONSuccess; 1967 | } 1968 | 1969 | JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number) { 1970 | JSON_Value *value = json_value_init_number(number); 1971 | if (value == NULL) { 1972 | return JSONFailure; 1973 | } 1974 | if (json_array_replace_value(array, i, value) != JSONSuccess) { 1975 | json_value_free(value); 1976 | return JSONFailure; 1977 | } 1978 | return JSONSuccess; 1979 | } 1980 | 1981 | JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean) { 1982 | JSON_Value *value = json_value_init_boolean(boolean); 1983 | if (value == NULL) { 1984 | return JSONFailure; 1985 | } 1986 | if (json_array_replace_value(array, i, value) != JSONSuccess) { 1987 | json_value_free(value); 1988 | return JSONFailure; 1989 | } 1990 | return JSONSuccess; 1991 | } 1992 | 1993 | JSON_Status json_array_replace_null(JSON_Array *array, size_t i) { 1994 | JSON_Value *value = json_value_init_null(); 1995 | if (value == NULL) { 1996 | return JSONFailure; 1997 | } 1998 | if (json_array_replace_value(array, i, value) != JSONSuccess) { 1999 | json_value_free(value); 2000 | return JSONFailure; 2001 | } 2002 | return JSONSuccess; 2003 | } 2004 | 2005 | JSON_Status json_array_clear(JSON_Array *array) { 2006 | size_t i = 0; 2007 | if (array == NULL) { 2008 | return JSONFailure; 2009 | } 2010 | for (i = 0; i < json_array_get_count(array); i++) { 2011 | json_value_free(json_array_get_value(array, i)); 2012 | } 2013 | array->count = 0; 2014 | return JSONSuccess; 2015 | } 2016 | 2017 | JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) { 2018 | if (array == NULL || value == NULL || value->parent != NULL) { 2019 | return JSONFailure; 2020 | } 2021 | return json_array_add(array, value); 2022 | } 2023 | 2024 | JSON_Status json_array_append_string(JSON_Array *array, const char *string) { 2025 | JSON_Value *value = json_value_init_string(string); 2026 | if (value == NULL) { 2027 | return JSONFailure; 2028 | } 2029 | if (json_array_append_value(array, value) != JSONSuccess) { 2030 | json_value_free(value); 2031 | return JSONFailure; 2032 | } 2033 | return JSONSuccess; 2034 | } 2035 | 2036 | JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len) { 2037 | JSON_Value *value = json_value_init_string_with_len(string, len); 2038 | if (value == NULL) { 2039 | return JSONFailure; 2040 | } 2041 | if (json_array_append_value(array, value) != JSONSuccess) { 2042 | json_value_free(value); 2043 | return JSONFailure; 2044 | } 2045 | return JSONSuccess; 2046 | } 2047 | 2048 | JSON_Status json_array_append_number(JSON_Array *array, double number) { 2049 | JSON_Value *value = json_value_init_number(number); 2050 | if (value == NULL) { 2051 | return JSONFailure; 2052 | } 2053 | if (json_array_append_value(array, value) != JSONSuccess) { 2054 | json_value_free(value); 2055 | return JSONFailure; 2056 | } 2057 | return JSONSuccess; 2058 | } 2059 | 2060 | JSON_Status json_array_append_boolean(JSON_Array *array, int boolean) { 2061 | JSON_Value *value = json_value_init_boolean(boolean); 2062 | if (value == NULL) { 2063 | return JSONFailure; 2064 | } 2065 | if (json_array_append_value(array, value) != JSONSuccess) { 2066 | json_value_free(value); 2067 | return JSONFailure; 2068 | } 2069 | return JSONSuccess; 2070 | } 2071 | 2072 | JSON_Status json_array_append_null(JSON_Array *array) { 2073 | JSON_Value *value = json_value_init_null(); 2074 | if (value == NULL) { 2075 | return JSONFailure; 2076 | } 2077 | if (json_array_append_value(array, value) != JSONSuccess) { 2078 | json_value_free(value); 2079 | return JSONFailure; 2080 | } 2081 | return JSONSuccess; 2082 | } 2083 | 2084 | JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) { 2085 | unsigned long hash = 0; 2086 | parson_bool_t found = PARSON_FALSE; 2087 | size_t cell_ix = 0; 2088 | size_t item_ix = 0; 2089 | JSON_Value *old_value = NULL; 2090 | char *key_copy = NULL; 2091 | 2092 | if (!object || !name || !value || value->parent) { 2093 | return JSONFailure; 2094 | } 2095 | hash = hash_string(name, strlen(name)); 2096 | found = PARSON_FALSE; 2097 | cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); 2098 | if (found) { 2099 | item_ix = object->cells[cell_ix]; 2100 | old_value = object->values[item_ix]; 2101 | json_value_free(old_value); 2102 | object->values[item_ix] = value; 2103 | value->parent = json_object_get_wrapping_value(object); 2104 | return JSONSuccess; 2105 | } 2106 | if (object->count >= object->item_capacity) { 2107 | JSON_Status res = json_object_grow_and_rehash(object); 2108 | if (res != JSONSuccess) { 2109 | return JSONFailure; 2110 | } 2111 | cell_ix = json_object_get_cell_ix(object, name, strlen(name), hash, &found); 2112 | } 2113 | key_copy = parson_strdup(name); 2114 | if (!key_copy) { 2115 | return JSONFailure; 2116 | } 2117 | object->names[object->count] = key_copy; 2118 | object->cells[cell_ix] = object->count; 2119 | object->values[object->count] = value; 2120 | object->cell_ixs[object->count] = cell_ix; 2121 | object->hashes[object->count] = hash; 2122 | object->count++; 2123 | value->parent = json_object_get_wrapping_value(object); 2124 | return JSONSuccess; 2125 | } 2126 | 2127 | JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string) { 2128 | JSON_Value *value = json_value_init_string(string); 2129 | JSON_Status status = json_object_set_value(object, name, value); 2130 | if (status != JSONSuccess) { 2131 | json_value_free(value); 2132 | } 2133 | return status; 2134 | } 2135 | 2136 | JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) { 2137 | JSON_Value *value = json_value_init_string_with_len(string, len); 2138 | JSON_Status status = json_object_set_value(object, name, value); 2139 | if (status != JSONSuccess) { 2140 | json_value_free(value); 2141 | } 2142 | return status; 2143 | } 2144 | 2145 | JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number) { 2146 | JSON_Value *value = json_value_init_number(number); 2147 | JSON_Status status = json_object_set_value(object, name, value); 2148 | if (status != JSONSuccess) { 2149 | json_value_free(value); 2150 | } 2151 | return status; 2152 | } 2153 | 2154 | JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean) { 2155 | JSON_Value *value = json_value_init_boolean(boolean); 2156 | JSON_Status status = json_object_set_value(object, name, value); 2157 | if (status != JSONSuccess) { 2158 | json_value_free(value); 2159 | } 2160 | return status; 2161 | } 2162 | 2163 | JSON_Status json_object_set_null(JSON_Object *object, const char *name) { 2164 | JSON_Value *value = json_value_init_null(); 2165 | JSON_Status status = json_object_set_value(object, name, value); 2166 | if (status != JSONSuccess) { 2167 | json_value_free(value); 2168 | } 2169 | return status; 2170 | } 2171 | 2172 | JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value) { 2173 | const char *dot_pos = NULL; 2174 | JSON_Value *temp_value = NULL, *new_value = NULL; 2175 | JSON_Object *temp_object = NULL, *new_object = NULL; 2176 | JSON_Status status = JSONFailure; 2177 | size_t name_len = 0; 2178 | char *name_copy = NULL; 2179 | 2180 | if (object == NULL || name == NULL || value == NULL) { 2181 | return JSONFailure; 2182 | } 2183 | dot_pos = strchr(name, '.'); 2184 | if (dot_pos == NULL) { 2185 | return json_object_set_value(object, name, value); 2186 | } 2187 | name_len = dot_pos - name; 2188 | temp_value = json_object_getn_value(object, name, name_len); 2189 | if (temp_value) { 2190 | /* Don't overwrite existing non-object (unlike json_object_set_value, but it shouldn't be changed at this point) */ 2191 | if (json_value_get_type(temp_value) != JSONObject) { 2192 | return JSONFailure; 2193 | } 2194 | temp_object = json_value_get_object(temp_value); 2195 | return json_object_dotset_value(temp_object, dot_pos + 1, value); 2196 | } 2197 | new_value = json_value_init_object(); 2198 | if (new_value == NULL) { 2199 | return JSONFailure; 2200 | } 2201 | new_object = json_value_get_object(new_value); 2202 | status = json_object_dotset_value(new_object, dot_pos + 1, value); 2203 | if (status != JSONSuccess) { 2204 | json_value_free(new_value); 2205 | return JSONFailure; 2206 | } 2207 | name_copy = parson_strndup(name, name_len); 2208 | if (!name_copy) { 2209 | json_object_dotremove_internal(new_object, dot_pos + 1, 0); 2210 | json_value_free(new_value); 2211 | return JSONFailure; 2212 | } 2213 | status = json_object_add(object, name_copy, new_value); 2214 | if (status != JSONSuccess) { 2215 | parson_free(name_copy); 2216 | json_object_dotremove_internal(new_object, dot_pos + 1, 0); 2217 | json_value_free(new_value); 2218 | return JSONFailure; 2219 | } 2220 | return JSONSuccess; 2221 | } 2222 | 2223 | JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string) { 2224 | JSON_Value *value = json_value_init_string(string); 2225 | if (value == NULL) { 2226 | return JSONFailure; 2227 | } 2228 | if (json_object_dotset_value(object, name, value) != JSONSuccess) { 2229 | json_value_free(value); 2230 | return JSONFailure; 2231 | } 2232 | return JSONSuccess; 2233 | } 2234 | 2235 | JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len) { 2236 | JSON_Value *value = json_value_init_string_with_len(string, len); 2237 | if (value == NULL) { 2238 | return JSONFailure; 2239 | } 2240 | if (json_object_dotset_value(object, name, value) != JSONSuccess) { 2241 | json_value_free(value); 2242 | return JSONFailure; 2243 | } 2244 | return JSONSuccess; 2245 | } 2246 | 2247 | JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number) { 2248 | JSON_Value *value = json_value_init_number(number); 2249 | if (value == NULL) { 2250 | return JSONFailure; 2251 | } 2252 | if (json_object_dotset_value(object, name, value) != JSONSuccess) { 2253 | json_value_free(value); 2254 | return JSONFailure; 2255 | } 2256 | return JSONSuccess; 2257 | } 2258 | 2259 | JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean) { 2260 | JSON_Value *value = json_value_init_boolean(boolean); 2261 | if (value == NULL) { 2262 | return JSONFailure; 2263 | } 2264 | if (json_object_dotset_value(object, name, value) != JSONSuccess) { 2265 | json_value_free(value); 2266 | return JSONFailure; 2267 | } 2268 | return JSONSuccess; 2269 | } 2270 | 2271 | JSON_Status json_object_dotset_null(JSON_Object *object, const char *name) { 2272 | JSON_Value *value = json_value_init_null(); 2273 | if (value == NULL) { 2274 | return JSONFailure; 2275 | } 2276 | if (json_object_dotset_value(object, name, value) != JSONSuccess) { 2277 | json_value_free(value); 2278 | return JSONFailure; 2279 | } 2280 | return JSONSuccess; 2281 | } 2282 | 2283 | JSON_Status json_object_remove(JSON_Object *object, const char *name) { 2284 | return json_object_remove_internal(object, name, PARSON_TRUE); 2285 | } 2286 | 2287 | JSON_Status json_object_dotremove(JSON_Object *object, const char *name) { 2288 | return json_object_dotremove_internal(object, name, PARSON_TRUE); 2289 | } 2290 | 2291 | JSON_Status json_object_clear(JSON_Object *object) { 2292 | size_t i = 0; 2293 | if (object == NULL) { 2294 | return JSONFailure; 2295 | } 2296 | for (i = 0; i < json_object_get_count(object); i++) { 2297 | parson_free(object->names[i]); 2298 | object->names[i] = NULL; 2299 | 2300 | json_value_free(object->values[i]); 2301 | object->values[i] = NULL; 2302 | } 2303 | object->count = 0; 2304 | for (i = 0; i < object->cell_capacity; i++) { 2305 | object->cells[i] = OBJECT_INVALID_IX; 2306 | } 2307 | return JSONSuccess; 2308 | } 2309 | 2310 | JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value) { 2311 | JSON_Value *temp_schema_value = NULL, *temp_value = NULL; 2312 | JSON_Array *schema_array = NULL, *value_array = NULL; 2313 | JSON_Object *schema_object = NULL, *value_object = NULL; 2314 | JSON_Value_Type schema_type = JSONError, value_type = JSONError; 2315 | const char *key = NULL; 2316 | size_t i = 0, count = 0; 2317 | if (schema == NULL || value == NULL) { 2318 | return JSONFailure; 2319 | } 2320 | schema_type = json_value_get_type(schema); 2321 | value_type = json_value_get_type(value); 2322 | if (schema_type != value_type && schema_type != JSONNull) { /* null represents all values */ 2323 | return JSONFailure; 2324 | } 2325 | switch (schema_type) { 2326 | case JSONArray: 2327 | schema_array = json_value_get_array(schema); 2328 | value_array = json_value_get_array(value); 2329 | count = json_array_get_count(schema_array); 2330 | if (count == 0) { 2331 | return JSONSuccess; /* Empty array allows all types */ 2332 | } 2333 | /* Get first value from array, rest is ignored */ 2334 | temp_schema_value = json_array_get_value(schema_array, 0); 2335 | for (i = 0; i < json_array_get_count(value_array); i++) { 2336 | temp_value = json_array_get_value(value_array, i); 2337 | if (json_validate(temp_schema_value, temp_value) != JSONSuccess) { 2338 | return JSONFailure; 2339 | } 2340 | } 2341 | return JSONSuccess; 2342 | case JSONObject: 2343 | schema_object = json_value_get_object(schema); 2344 | value_object = json_value_get_object(value); 2345 | count = json_object_get_count(schema_object); 2346 | if (count == 0) { 2347 | return JSONSuccess; /* Empty object allows all objects */ 2348 | } else if (json_object_get_count(value_object) < count) { 2349 | return JSONFailure; /* Tested object mustn't have less name-value pairs than schema */ 2350 | } 2351 | for (i = 0; i < count; i++) { 2352 | key = json_object_get_name(schema_object, i); 2353 | temp_schema_value = json_object_get_value(schema_object, key); 2354 | temp_value = json_object_get_value(value_object, key); 2355 | if (temp_value == NULL) { 2356 | return JSONFailure; 2357 | } 2358 | if (json_validate(temp_schema_value, temp_value) != JSONSuccess) { 2359 | return JSONFailure; 2360 | } 2361 | } 2362 | return JSONSuccess; 2363 | case JSONString: case JSONNumber: case JSONBoolean: case JSONNull: 2364 | return JSONSuccess; /* equality already tested before switch */ 2365 | case JSONError: default: 2366 | return JSONFailure; 2367 | } 2368 | } 2369 | 2370 | int json_value_equals(const JSON_Value *a, const JSON_Value *b) { 2371 | JSON_Object *a_object = NULL, *b_object = NULL; 2372 | JSON_Array *a_array = NULL, *b_array = NULL; 2373 | const JSON_String *a_string = NULL, *b_string = NULL; 2374 | const char *key = NULL; 2375 | size_t a_count = 0, b_count = 0, i = 0; 2376 | JSON_Value_Type a_type, b_type; 2377 | a_type = json_value_get_type(a); 2378 | b_type = json_value_get_type(b); 2379 | if (a_type != b_type) { 2380 | return PARSON_FALSE; 2381 | } 2382 | switch (a_type) { 2383 | case JSONArray: 2384 | a_array = json_value_get_array(a); 2385 | b_array = json_value_get_array(b); 2386 | a_count = json_array_get_count(a_array); 2387 | b_count = json_array_get_count(b_array); 2388 | if (a_count != b_count) { 2389 | return PARSON_FALSE; 2390 | } 2391 | for (i = 0; i < a_count; i++) { 2392 | if (!json_value_equals(json_array_get_value(a_array, i), 2393 | json_array_get_value(b_array, i))) { 2394 | return PARSON_FALSE; 2395 | } 2396 | } 2397 | return PARSON_TRUE; 2398 | case JSONObject: 2399 | a_object = json_value_get_object(a); 2400 | b_object = json_value_get_object(b); 2401 | a_count = json_object_get_count(a_object); 2402 | b_count = json_object_get_count(b_object); 2403 | if (a_count != b_count) { 2404 | return PARSON_FALSE; 2405 | } 2406 | for (i = 0; i < a_count; i++) { 2407 | key = json_object_get_name(a_object, i); 2408 | if (!json_value_equals(json_object_get_value(a_object, key), 2409 | json_object_get_value(b_object, key))) { 2410 | return PARSON_FALSE; 2411 | } 2412 | } 2413 | return PARSON_TRUE; 2414 | case JSONString: 2415 | a_string = json_value_get_string_desc(a); 2416 | b_string = json_value_get_string_desc(b); 2417 | if (a_string == NULL || b_string == NULL) { 2418 | return PARSON_FALSE; /* shouldn't happen */ 2419 | } 2420 | return a_string->length == b_string->length && 2421 | memcmp(a_string->chars, b_string->chars, a_string->length) == 0; 2422 | case JSONBoolean: 2423 | return json_value_get_boolean(a) == json_value_get_boolean(b); 2424 | case JSONNumber: 2425 | return fabs(json_value_get_number(a) - json_value_get_number(b)) < 0.000001; /* EPSILON */ 2426 | case JSONError: 2427 | return PARSON_TRUE; 2428 | case JSONNull: 2429 | return PARSON_TRUE; 2430 | default: 2431 | return PARSON_TRUE; 2432 | } 2433 | } 2434 | 2435 | JSON_Value_Type json_type(const JSON_Value *value) { 2436 | return json_value_get_type(value); 2437 | } 2438 | 2439 | JSON_Object * json_object (const JSON_Value *value) { 2440 | return json_value_get_object(value); 2441 | } 2442 | 2443 | JSON_Array * json_array(const JSON_Value *value) { 2444 | return json_value_get_array(value); 2445 | } 2446 | 2447 | const char * json_string(const JSON_Value *value) { 2448 | return json_value_get_string(value); 2449 | } 2450 | 2451 | size_t json_string_len(const JSON_Value *value) { 2452 | return json_value_get_string_len(value); 2453 | } 2454 | 2455 | double json_number(const JSON_Value *value) { 2456 | return json_value_get_number(value); 2457 | } 2458 | 2459 | int json_boolean(const JSON_Value *value) { 2460 | return json_value_get_boolean(value); 2461 | } 2462 | 2463 | void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun) { 2464 | parson_malloc = malloc_fun; 2465 | parson_free = free_fun; 2466 | } 2467 | 2468 | void json_set_escape_slashes(int escape_slashes) { 2469 | parson_escape_slashes = escape_slashes; 2470 | } 2471 | 2472 | void json_set_float_serialization_format(const char *format) { 2473 | if (parson_float_format) { 2474 | parson_free(parson_float_format); 2475 | parson_float_format = NULL; 2476 | } 2477 | if (!format) { 2478 | parson_float_format = NULL; 2479 | return; 2480 | } 2481 | parson_float_format = parson_strdup(format); 2482 | } 2483 | 2484 | void json_set_number_serialization_function(JSON_Number_Serialization_Function func) { 2485 | parson_number_serialization_function = func; 2486 | } 2487 | -------------------------------------------------------------------------------- /parson.h: -------------------------------------------------------------------------------- 1 | /* 2 | SPDX-License-Identifier: MIT 3 | 4 | Parson 1.5.3 (https://github.com/kgabis/parson) 5 | Copyright (c) 2012 - 2023 Krzysztof Gabis 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in 15 | all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | THE SOFTWARE. 24 | */ 25 | 26 | #ifndef parson_parson_h 27 | #define parson_parson_h 28 | 29 | #ifdef __cplusplus 30 | extern "C" 31 | { 32 | #endif 33 | #if 0 34 | } /* unconfuse xcode */ 35 | #endif 36 | 37 | #define PARSON_VERSION_MAJOR 1 38 | #define PARSON_VERSION_MINOR 5 39 | #define PARSON_VERSION_PATCH 3 40 | 41 | #define PARSON_VERSION_STRING "1.5.3" 42 | 43 | #include /* size_t */ 44 | 45 | /* Types and enums */ 46 | typedef struct json_object_t JSON_Object; 47 | typedef struct json_array_t JSON_Array; 48 | typedef struct json_value_t JSON_Value; 49 | 50 | enum json_value_type { 51 | JSONError = -1, 52 | JSONNull = 1, 53 | JSONString = 2, 54 | JSONNumber = 3, 55 | JSONObject = 4, 56 | JSONArray = 5, 57 | JSONBoolean = 6 58 | }; 59 | typedef int JSON_Value_Type; 60 | 61 | enum json_result_t { 62 | JSONSuccess = 0, 63 | JSONFailure = -1 64 | }; 65 | typedef int JSON_Status; 66 | 67 | typedef void * (*JSON_Malloc_Function)(size_t); 68 | typedef void (*JSON_Free_Function)(void *); 69 | 70 | /* A function used for serializing numbers (see json_set_number_serialization_function). 71 | If 'buf' is null then it should return number of bytes that would've been written 72 | (but not more than PARSON_NUM_BUF_SIZE). 73 | */ 74 | typedef int (*JSON_Number_Serialization_Function)(double num, char *buf); 75 | 76 | /* Call only once, before calling any other function from parson API. If not called, malloc and free 77 | from stdlib will be used for all allocations */ 78 | void json_set_allocation_functions(JSON_Malloc_Function malloc_fun, JSON_Free_Function free_fun); 79 | 80 | /* Sets if slashes should be escaped or not when serializing JSON. By default slashes are escaped. 81 | This function sets a global setting and is not thread safe. */ 82 | void json_set_escape_slashes(int escape_slashes); 83 | 84 | /* Sets float format used for serialization of numbers. 85 | Make sure it can't serialize to a string longer than PARSON_NUM_BUF_SIZE. 86 | If format is null then the default format is used. */ 87 | void json_set_float_serialization_format(const char *format); 88 | 89 | /* Sets a function that will be used for serialization of numbers. 90 | If function is null then the default serialization function is used. */ 91 | void json_set_number_serialization_function(JSON_Number_Serialization_Function fun); 92 | 93 | /* Parses first JSON value in a file, returns NULL in case of error */ 94 | JSON_Value * json_parse_file(const char *filename); 95 | 96 | /* Parses first JSON value in a file and ignores comments (/ * * / and //), 97 | returns NULL in case of error */ 98 | JSON_Value * json_parse_file_with_comments(const char *filename); 99 | 100 | /* Parses first JSON value in a string, returns NULL in case of error */ 101 | JSON_Value * json_parse_string(const char *string); 102 | 103 | /* Parses first JSON value in a string and ignores comments (/ * * / and //), 104 | returns NULL in case of error */ 105 | JSON_Value * json_parse_string_with_comments(const char *string); 106 | 107 | /* Serialization */ 108 | size_t json_serialization_size(const JSON_Value *value); /* returns 0 on fail */ 109 | JSON_Status json_serialize_to_buffer(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); 110 | JSON_Status json_serialize_to_file(const JSON_Value *value, const char *filename); 111 | char * json_serialize_to_string(const JSON_Value *value); 112 | 113 | /* Pretty serialization */ 114 | size_t json_serialization_size_pretty(const JSON_Value *value); /* returns 0 on fail */ 115 | JSON_Status json_serialize_to_buffer_pretty(const JSON_Value *value, char *buf, size_t buf_size_in_bytes); 116 | JSON_Status json_serialize_to_file_pretty(const JSON_Value *value, const char *filename); 117 | char * json_serialize_to_string_pretty(const JSON_Value *value); 118 | 119 | void json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */ 120 | 121 | /* Comparing */ 122 | int json_value_equals(const JSON_Value *a, const JSON_Value *b); 123 | 124 | /* Validation 125 | This is *NOT* JSON Schema. It validates json by checking if object have identically 126 | named fields with matching types. 127 | For example schema {"name":"", "age":0} will validate 128 | {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"}, 129 | but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}. 130 | In case of arrays, only first value in schema is checked against all values in tested array. 131 | Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays, 132 | null validates values of every type. 133 | */ 134 | JSON_Status json_validate(const JSON_Value *schema, const JSON_Value *value); 135 | 136 | /* 137 | * JSON Object 138 | */ 139 | JSON_Value * json_object_get_value (const JSON_Object *object, const char *name); 140 | const char * json_object_get_string (const JSON_Object *object, const char *name); 141 | size_t json_object_get_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */ 142 | JSON_Object * json_object_get_object (const JSON_Object *object, const char *name); 143 | JSON_Array * json_object_get_array (const JSON_Object *object, const char *name); 144 | double json_object_get_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ 145 | int json_object_get_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */ 146 | 147 | /* dotget functions enable addressing values with dot notation in nested objects, 148 | just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). 149 | Because valid names in JSON can contain dots, some values may be inaccessible 150 | this way. */ 151 | JSON_Value * json_object_dotget_value (const JSON_Object *object, const char *name); 152 | const char * json_object_dotget_string (const JSON_Object *object, const char *name); 153 | size_t json_object_dotget_string_len(const JSON_Object *object, const char *name); /* doesn't account for last null character */ 154 | JSON_Object * json_object_dotget_object (const JSON_Object *object, const char *name); 155 | JSON_Array * json_object_dotget_array (const JSON_Object *object, const char *name); 156 | double json_object_dotget_number (const JSON_Object *object, const char *name); /* returns 0 on fail */ 157 | int json_object_dotget_boolean(const JSON_Object *object, const char *name); /* returns -1 on fail */ 158 | 159 | /* Functions to get available names */ 160 | size_t json_object_get_count (const JSON_Object *object); 161 | const char * json_object_get_name (const JSON_Object *object, size_t index); 162 | JSON_Value * json_object_get_value_at(const JSON_Object *object, size_t index); 163 | JSON_Value * json_object_get_wrapping_value(const JSON_Object *object); 164 | 165 | /* Functions to check if object has a value with a specific name. Returned value is 1 if object has 166 | * a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */ 167 | int json_object_has_value (const JSON_Object *object, const char *name); 168 | int json_object_has_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type); 169 | 170 | int json_object_dothas_value (const JSON_Object *object, const char *name); 171 | int json_object_dothas_value_of_type(const JSON_Object *object, const char *name, JSON_Value_Type type); 172 | 173 | /* Creates new name-value pair or frees and replaces old value with a new one. 174 | * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */ 175 | JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value); 176 | JSON_Status json_object_set_string(JSON_Object *object, const char *name, const char *string); 177 | JSON_Status json_object_set_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */ 178 | JSON_Status json_object_set_number(JSON_Object *object, const char *name, double number); 179 | JSON_Status json_object_set_boolean(JSON_Object *object, const char *name, int boolean); 180 | JSON_Status json_object_set_null(JSON_Object *object, const char *name); 181 | 182 | /* Works like dotget functions, but creates whole hierarchy if necessary. 183 | * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */ 184 | JSON_Status json_object_dotset_value(JSON_Object *object, const char *name, JSON_Value *value); 185 | JSON_Status json_object_dotset_string(JSON_Object *object, const char *name, const char *string); 186 | JSON_Status json_object_dotset_string_with_len(JSON_Object *object, const char *name, const char *string, size_t len); /* length shouldn't include last null character */ 187 | JSON_Status json_object_dotset_number(JSON_Object *object, const char *name, double number); 188 | JSON_Status json_object_dotset_boolean(JSON_Object *object, const char *name, int boolean); 189 | JSON_Status json_object_dotset_null(JSON_Object *object, const char *name); 190 | 191 | /* Frees and removes name-value pair */ 192 | JSON_Status json_object_remove(JSON_Object *object, const char *name); 193 | 194 | /* Works like dotget function, but removes name-value pair only on exact match. */ 195 | JSON_Status json_object_dotremove(JSON_Object *object, const char *key); 196 | 197 | /* Removes all name-value pairs in object */ 198 | JSON_Status json_object_clear(JSON_Object *object); 199 | 200 | /* 201 | *JSON Array 202 | */ 203 | JSON_Value * json_array_get_value (const JSON_Array *array, size_t index); 204 | const char * json_array_get_string (const JSON_Array *array, size_t index); 205 | size_t json_array_get_string_len(const JSON_Array *array, size_t index); /* doesn't account for last null character */ 206 | JSON_Object * json_array_get_object (const JSON_Array *array, size_t index); 207 | JSON_Array * json_array_get_array (const JSON_Array *array, size_t index); 208 | double json_array_get_number (const JSON_Array *array, size_t index); /* returns 0 on fail */ 209 | int json_array_get_boolean(const JSON_Array *array, size_t index); /* returns -1 on fail */ 210 | size_t json_array_get_count (const JSON_Array *array); 211 | JSON_Value * json_array_get_wrapping_value(const JSON_Array *array); 212 | 213 | /* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist. 214 | * Order of values in array may change during execution. */ 215 | JSON_Status json_array_remove(JSON_Array *array, size_t i); 216 | 217 | /* Frees and removes from array value at given index and replaces it with given one. 218 | * Does nothing and returns JSONFailure if index doesn't exist. 219 | * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */ 220 | JSON_Status json_array_replace_value(JSON_Array *array, size_t i, JSON_Value *value); 221 | JSON_Status json_array_replace_string(JSON_Array *array, size_t i, const char* string); 222 | JSON_Status json_array_replace_string_with_len(JSON_Array *array, size_t i, const char *string, size_t len); /* length shouldn't include last null character */ 223 | JSON_Status json_array_replace_number(JSON_Array *array, size_t i, double number); 224 | JSON_Status json_array_replace_boolean(JSON_Array *array, size_t i, int boolean); 225 | JSON_Status json_array_replace_null(JSON_Array *array, size_t i); 226 | 227 | /* Frees and removes all values from array */ 228 | JSON_Status json_array_clear(JSON_Array *array); 229 | 230 | /* Appends new value at the end of array. 231 | * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */ 232 | JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value); 233 | JSON_Status json_array_append_string(JSON_Array *array, const char *string); 234 | JSON_Status json_array_append_string_with_len(JSON_Array *array, const char *string, size_t len); /* length shouldn't include last null character */ 235 | JSON_Status json_array_append_number(JSON_Array *array, double number); 236 | JSON_Status json_array_append_boolean(JSON_Array *array, int boolean); 237 | JSON_Status json_array_append_null(JSON_Array *array); 238 | 239 | /* 240 | *JSON Value 241 | */ 242 | JSON_Value * json_value_init_object (void); 243 | JSON_Value * json_value_init_array (void); 244 | JSON_Value * json_value_init_string (const char *string); /* copies passed string */ 245 | JSON_Value * json_value_init_string_with_len(const char *string, size_t length); /* copies passed string, length shouldn't include last null character */ 246 | JSON_Value * json_value_init_number (double number); 247 | JSON_Value * json_value_init_boolean(int boolean); 248 | JSON_Value * json_value_init_null (void); 249 | JSON_Value * json_value_deep_copy (const JSON_Value *value); 250 | void json_value_free (JSON_Value *value); 251 | 252 | JSON_Value_Type json_value_get_type (const JSON_Value *value); 253 | JSON_Object * json_value_get_object (const JSON_Value *value); 254 | JSON_Array * json_value_get_array (const JSON_Value *value); 255 | const char * json_value_get_string (const JSON_Value *value); 256 | size_t json_value_get_string_len(const JSON_Value *value); /* doesn't account for last null character */ 257 | double json_value_get_number (const JSON_Value *value); 258 | int json_value_get_boolean(const JSON_Value *value); 259 | JSON_Value * json_value_get_parent (const JSON_Value *value); 260 | 261 | /* Same as above, but shorter */ 262 | JSON_Value_Type json_type (const JSON_Value *value); 263 | JSON_Object * json_object (const JSON_Value *value); 264 | JSON_Array * json_array (const JSON_Value *value); 265 | const char * json_string (const JSON_Value *value); 266 | size_t json_string_len(const JSON_Value *value); /* doesn't account for last null character */ 267 | double json_number (const JSON_Value *value); 268 | int json_boolean(const JSON_Value *value); 269 | 270 | #ifdef __cplusplus 271 | } 272 | #endif 273 | 274 | #endif 275 | -------------------------------------------------------------------------------- /sha1.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha1.c 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Implementation of the SHA1 hashing algorithm. 7 | Algorithm specification can be found here: 8 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf 9 | This implementation uses little endian byte order. 10 | *********************************************************************/ 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | #include 15 | #include "sha1.h" 16 | 17 | /****************************** MACROS ******************************/ 18 | #define ROTLEFT(a, b) ((a << b) | (a >> (32 - b))) 19 | 20 | /*********************** FUNCTION DEFINITIONS ***********************/ 21 | void sha1_transform(SHA1_CTX *ctx, const uint8_t data[]) 22 | { 23 | uint32_t a, b, c, d, e, i, j, t, m[80]; 24 | 25 | for (i = 0, j = 0; i < 16; ++i, j += 4) 26 | m[i] = (data[j] << 24) + (data[j + 1] << 16) + (data[j + 2] << 8) + (data[j + 3]); 27 | for ( ; i < 80; ++i) { 28 | m[i] = (m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16]); 29 | m[i] = (m[i] << 1) | (m[i] >> 31); 30 | } 31 | 32 | a = ctx->state[0]; 33 | b = ctx->state[1]; 34 | c = ctx->state[2]; 35 | d = ctx->state[3]; 36 | e = ctx->state[4]; 37 | 38 | for (i = 0; i < 20; ++i) { 39 | t = ROTLEFT(a, 5) + ((b & c) ^ (~b & d)) + e + ctx->k[0] + m[i]; 40 | e = d; 41 | d = c; 42 | c = ROTLEFT(b, 30); 43 | b = a; 44 | a = t; 45 | } 46 | for ( ; i < 40; ++i) { 47 | t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[1] + m[i]; 48 | e = d; 49 | d = c; 50 | c = ROTLEFT(b, 30); 51 | b = a; 52 | a = t; 53 | } 54 | for ( ; i < 60; ++i) { 55 | t = ROTLEFT(a, 5) + ((b & c) ^ (b & d) ^ (c & d)) + e + ctx->k[2] + m[i]; 56 | e = d; 57 | d = c; 58 | c = ROTLEFT(b, 30); 59 | b = a; 60 | a = t; 61 | } 62 | for ( ; i < 80; ++i) { 63 | t = ROTLEFT(a, 5) + (b ^ c ^ d) + e + ctx->k[3] + m[i]; 64 | e = d; 65 | d = c; 66 | c = ROTLEFT(b, 30); 67 | b = a; 68 | a = t; 69 | } 70 | 71 | ctx->state[0] += a; 72 | ctx->state[1] += b; 73 | ctx->state[2] += c; 74 | ctx->state[3] += d; 75 | ctx->state[4] += e; 76 | } 77 | 78 | void sha1_init(SHA1_CTX *ctx) 79 | { 80 | ctx->datalen = 0; 81 | ctx->bitlen = 0; 82 | ctx->state[0] = 0x67452301; 83 | ctx->state[1] = 0xEFCDAB89; 84 | ctx->state[2] = 0x98BADCFE; 85 | ctx->state[3] = 0x10325476; 86 | ctx->state[4] = 0xc3d2e1f0; 87 | ctx->k[0] = 0x5a827999; 88 | ctx->k[1] = 0x6ed9eba1; 89 | ctx->k[2] = 0x8f1bbcdc; 90 | ctx->k[3] = 0xca62c1d6; 91 | } 92 | 93 | void sha1_update(SHA1_CTX *ctx, const uint8_t data[], size_t len) 94 | { 95 | size_t i; 96 | 97 | for (i = 0; i < len; ++i) { 98 | ctx->data[ctx->datalen] = data[i]; 99 | ctx->datalen++; 100 | if (ctx->datalen == 64) { 101 | sha1_transform(ctx, ctx->data); 102 | ctx->bitlen += 512; 103 | ctx->datalen = 0; 104 | } 105 | } 106 | } 107 | 108 | void sha1_final(SHA1_CTX *ctx, uint8_t hash[]) 109 | { 110 | uint32_t i; 111 | 112 | i = ctx->datalen; 113 | 114 | // Pad whatever data is left in the buffer. 115 | if (ctx->datalen < 56) { 116 | ctx->data[i++] = 0x80; 117 | while (i < 56) 118 | ctx->data[i++] = 0x00; 119 | } 120 | else { 121 | ctx->data[i++] = 0x80; 122 | while (i < 64) 123 | ctx->data[i++] = 0x00; 124 | sha1_transform(ctx, ctx->data); 125 | memset(ctx->data, 0, 56); 126 | } 127 | 128 | // Append to the padding the total message's length in bits and transform. 129 | ctx->bitlen += ctx->datalen * 8; 130 | ctx->data[63] = ctx->bitlen; 131 | ctx->data[62] = ctx->bitlen >> 8; 132 | ctx->data[61] = ctx->bitlen >> 16; 133 | ctx->data[60] = ctx->bitlen >> 24; 134 | ctx->data[59] = ctx->bitlen >> 32; 135 | ctx->data[58] = ctx->bitlen >> 40; 136 | ctx->data[57] = ctx->bitlen >> 48; 137 | ctx->data[56] = ctx->bitlen >> 56; 138 | sha1_transform(ctx, ctx->data); 139 | 140 | // Since this implementation uses little endian byte ordering and MD uses big endian, 141 | // reverse all the bytes when copying the final state to the output hash. 142 | for (i = 0; i < 4; ++i) { 143 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 144 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 145 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 146 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 147 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /sha1.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha1.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA1_H 10 | #define SHA1_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | #include 15 | 16 | /****************************** MACROS ******************************/ 17 | #define SHA1_BLOCK_SIZE 20 // SHA1 outputs a 20 byte digest 18 | 19 | /**************************** DATA TYPES ****************************/ 20 | typedef struct { 21 | uint8_t data[64]; 22 | uint32_t datalen; 23 | unsigned long long bitlen; 24 | uint32_t state[5]; 25 | uint32_t k[4]; 26 | } SHA1_CTX; 27 | 28 | /*********************** FUNCTION DECLARATIONS **********************/ 29 | void sha1_init(SHA1_CTX *ctx); 30 | void sha1_update(SHA1_CTX *ctx, const uint8_t data[], size_t len); 31 | void sha1_final(SHA1_CTX *ctx, uint8_t hash[]); 32 | 33 | #endif // SHA1_H 34 | -------------------------------------------------------------------------------- /sha256.c: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.c 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Implementation of the SHA-256 hashing algorithm. 7 | SHA-256 is one of the three algorithms in the SHA2 8 | specification. The others, SHA-384 and SHA-512, are not 9 | offered in this implementation. 10 | Algorithm specification can be found here: 11 | * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2withchangenotice.pdf 12 | This implementation uses little endian byte order. 13 | *********************************************************************/ 14 | 15 | /*************************** HEADER FILES ***************************/ 16 | #include 17 | #include 18 | #include "sha256.h" 19 | 20 | /****************************** MACROS ******************************/ 21 | #define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32-(b)))) 22 | #define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32-(b)))) 23 | 24 | #define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z))) 25 | #define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) 26 | #define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22)) 27 | #define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25)) 28 | #define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3)) 29 | #define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10)) 30 | 31 | /**************************** VARIABLES *****************************/ 32 | static const uint32_t k[64] = { 33 | 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, 34 | 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, 35 | 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, 36 | 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, 37 | 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, 38 | 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, 39 | 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, 40 | 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 41 | }; 42 | 43 | /*********************** FUNCTION DEFINITIONS ***********************/ 44 | void sha256_transform(SHA256_CTX *ctx, const uint8_t data[]) 45 | { 46 | uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64]; 47 | 48 | for (i = 0, j = 0; i < 16; ++i, j += 4) 49 | m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]); 50 | for ( ; i < 64; ++i) 51 | m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; 52 | 53 | a = ctx->state[0]; 54 | b = ctx->state[1]; 55 | c = ctx->state[2]; 56 | d = ctx->state[3]; 57 | e = ctx->state[4]; 58 | f = ctx->state[5]; 59 | g = ctx->state[6]; 60 | h = ctx->state[7]; 61 | 62 | for (i = 0; i < 64; ++i) { 63 | t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i]; 64 | t2 = EP0(a) + MAJ(a,b,c); 65 | h = g; 66 | g = f; 67 | f = e; 68 | e = d + t1; 69 | d = c; 70 | c = b; 71 | b = a; 72 | a = t1 + t2; 73 | } 74 | 75 | ctx->state[0] += a; 76 | ctx->state[1] += b; 77 | ctx->state[2] += c; 78 | ctx->state[3] += d; 79 | ctx->state[4] += e; 80 | ctx->state[5] += f; 81 | ctx->state[6] += g; 82 | ctx->state[7] += h; 83 | } 84 | 85 | void sha256_init(SHA256_CTX *ctx) 86 | { 87 | ctx->datalen = 0; 88 | ctx->bitlen = 0; 89 | ctx->state[0] = 0x6a09e667; 90 | ctx->state[1] = 0xbb67ae85; 91 | ctx->state[2] = 0x3c6ef372; 92 | ctx->state[3] = 0xa54ff53a; 93 | ctx->state[4] = 0x510e527f; 94 | ctx->state[5] = 0x9b05688c; 95 | ctx->state[6] = 0x1f83d9ab; 96 | ctx->state[7] = 0x5be0cd19; 97 | } 98 | 99 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len) 100 | { 101 | uint32_t i; 102 | 103 | for (i = 0; i < len; ++i) { 104 | ctx->data[ctx->datalen] = data[i]; 105 | ctx->datalen++; 106 | if (ctx->datalen == 64) { 107 | sha256_transform(ctx, ctx->data); 108 | ctx->bitlen += 512; 109 | ctx->datalen = 0; 110 | } 111 | } 112 | } 113 | 114 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]) 115 | { 116 | uint32_t i; 117 | 118 | i = ctx->datalen; 119 | 120 | // Pad whatever data is left in the buffer. 121 | if (ctx->datalen < 56) { 122 | ctx->data[i++] = 0x80; 123 | while (i < 56) 124 | ctx->data[i++] = 0x00; 125 | } 126 | else { 127 | ctx->data[i++] = 0x80; 128 | while (i < 64) 129 | ctx->data[i++] = 0x00; 130 | sha256_transform(ctx, ctx->data); 131 | memset(ctx->data, 0, 56); 132 | } 133 | 134 | // Append to the padding the total message's length in bits and transform. 135 | ctx->bitlen += ctx->datalen * 8; 136 | ctx->data[63] = ctx->bitlen; 137 | ctx->data[62] = ctx->bitlen >> 8; 138 | ctx->data[61] = ctx->bitlen >> 16; 139 | ctx->data[60] = ctx->bitlen >> 24; 140 | ctx->data[59] = ctx->bitlen >> 32; 141 | ctx->data[58] = ctx->bitlen >> 40; 142 | ctx->data[57] = ctx->bitlen >> 48; 143 | ctx->data[56] = ctx->bitlen >> 56; 144 | sha256_transform(ctx, ctx->data); 145 | 146 | // Since this implementation uses little endian byte ordering and SHA uses big endian, 147 | // reverse all the bytes when copying the final state to the output hash. 148 | for (i = 0; i < 4; ++i) { 149 | hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff; 150 | hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff; 151 | hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff; 152 | hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff; 153 | hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff; 154 | hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff; 155 | hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff; 156 | hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff; 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /sha256.h: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * Filename: sha256.h 3 | * Author: Brad Conte (brad AT bradconte.com) 4 | * Copyright: 5 | * Disclaimer: This code is presented "as is" without any guarantees. 6 | * Details: Defines the API for the corresponding SHA1 implementation. 7 | *********************************************************************/ 8 | 9 | #ifndef SHA256_H 10 | #define SHA256_H 11 | 12 | /*************************** HEADER FILES ***************************/ 13 | #include 14 | #include 15 | 16 | /****************************** MACROS ******************************/ 17 | #define SHA256_BLOCK_SIZE 32 // SHA256 outputs a 32 byte digest 18 | 19 | /**************************** DATA TYPES ****************************/ 20 | typedef struct { 21 | uint8_t data[64]; 22 | uint32_t datalen; 23 | unsigned long long bitlen; 24 | uint32_t state[8]; 25 | } SHA256_CTX; 26 | 27 | /*********************** FUNCTION DECLARATIONS **********************/ 28 | void sha256_init(SHA256_CTX *ctx); 29 | void sha256_update(SHA256_CTX *ctx, const uint8_t data[], size_t len); 30 | void sha256_final(SHA256_CTX *ctx, uint8_t hash[]); 31 | 32 | #endif // SHA256_H 33 | --------------------------------------------------------------------------------