├── .restyled.yaml ├── test ├── cases.mpac ├── utils.h ├── profile.c ├── utils.c ├── tests.h ├── test.c ├── buf.h └── buf.c ├── examples ├── cmp_data.dat ├── example1.c └── example2.c ├── CMakeLists.txt ├── .travis.yml ├── .github └── workflows │ └── ci.yml ├── TODO.md ├── .gitignore ├── LICENSE ├── CODE_OF_CONDUCT.md ├── Makefile ├── README.md ├── cmp.h └── cmp.c /.restyled.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | exclude: 3 | - "**/*.c" 4 | - "**/*.h" 5 | -------------------------------------------------------------------------------- /test/cases.mpac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camgunz/cmp/HEAD/test/cases.mpac -------------------------------------------------------------------------------- /examples/cmp_data.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/camgunz/cmp/HEAD/examples/cmp_data.dat -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Edit following two lines to set component requirements (see docs) 2 | set(COMPONENT_SRCS "cmp.c" ) 3 | set(COMPONENT_ADD_INCLUDEDIRS ".") 4 | register_component() 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | sudo: false 3 | language: c 4 | compiler: gcc 5 | 6 | addons: 7 | apt: 8 | packages: 9 | - build-essential 10 | - python-dev 11 | - libffi-dev 12 | - libssl-dev 13 | - libcmocka-dev 14 | - clang 15 | 16 | before_install: 17 | - pip install --user cpp-coveralls 18 | 19 | script: 20 | - make test 21 | 22 | after_success: 23 | - coveralls --gcov-options '\-lp' -i cmp.c -i cmp.h -e test/utils.c -e test/buf.c -e test/test.c -e test/buf.h -e test/utils.h -e examples/example1.c -e examples/example2.c 24 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: ci 2 | 3 | on: 4 | pull_request: 5 | branches: [master] 6 | 7 | jobs: 8 | build-linux: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Install dependencies 13 | run: sudo apt-get install -y --no-install-recommends libcmocka-dev 14 | - name: Compile as C++ 15 | run: g++ -fsyntax-only -xc++ cmp.c 16 | - name: Build library 17 | run: make -j4 18 | - name: Build test programs 19 | run: make testprogs 20 | - name: Run tests 21 | run: make test 22 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # To Do 2 | 3 | - Work on fixing double-copy issue 4 | - Essentially everything is written to a `cmp_object_t` before it's written 5 | out to the caller, which is inefficient. The reasoning for this is to not 6 | pollute the caller's environment should an error occur, but in practice 7 | it's probably better to say, "you can't trust the contents of output 8 | arguments you pass to CMP if the call fails". 9 | 10 | - Build real docs 11 | - Probably still just a Markdown file, but still, things have gotten complex 12 | enough that `cmp.h` and `README.md` don't really cover it anymore. 13 | 14 | - Prevent users from using extended types < 0 (reserved by MessagePack) 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | *.ko 4 | *.obj 5 | *.elf 6 | 7 | # Libraries 8 | *.lib 9 | *.a 10 | 11 | # Shared objects (inc. Windows DLLs) 12 | *.dll 13 | *.so 14 | *.so.* 15 | *.dylib 16 | 17 | # Executables 18 | *.exe 19 | *.out 20 | *.app 21 | *.i*86 22 | *.x86_64 23 | *.hex 24 | 25 | # Vim swap files 26 | *.swp 27 | *.swo 28 | 29 | # Coverage files 30 | *.gcda 31 | *.gcno 32 | coverage/ 33 | 34 | # Profiling files 35 | *.prof 36 | 37 | # Testing executable 38 | test/test-cmp 39 | cmptest 40 | cmptest2 41 | cmpaddrtest 42 | cmpmemtest 43 | cmpnofloattest 44 | cmpprof 45 | cmpubtest 46 | 47 | # Example executables 48 | examples/example1 49 | examples/example2 50 | example1 51 | example2 52 | 53 | # Test data 54 | cmp_data.dat 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Charles Gunyon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /test/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef UTILS_H__ 26 | #define UTILS_H__ 27 | 28 | void error_and_exit(const char *msg); 29 | 30 | #ifdef __GNUC__ 31 | void errorf_and_exit(const char *msg, ...) 32 | __attribute__ ((format (printf, 1, 2))); 33 | #else 34 | void errorf_and_exit(const char *msg, ...); 35 | #endif 36 | 37 | char* _strdup(const char *s); 38 | 39 | #ifndef strdup 40 | #define strdup _strdup 41 | #endif 42 | 43 | #ifndef MAX 44 | #define MAX(a,b) ((a)>(b)?(a):(b)) 45 | #endif 46 | 47 | #ifndef MIN 48 | #define MIN(a,b) ((a)<(b)?(a):(b)) 49 | #endif 50 | 51 | #endif 52 | 53 | -------------------------------------------------------------------------------- /test/profile.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | 27 | #include "tests.h" 28 | 29 | int main(void) { 30 | test_msgpack(NULL); 31 | test_fixedint(NULL); 32 | test_numbers(NULL); 33 | test_nil(NULL); 34 | test_boolean(NULL); 35 | test_bin(NULL); 36 | test_string(NULL); 37 | test_array(NULL); 38 | test_map(NULL); 39 | test_ext(NULL); 40 | test_obj(NULL); 41 | 42 | #ifndef CMP_NO_FLOAT 43 | test_float_flip(NULL); 44 | #endif 45 | 46 | test_skipping(NULL); 47 | test_deprecated_limited_skipping(NULL); 48 | test_errors(NULL); 49 | test_version(NULL); 50 | test_conversions(NULL); 51 | 52 | return EXIT_SUCCESS; 53 | } 54 | 55 | /* vi: set et ts=2 sw=2: */ 56 | -------------------------------------------------------------------------------- /test/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "utils.h" 33 | 34 | void error_and_exit(const char *msg) { 35 | fprintf(stderr, "%s\n", msg); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | void errorf_and_exit(const char *msg, ...) { 40 | va_list args; 41 | 42 | va_start(args, msg); 43 | vfprintf(stderr, msg, args); 44 | va_end(args); 45 | 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | char* _strdup(const char *s) { 50 | char *out = calloc(strlen(s) + 1, sizeof(char)); 51 | 52 | strcpy(out, s); 53 | 54 | return out; 55 | } 56 | 57 | /* vi: set et ts=2 sw=2: */ 58 | 59 | -------------------------------------------------------------------------------- /test/tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | void test_msgpack(void **state); 26 | void test_fixedint(void **state); 27 | void test_numbers(void **state); 28 | void test_conversions(void **state); 29 | void test_nil(void **state); 30 | void test_boolean(void **state); 31 | void test_bin(void **state); 32 | void test_string(void **state); 33 | void test_array(void **state); 34 | void test_map(void **state); 35 | void test_ext(void **state); 36 | void test_obj(void **state); 37 | #ifndef CMP_NO_FLOAT 38 | void test_float_flip(void **state); 39 | #endif 40 | void test_skipping(void **state); 41 | void test_skip_bytes(void **state); 42 | void test_deprecated_limited_skipping(void **state); 43 | void test_errors(void **state); 44 | void test_version(void **state); 45 | 46 | /* vi: set et ts=2 sw=2: */ 47 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include 31 | 32 | #include "tests.h" 33 | 34 | int main(void) { 35 | /* Use the old CMocka API because Travis' latest Ubuntu is Trusty */ 36 | const UnitTest tests[18] = { 37 | unit_test(test_msgpack), 38 | unit_test(test_fixedint), 39 | unit_test(test_numbers), 40 | unit_test(test_nil), 41 | unit_test(test_boolean), 42 | unit_test(test_bin), 43 | unit_test(test_string), 44 | unit_test(test_array), 45 | unit_test(test_map), 46 | unit_test(test_ext), 47 | unit_test(test_obj), 48 | 49 | #ifndef CMP_NO_FLOAT 50 | unit_test(test_float_flip), 51 | #endif 52 | 53 | unit_test(test_skipping), 54 | unit_test(test_skip_bytes), 55 | unit_test(test_deprecated_limited_skipping), 56 | unit_test(test_errors), 57 | unit_test(test_version), 58 | unit_test(test_conversions), 59 | }; 60 | 61 | if (run_tests(tests)) { 62 | return EXIT_FAILURE; 63 | } 64 | 65 | return EXIT_SUCCESS; 66 | } 67 | 68 | /* vi: set et ts=2 sw=2: */ 69 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This Code of Conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at charles.gunyon@gmail.com. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident. 43 | 44 | 45 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 46 | version 1.3.0, available at 47 | [http://contributor-covenant.org/version/1/3/0/][version] 48 | 49 | [homepage]: http://contributor-covenant.org 50 | [version]: http://contributor-covenant.org/version/1/3/0/ 51 | -------------------------------------------------------------------------------- /examples/example1.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "cmp.h" 29 | 30 | static bool read_bytes(void *data, size_t sz, FILE *fh) { 31 | return fread(data, sizeof(uint8_t), sz, fh) == (sz * sizeof(uint8_t)); 32 | } 33 | 34 | static bool file_reader(cmp_ctx_t *ctx, void *data, size_t limit) { 35 | return read_bytes(data, limit, (FILE *)ctx->buf); 36 | } 37 | 38 | static bool file_skipper(cmp_ctx_t *ctx, size_t count) { 39 | return fseek((FILE *)ctx->buf, count, SEEK_CUR); 40 | } 41 | 42 | static size_t file_writer(cmp_ctx_t *ctx, const void *data, size_t count) { 43 | return fwrite(data, sizeof(uint8_t), count, (FILE *)ctx->buf); 44 | } 45 | 46 | static void error_and_exit(const char *msg) { 47 | fprintf(stderr, "%s\n\n", msg); 48 | exit(EXIT_FAILURE); 49 | } 50 | 51 | int main(void) { 52 | FILE *fh = NULL; 53 | cmp_ctx_t cmp = {0}; 54 | uint32_t array_size = 0; 55 | uint32_t str_size = 0; 56 | char hello[6] = {0}; 57 | char message_pack[12] = {0}; 58 | 59 | fh = fopen("cmp_data.dat", "w+b"); 60 | 61 | if (fh == NULL) { 62 | error_and_exit("Error opening data.dat"); 63 | } 64 | 65 | cmp_init(&cmp, fh, file_reader, file_skipper, file_writer); 66 | 67 | if (!cmp_write_array(&cmp, 2)) { 68 | error_and_exit(cmp_strerror(&cmp)); 69 | } 70 | 71 | if (!cmp_write_str(&cmp, "Hello", 5)) { 72 | error_and_exit(cmp_strerror(&cmp)); 73 | } 74 | 75 | if (!cmp_write_str(&cmp, "MessagePack", 11)) { 76 | error_and_exit(cmp_strerror(&cmp)); 77 | } 78 | 79 | rewind(fh); 80 | 81 | if (!cmp_read_array(&cmp, &array_size)) { 82 | error_and_exit(cmp_strerror(&cmp)); 83 | } 84 | 85 | /* You can read the str byte size and then read str bytes... */ 86 | 87 | if (!cmp_read_str_size(&cmp, &str_size)) { 88 | error_and_exit(cmp_strerror(&cmp)); 89 | } 90 | 91 | if (str_size > (sizeof(hello) - 1)) { 92 | error_and_exit("Packed 'hello' length too long\n"); 93 | } 94 | 95 | if (!read_bytes(hello, str_size, fh)) { 96 | error_and_exit(cmp_strerror(&cmp)); 97 | } 98 | 99 | /* 100 | * ...or you can set the maximum number of bytes to read and do it all in 101 | * one call 102 | */ 103 | 104 | str_size = sizeof(message_pack); 105 | if (!cmp_read_str(&cmp, message_pack, &str_size)) { 106 | error_and_exit(cmp_strerror(&cmp)); 107 | } 108 | 109 | printf("Array Length: %u.\n", array_size); 110 | printf("[\"%s\", \"%s\"]\n", hello, message_pack); 111 | 112 | fclose(fh); 113 | 114 | return EXIT_SUCCESS; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC ?= gcc 2 | CLANG ?= clang 3 | 4 | EXTRA_CFLAGS ?= -Werror -Wall -Wextra -funsigned-char -fwrapv -Wconversion \ 5 | -Wno-sign-conversion -Wmissing-format-attribute \ 6 | -Wpointer-arith -Wformat-nonliteral -Winit-self \ 7 | -Wwrite-strings -Wshadow -Wenum-compare -Wempty-body \ 8 | -Wparentheses -Wcast-align -Wstrict-aliasing --pedantic-errors 9 | CMPCFLAGS ?= -std=c89 -Wno-c99-extensions 10 | TESTCFLAGS ?= -std=c99 -Wno-error=deprecated-declarations \ 11 | -Wno-deprecated-declarations -O0 12 | NOFPUTESTCFLAGS ?= $(TESTCFLAGS) -DCMP_NO_FLOAT 13 | 14 | ADDRCFLAGS ?= -fsanitize=address 15 | MEMCFLAGS ?= -fsanitize=memory -fno-omit-frame-pointer \ 16 | -fno-optimize-sibling-calls 17 | UBCFLAGS ?= -fsanitize=undefined,nullability,local-bounds,float-divide-by-zero,integer 18 | 19 | .PHONY: all clean test coverage 20 | 21 | all: cmpunittest example1 example2 22 | 23 | profile: cmpprof 24 | @env LD_PRELOAD=/usr/lib/libprofiler.so CPUPROFILE=cmp.prof \ 25 | CPUPROFILE_FREQUENCY=1000 ./cmpprof 26 | @pprof --web ./cmpprof cmp.prof 27 | 28 | test: addrtest memtest nofloattest ubtest unittest 29 | 30 | testprogs: cmpaddrtest cmpmemtest cmpnofloattest cmpubtest cmpunittest 31 | 32 | addrtest: cmpaddrtest 33 | @./cmpaddrtest 34 | 35 | memtest: cmpmemtest 36 | @./cmpmemtest 37 | 38 | nofloattest: cmpnofloattest 39 | @./cmpnofloattest 40 | @rm -f *.gcno *.gcda *.info 41 | 42 | ubtest: cmpubtest 43 | @./cmpubtest 44 | 45 | unittest: cmpunittest 46 | @./cmpunittest 47 | 48 | cmp.o: cmp.c 49 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CMPCFLAGS) \ 50 | -fprofile-arcs -ftest-coverage -g -I. -c cmp.c 51 | 52 | cmpprof: cmp.o 53 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(TESTCFLAGS) $(LDFLAGS) \ 54 | -fprofile-arcs -I. \ 55 | -o cmpprof cmp.o test/profile.c test/tests.c test/buf.c test/utils.c \ 56 | -lcmocka -lprofiler 57 | 58 | cmpunittest: cmp.o 59 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(TESTCFLAGS) $(LDFLAGS) \ 60 | -fprofile-arcs -ftest-coverage -g -I. \ 61 | -o cmpunittest cmp.o test/test.c test/tests.c test/buf.c test/utils.c \ 62 | -lcmocka 63 | 64 | cmpnofloattest: cmp.o 65 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(NOFPUTESTCFLAGS) $(LDFLAGS) \ 66 | -fprofile-arcs -ftest-coverage -g -I. \ 67 | -o cmpnofloattest cmp.o test/test.c test/tests.c test/buf.c \ 68 | test/utils.c \ 69 | -lcmocka 70 | 71 | clangcmp.o: cmp.c 72 | $(CLANG) $(CFLAGS) $(EXTRA_CFLAGS) $(CMPCFLAGS) \ 73 | -fprofile-arcs -ftest-coverage -g -I. -c cmp.c -o clangcmp.o 74 | 75 | cmpaddrtest: clangcmp.o clean 76 | $(CLANG) $(CFLAGS) $(EXTRA_CFLAGS) $(TESTCFLAGS) $(ADDRCFLAGS) $(LDFLAGS) \ 77 | -I. -o cmpaddrtest \ 78 | cmp.c test/test.c test/tests.c test/buf.c test/utils.c \ 79 | -lcmocka 80 | 81 | cmpmemtest: clangcmp.o clean 82 | $(CLANG) $(CFLAGS) $(EXTRA_CFLAGS) $(TESTCFLAGS) $(MEMCFLAGS) $(LDFLAGS) \ 83 | -I. -o cmpmemtest \ 84 | cmp.c test/test.c test/tests.c test/buf.c test/utils.c \ 85 | -lcmocka 86 | 87 | cmpubtest: clangcmp.o clean 88 | $(CLANG) $(CFLAGS) $(EXTRA_CFLAGS) $(TESTCFLAGS) $(UBCFLAGS) $(LDFLAGS) \ 89 | -I. -o cmpubtest \ 90 | cmp.c test/test.c test/tests.c test/buf.c test/utils.c \ 91 | -lcmocka 92 | 93 | example1: 94 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) --std=c89 -O3 -I. -o example1 \ 95 | cmp.c examples/example1.c 96 | 97 | example2: 98 | $(CC) $(CFLAGS) $(EXTRA_CFLAGS) --std=c89 -O3 -I. -o example2 \ 99 | cmp.c examples/example2.c 100 | 101 | coverage: 102 | @rm -f base_coverage.info test_coverage.info total_coverage.info 103 | @rm -rf coverage 104 | @lcov -q -c -i -d . -o base_coverage.info 105 | @lcov -q -c -d . -o test_coverage.info 106 | @lcov -q -a base_coverage.info -a test_coverage.info -o total_coverage.info 107 | @lcov -q --summary total_coverage.info 108 | @mkdir coverage 109 | @genhtml -q -o coverage total_coverage.info 110 | 111 | clean: 112 | @rm -f cmp.prof 113 | @rm -f cmpunittest 114 | @rm -f cmpaddrtest 115 | @rm -f cmpmemtest 116 | @rm -f cmpubtest 117 | @rm -f cmpnofloattest 118 | @rm -f cmpprof 119 | @rm -f example1 120 | @rm -f example2 121 | @rm -f *.o 122 | @rm -f *.gcno *.gcda *.info 123 | @rm -f cmp_data.dat 124 | -------------------------------------------------------------------------------- /test/buf.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef M_BUF_H__ 26 | #define M_BUF_H__ 27 | 28 | typedef struct buf_s { 29 | size_t capacity; 30 | size_t size; 31 | size_t cursor; 32 | char *data; 33 | } buf_t; 34 | 35 | buf_t* M_BufferNew(void); 36 | buf_t* M_BufferNewWithCapacity(size_t capacity); 37 | void M_BufferInit(buf_t *buf); 38 | void M_BufferInitWithCapacity(buf_t *buf, size_t capacity); 39 | 40 | size_t M_BufferGetCapacity(const buf_t *buf); 41 | size_t M_BufferGetSize(const buf_t *buf); 42 | size_t M_BufferGetCursor(const buf_t *buf); 43 | char* M_BufferGetData(const buf_t *buf); 44 | char* M_BufferGetDataAtCursor(const buf_t *buf); 45 | 46 | void M_BufferEnsureCapacity(buf_t *buf, size_t capacity); 47 | void M_BufferEnsureTotalCapacity(buf_t *buf, size_t capacity); 48 | 49 | void M_BufferCopy(buf_t *dst, const buf_t *src); 50 | void M_BufferCursorCopy(buf_t *dst, const buf_t *src); 51 | bool M_BufferMove(buf_t *buf, size_t dpos, size_t spos, size_t count); 52 | 53 | void M_BufferSetData(buf_t *buf, const void *data, size_t size); 54 | void M_BufferSetString(buf_t *buf, const char *data, size_t length); 55 | bool M_BufferSetFile(buf_t *buf, const char *filename); 56 | 57 | bool M_BufferSeek(buf_t *buf, size_t pos); 58 | bool M_BufferSeekBackward(buf_t *buf, size_t count); 59 | bool M_BufferSeekForward(buf_t *buf, size_t count); 60 | 61 | uint8_t M_BufferPeek(const buf_t *buf); 62 | 63 | void M_BufferWrite(buf_t *buf, const void *data, size_t size); 64 | void M_BufferWriteBool(buf_t *buf, bool b); 65 | void M_BufferWriteBools(buf_t *buf, const bool *bools, size_t count); 66 | void M_BufferWriteChar(buf_t *buf, char c); 67 | void M_BufferWriteChars(buf_t *buf, const char *chars, size_t count); 68 | void M_BufferWriteUChar(buf_t *buf, unsigned char c); 69 | void M_BufferWriteUChars(buf_t *buf, const unsigned char *uchars, 70 | size_t count); 71 | void M_BufferWriteShort(buf_t *buf, short s); 72 | void M_BufferWriteShorts(buf_t *buf, const short *shorts, size_t count); 73 | void M_BufferWriteUShort(buf_t *buf, unsigned short s); 74 | void M_BufferWriteUShorts(buf_t *buf, const unsigned short *ushorts, 75 | size_t count); 76 | void M_BufferWriteInt(buf_t *buf, int i); 77 | void M_BufferWriteInts(buf_t *buf, const int *ints, size_t count); 78 | void M_BufferWriteUInt(buf_t *buf, unsigned int i); 79 | void M_BufferWriteUInts(buf_t *buf, const unsigned int *ints, 80 | size_t count); 81 | void M_BufferWriteLong(buf_t *buf, int64_t l); 82 | void M_BufferWriteLongs(buf_t *buf, const int64_t *longs, size_t count); 83 | void M_BufferWriteULong(buf_t *buf, uint64_t l); 84 | void M_BufferWriteULongs(buf_t *buf, const uint64_t *longs, size_t count); 85 | #ifndef CMP_NO_FLOAT 86 | void M_BufferWriteFloat(buf_t *buf, float f); 87 | void M_BufferWriteFloats(buf_t *buf, const float *floats, size_t count); 88 | void M_BufferWriteDouble(buf_t *buf, double d); 89 | void M_BufferWriteDoubles(buf_t *buf, const double *doubles, size_t count); 90 | #endif 91 | void M_BufferWriteString(buf_t *buf, const char *string, size_t length); 92 | void M_BufferWriteZeros(buf_t *buf, size_t count); 93 | 94 | bool M_BufferEqualsString(const buf_t *buf, const char *s); 95 | bool M_BufferEqualsData(const buf_t *buf, const void *d, size_t size); 96 | 97 | bool M_BufferRead(buf_t *buf, void *data, size_t size); 98 | bool M_BufferReadBool(buf_t *buf, bool *b); 99 | bool M_BufferReadBools(buf_t *buf, bool *b, size_t count); 100 | bool M_BufferReadChar(buf_t *buf, char *c); 101 | bool M_BufferReadChars(buf_t *buf, char *c, size_t count); 102 | bool M_BufferReadUChar(buf_t *buf, unsigned char *c); 103 | bool M_BufferReadUChars(buf_t *buf, unsigned char *c, size_t count); 104 | bool M_BufferReadShort(buf_t *buf, short *s); 105 | bool M_BufferReadShorts(buf_t *buf, short *shorts, size_t count); 106 | bool M_BufferReadUShort(buf_t *buf, unsigned short *s); 107 | bool M_BufferReadUShorts(buf_t *buf, unsigned short *s, size_t count); 108 | bool M_BufferReadInt(buf_t *buf, int *i); 109 | bool M_BufferReadInts(buf_t *buf, int *i, size_t count); 110 | bool M_BufferReadUInt(buf_t *buf, unsigned int *i); 111 | bool M_BufferReadUInts(buf_t *buf, unsigned int *i, size_t count); 112 | bool M_BufferReadLong(buf_t *buf, int64_t *l); 113 | bool M_BufferReadLongs(buf_t *buf, int64_t *l, size_t count); 114 | bool M_BufferReadULong(buf_t *buf, uint64_t *l); 115 | bool M_BufferReadULongs(buf_t *buf, uint64_t *l, size_t count); 116 | #ifndef CMP_NO_FLOAT 117 | bool M_BufferReadFloat(buf_t *buf, float *f); 118 | bool M_BufferReadFloats(buf_t *buf, float *f, size_t count); 119 | bool M_BufferReadDouble(buf_t *buf, double *d); 120 | bool M_BufferReadDoubles(buf_t *buf, double *d, size_t count); 121 | #endif 122 | bool M_BufferReadString(buf_t *buf, char *s, size_t length); 123 | bool M_BufferReadStringDup(const buf_t *buf, char **s); 124 | bool M_BufferCopyString(buf_t *dst, const buf_t *src); 125 | 126 | void M_BufferCompact(buf_t *buf); 127 | void M_BufferTruncate(buf_t *buf, size_t new_size); 128 | void M_BufferZero(const buf_t *buf); 129 | void M_BufferClear(buf_t *buf); 130 | void M_BufferFree(buf_t *buf); 131 | 132 | void M_BufferPrint(const buf_t *buf); 133 | void M_BufferPrintAll(const buf_t *buf); 134 | 135 | #endif 136 | 137 | /* vi: set et ts=2 sw=2: */ 138 | 139 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CMP 2 | 3 | [![Build Status](https://travis-ci.org/camgunz/cmp.svg?branch=master)](https://travis-ci.org/camgunz/cmp) [![Coverage Status](https://coveralls.io/repos/github/camgunz/cmp/badge.svg?branch=develop)](https://coveralls.io/github/camgunz/cmp?branch=develop) 4 | 5 | CMP is a C implementation of the MessagePack serialization format. It 6 | currently implements version 5 of the [MessagePack 7 | Spec](http://github.com/msgpack/msgpack/blob/master/spec.md). 8 | 9 | CMP's goal is to be lightweight and straightforward, forcing nothing on the 10 | programmer. 11 | 12 | ## License 13 | 14 | While I'm a big believer in the GPL, I license CMP under the MIT license. 15 | 16 | ## Example Usage 17 | 18 | The following examples use a file as the backend, and are modeled after the 19 | examples included with the msgpack-c project. 20 | 21 | ```C 22 | #include 23 | #include 24 | 25 | #include "cmp.h" 26 | 27 | static bool read_bytes(void *data, size_t sz, FILE *fh) { 28 | return fread(data, sizeof(uint8_t), sz, fh) == (sz * sizeof(uint8_t)); 29 | } 30 | 31 | static bool file_reader(cmp_ctx_t *ctx, void *data, size_t limit) { 32 | return read_bytes(data, limit, (FILE *)ctx->buf); 33 | } 34 | 35 | static bool file_skipper(cmp_ctx_t *ctx, size_t count) { 36 | return fseek((FILE *)ctx->buf, count, SEEK_CUR); 37 | } 38 | 39 | static size_t file_writer(cmp_ctx_t *ctx, const void *data, size_t count) { 40 | return fwrite(data, sizeof(uint8_t), count, (FILE *)ctx->buf); 41 | } 42 | 43 | static void error_and_exit(const char *msg) { 44 | fprintf(stderr, "%s\n\n", msg); 45 | exit(EXIT_FAILURE); 46 | } 47 | 48 | int main(void) { 49 | FILE *fh = NULL; 50 | cmp_ctx_t cmp = {0}; 51 | uint32_t array_size = 0; 52 | uint32_t str_size = 0; 53 | char hello[6] = {0}; 54 | char message_pack[12] = {0}; 55 | 56 | fh = fopen("cmp_data.dat", "w+b"); 57 | 58 | if (fh == NULL) { 59 | error_and_exit("Error opening data.dat"); 60 | } 61 | 62 | cmp_init(&cmp, fh, file_reader, file_skipper, file_writer); 63 | 64 | if (!cmp_write_array(&cmp, 2)) { 65 | error_and_exit(cmp_strerror(&cmp)); 66 | } 67 | 68 | if (!cmp_write_str(&cmp, "Hello", 5)) { 69 | error_and_exit(cmp_strerror(&cmp)); 70 | } 71 | 72 | if (!cmp_write_str(&cmp, "MessagePack", 11)) { 73 | error_and_exit(cmp_strerror(&cmp)); 74 | } 75 | 76 | rewind(fh); 77 | 78 | if (!cmp_read_array(&cmp, &array_size)) { 79 | error_and_exit(cmp_strerror(&cmp)); 80 | } 81 | 82 | /* You can read the str byte size and then read str bytes... */ 83 | 84 | if (!cmp_read_str_size(&cmp, &str_size)) { 85 | error_and_exit(cmp_strerror(&cmp)); 86 | } 87 | 88 | if (str_size > (sizeof(hello) - 1)) { 89 | error_and_exit("Packed 'hello' length too long\n"); 90 | } 91 | 92 | if (!read_bytes(hello, str_size, fh)) { 93 | error_and_exit(cmp_strerror(&cmp)); 94 | } 95 | 96 | /* 97 | * ...or you can set the maximum number of bytes to read and do it all in 98 | * one call 99 | */ 100 | 101 | str_size = sizeof(message_pack); 102 | if (!cmp_read_str(&cmp, message_pack, &str_size)) { 103 | error_and_exit(cmp_strerror(&cmp)); 104 | } 105 | 106 | printf("Array Length: %u.\n", array_size); 107 | printf("[\"%s\", \"%s\"]\n", hello, message_pack); 108 | 109 | fclose(fh); 110 | 111 | return EXIT_SUCCESS; 112 | } 113 | ``` 114 | 115 | ## Advanced Usage 116 | 117 | See the `examples` folder. 118 | 119 | ## Fast, Lightweight, Flexible, and Robust 120 | 121 | CMP uses no internal buffers; conversions, encoding and decoding are done on 122 | the fly. 123 | 124 | CMP's source and header file together are ~4k LOC. 125 | 126 | CMP makes no heap allocations. 127 | 128 | CMP uses standardized types rather than declaring its own, and it depends only 129 | on `stdbool.h`, `stdint.h` and `string.h`. 130 | 131 | CMP is written using C89 (ANSI C), aside, of course, from its use of 132 | fixed-width integer types and `bool`. 133 | 134 | On the other hand, CMP's test suite requires C99. 135 | 136 | CMP only requires the programmer supply a read function, a write function, and 137 | an optional skip function. In this way, the programmer can use CMP on memory, 138 | files, sockets, etc. 139 | 140 | CMP is portable. It uses fixed-width integer types, and checks the endianness 141 | of the machine at runtime before swapping bytes (MessagePack is big-endian). 142 | 143 | CMP provides a fairly comprehensive error reporting mechanism modeled after 144 | `errno` and `strerror`. 145 | 146 | CMP is thread aware; while contexts cannot be shared between threads, each 147 | thread may use its own context freely. 148 | 149 | CMP is tested using the MessagePack test suite as well as a large set of custom 150 | test cases. Its small test program is compiled with clang using `-Wall -Werror 151 | -Wextra ...` along with several other flags, and generates no compilation 152 | errors in either clang or GCC. 153 | 154 | CMP's source is written as readably as possible, using explicit, descriptive 155 | variable names and a consistent, clear style. 156 | 157 | CMP's source is written to be as secure as possible. Its testing suite checks 158 | for invalid values, and data is always treated as suspect before it passes 159 | validation. 160 | 161 | CMP's API is designed to be clear, convenient and unsurprising. Strings are 162 | null-terminated, binary data is not, error codes are clear, and so on. 163 | 164 | CMP provides optional backwards compatibility for use with other MessagePack 165 | implementations that only implement version 4 of the spec. 166 | 167 | ## Building 168 | 169 | There is no build system for CMP. The programmer can drop `cmp.c` and `cmp.h` 170 | in their source tree and modify as necessary. No special compiler settings are 171 | required to build it, and it generates no compilation errors in either clang or 172 | gcc. 173 | 174 | ## Versioning 175 | 176 | CMP's versions are single integers. I don't use semantic versioning because 177 | I don't guarantee that any version is completely compatible with any other. In 178 | general, semantic versioning provides a false sense of security. You should be 179 | evaluating compatibility yourself, not relying on some stranger's versioning 180 | convention. 181 | 182 | ## Stability 183 | 184 | I only guarantee stability for versions released on 185 | [the releases page](../../releases). While rare, both `master` and `develop` 186 | branches may have errors or mismatched versions. 187 | 188 | ## Backwards Compatibility 189 | 190 | Version 4 of the MessagePack spec has no `BIN` type, and provides no `STR8` 191 | marker. In order to remain backwards compatible with version 4 of MessagePack, 192 | do the following: 193 | 194 | Avoid these functions: 195 | 196 | - `cmp_write_bin` 197 | - `cmp_write_bin_marker` 198 | - `cmp_write_str8_marker` 199 | - `cmp_write_str8` 200 | - `cmp_write_bin8_marker` 201 | - `cmp_write_bin8` 202 | - `cmp_write_bin16_marker` 203 | - `cmp_write_bin16` 204 | - `cmp_write_bin32_marker` 205 | - `cmp_write_bin32` 206 | 207 | Use these functions in lieu of their v5 counterparts: 208 | 209 | - `cmp_write_str_marker_v4` instead of `cmp_write_str_marker` 210 | - `cmp_write_str_v4` instead of `cmp_write_str` 211 | - `cmp_write_object_v4` instead of `cmp_write_object` 212 | 213 | ## Disabling Floating Point Operations 214 | 215 | Thanks to [tdragon](https://github.com/tdragon) it's possible to disable 216 | floating point operations in CMP by defining `CMP_NO_FLOAT`. No floating point 217 | functionality will be included. Fair warning: this changes the ABI. 218 | 219 | ## Setting Endianness at Compile Time 220 | 221 | CMP will honor `WORDS_BIGENDIAN`. If defined to `0` it will convert data 222 | to/from little-endian format when writing/reading. If defined to `1` it won't. 223 | If not defined, CMP will check at runtime. 224 | -------------------------------------------------------------------------------- /test/buf.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "utils.h" 33 | #include "buf.h" 34 | 35 | 36 | static void check_cursor(buf_t *buf) { 37 | if (buf->cursor > buf->size) 38 | buf->size = buf->cursor; 39 | } 40 | 41 | buf_t* M_BufferNew(void) { 42 | buf_t *buf = calloc(1, sizeof(buf_t)); 43 | 44 | if (buf == NULL) 45 | error_and_exit("M_BufferNew: Calloc returned NULL."); 46 | 47 | M_BufferInit(buf); 48 | 49 | return buf; 50 | } 51 | 52 | buf_t* M_BufferNewWithCapacity(size_t capacity) { 53 | buf_t *buf = calloc(1, sizeof(buf_t)); 54 | 55 | if (buf == NULL) 56 | error_and_exit("M_BufferNew: calloc returned NULL"); 57 | 58 | M_BufferInitWithCapacity(buf, capacity); 59 | 60 | return buf; 61 | } 62 | 63 | void M_BufferInit(buf_t *buf) { 64 | buf->size = 0; 65 | buf->capacity = 0; 66 | buf->cursor = 0; 67 | buf->data = NULL; 68 | } 69 | 70 | void M_BufferInitWithCapacity(buf_t *buf, size_t capacity) { 71 | M_BufferInit(buf); 72 | M_BufferEnsureTotalCapacity(buf, capacity); 73 | } 74 | 75 | size_t M_BufferGetCapacity(const buf_t *buf) { 76 | return buf->capacity; 77 | } 78 | 79 | size_t M_BufferGetSize(const buf_t *buf) { 80 | return buf->size; 81 | } 82 | 83 | size_t M_BufferGetCursor(const buf_t *buf) { 84 | return buf->cursor; 85 | } 86 | 87 | char* M_BufferGetData(const buf_t *buf) { 88 | return buf->data; 89 | } 90 | 91 | char* M_BufferGetDataAtCursor(const buf_t *buf) { 92 | return buf->data + buf->cursor; 93 | } 94 | 95 | void M_BufferEnsureCapacity(buf_t *buf, size_t capacity) { 96 | size_t needed_capacity = buf->cursor + capacity; 97 | 98 | if (buf->capacity < needed_capacity) { 99 | buf->data = realloc(buf->data, needed_capacity * sizeof(uint8_t)); 100 | 101 | if (buf->data == NULL) { 102 | error_and_exit( 103 | "M_BufferEnsureCapacity: Reallocating buffer data failed" 104 | ); 105 | } 106 | 107 | memset(buf->data + buf->capacity, 0, needed_capacity - buf->capacity); 108 | buf->capacity = needed_capacity; 109 | } 110 | } 111 | 112 | void M_BufferEnsureTotalCapacity(buf_t *buf, size_t capacity) { 113 | if (buf->capacity < capacity) { 114 | size_t old_capacity = buf->capacity; 115 | 116 | buf->capacity = capacity; 117 | buf->data = realloc(buf->data, buf->capacity * sizeof(uint8_t)); 118 | 119 | if (buf->data == NULL) 120 | error_and_exit("M_BufferEnsureCapacity: Allocating buffer data failed"); 121 | 122 | memset(buf->data + old_capacity, 0, buf->capacity - old_capacity); 123 | } 124 | } 125 | 126 | void M_BufferCopy(buf_t *dst, const buf_t *src) { 127 | M_BufferSetData(dst, M_BufferGetData(src), M_BufferGetSize(src)); 128 | } 129 | 130 | void M_BufferCursorCopy(buf_t *dst, const buf_t *src) { 131 | M_BufferWrite( 132 | dst, 133 | M_BufferGetDataAtCursor(src), 134 | M_BufferGetSize(src) - (M_BufferGetCursor(src) - 1) 135 | ); 136 | } 137 | 138 | bool M_BufferMove(buf_t *buf, size_t dpos, size_t spos, size_t count) { 139 | if ((spos + count) > M_BufferGetSize(buf)) 140 | return false; 141 | 142 | M_BufferEnsureTotalCapacity(buf, dpos + count); 143 | 144 | memmove(M_BufferGetData(buf) + dpos, M_BufferGetData(buf) + spos, count); 145 | 146 | return true; 147 | } 148 | 149 | void M_BufferSetData(buf_t *buf, const void *data, size_t size) { 150 | M_BufferClear(buf); 151 | M_BufferEnsureTotalCapacity(buf, size); 152 | M_BufferWrite(buf, data, size); 153 | } 154 | 155 | void M_BufferSetString(buf_t *buf, const char *data, size_t length) { 156 | M_BufferClear(buf); 157 | M_BufferWriteString(buf, data, length); 158 | } 159 | 160 | bool M_BufferSetFile(buf_t *buf, const char *filename) { 161 | FILE *fp; 162 | size_t length; 163 | bool out = false; 164 | 165 | if ((fp = fopen(filename, "rb")) == NULL) 166 | return false; 167 | 168 | fseek(fp, 0, SEEK_END); 169 | length = ftell(fp); 170 | fseek(fp, 0, SEEK_SET); 171 | 172 | M_BufferClear(buf); 173 | M_BufferEnsureTotalCapacity(buf, length); 174 | 175 | if (fread(buf->data, sizeof(uint8_t), length, fp) == length) { 176 | buf->cursor = length; 177 | buf->size = length; 178 | out = true; 179 | } 180 | else { 181 | M_BufferClear(buf); 182 | out = false; 183 | } 184 | 185 | fclose(fp); 186 | return out; 187 | } 188 | 189 | bool M_BufferSeek(buf_t *buf, size_t pos) { 190 | if (pos > buf->size) 191 | return false; 192 | 193 | buf->cursor = pos; 194 | return true; 195 | } 196 | 197 | bool M_BufferSeekBackward(buf_t *buf, size_t count) { 198 | if (count > buf->cursor) 199 | return false; 200 | 201 | buf->cursor -= count; 202 | return true; 203 | } 204 | 205 | bool M_BufferSeekForward(buf_t *buf, size_t count) { 206 | if (buf->cursor + count > buf->size) 207 | return false; 208 | 209 | buf->cursor += count; 210 | return true; 211 | } 212 | 213 | uint8_t M_BufferPeek(const buf_t *buf) { 214 | return *(buf->data + buf->cursor); 215 | } 216 | 217 | void M_BufferWrite(buf_t *buf, const void *data, size_t size) { 218 | M_BufferEnsureCapacity(buf, size); 219 | memcpy(buf->data + buf->cursor, data, size); 220 | buf->cursor += size; 221 | 222 | check_cursor(buf); 223 | } 224 | 225 | void M_BufferWriteBool(buf_t *buf, bool b) { 226 | M_BufferWriteBools(buf, &b, 1); 227 | } 228 | 229 | void M_BufferWriteBools(buf_t *buf, const bool *bools, size_t count) { 230 | M_BufferEnsureCapacity(buf, count * sizeof(bool)); 231 | M_BufferWriteChars(buf, (char *)bools, count * sizeof(bool)); 232 | } 233 | 234 | void M_BufferWriteChar(buf_t *buf, char c) { 235 | M_BufferWriteChars(buf, &c, 1); 236 | } 237 | 238 | void M_BufferWriteChars(buf_t *buf, const char *chars, size_t count) { 239 | M_BufferWrite(buf, chars, count * sizeof(char)); 240 | } 241 | 242 | void M_BufferWriteUChar(buf_t *buf, unsigned char c) { 243 | M_BufferWriteUChars(buf, &c, 1); 244 | } 245 | 246 | void M_BufferWriteUChars(buf_t *buf, const unsigned char *uchars, size_t count) { 247 | M_BufferWrite(buf, uchars, count * sizeof(unsigned char)); 248 | } 249 | 250 | void M_BufferWriteShort(buf_t *buf, short s) { 251 | M_BufferWriteShorts(buf, &s, 1); 252 | } 253 | 254 | void M_BufferWriteShorts(buf_t *buf, const short *shorts, size_t count) { 255 | M_BufferEnsureCapacity(buf, count * sizeof(short)); 256 | M_BufferWriteChars(buf, (char *)shorts, count * sizeof(short)); 257 | } 258 | 259 | void M_BufferWriteUShort(buf_t *buf, unsigned short s) { 260 | M_BufferWriteUShorts(buf, &s, 1); 261 | } 262 | 263 | void M_BufferWriteUShorts(buf_t *buf, const unsigned short *ushorts, 264 | size_t count) { 265 | M_BufferEnsureCapacity(buf, count * sizeof(unsigned short)); 266 | M_BufferWriteChars(buf, (char *)ushorts, count * sizeof(unsigned short)); 267 | } 268 | 269 | void M_BufferWriteInt(buf_t *buf, int i) { 270 | M_BufferWriteInts(buf, &i, 1); 271 | } 272 | 273 | void M_BufferWriteInts(buf_t *buf, const int *ints, size_t count) { 274 | M_BufferEnsureCapacity(buf, count * sizeof(int)); 275 | M_BufferWriteChars(buf, (char *)ints, count * sizeof(int)); 276 | } 277 | 278 | void M_BufferWriteUInt(buf_t *buf, unsigned int s) { 279 | M_BufferWriteUInts(buf, &s, 1); 280 | } 281 | 282 | void M_BufferWriteUInts(buf_t *buf, const unsigned int *uints, size_t count) { 283 | M_BufferEnsureCapacity(buf, count * sizeof(unsigned int)); 284 | M_BufferWriteChars(buf, (char *)uints, count * sizeof(unsigned int)); 285 | } 286 | 287 | void M_BufferWriteLong(buf_t *buf, int64_t l) { 288 | M_BufferWriteLongs(buf, &l, 1); 289 | } 290 | 291 | void M_BufferWriteLongs(buf_t *buf, const int64_t *longs, size_t count) { 292 | M_BufferEnsureCapacity(buf, count * sizeof(int64_t)); 293 | M_BufferWriteChars(buf, (char *)longs, count * sizeof(int64_t)); 294 | } 295 | 296 | void M_BufferWriteULong(buf_t *buf, uint64_t l) { 297 | M_BufferWriteULongs(buf, &l, 1); 298 | } 299 | 300 | void M_BufferWriteULongs(buf_t *buf, const uint64_t *ulongs, size_t count) { 301 | M_BufferEnsureCapacity(buf, count * sizeof(int64_t)); 302 | M_BufferWriteChars(buf, (char *)ulongs, count * sizeof(uint64_t)); 303 | } 304 | 305 | #ifndef CMP_NO_FLOAT 306 | void M_BufferWriteFloat(buf_t *buf, float f) { 307 | M_BufferWriteFloats(buf, &f, 1); 308 | } 309 | 310 | void M_BufferWriteFloats(buf_t *buf, const float *floats, size_t count) { 311 | M_BufferEnsureCapacity(buf, count * sizeof(float)); 312 | M_BufferWriteChars(buf, (char *)floats, count * sizeof(floats)); 313 | } 314 | 315 | void M_BufferWriteDouble(buf_t *buf, double d) { 316 | M_BufferWriteDoubles(buf, &d, 1); 317 | } 318 | 319 | void M_BufferWriteDoubles(buf_t *buf, const double *doubles, size_t count) { 320 | M_BufferEnsureCapacity(buf, count * sizeof(double)); 321 | M_BufferWriteChars(buf, (char *)doubles, count * sizeof(doubles)); 322 | } 323 | #endif 324 | 325 | void M_BufferWriteString(buf_t *buf, const char *string, size_t length) { 326 | M_BufferEnsureCapacity(buf, length + 1); 327 | strncpy(buf->data + buf->cursor, string, length + 1); 328 | buf->cursor += (length + 1); 329 | 330 | check_cursor(buf); 331 | } 332 | 333 | void M_BufferWriteZeros(buf_t *buf, size_t count) { 334 | M_BufferEnsureCapacity(buf, count); 335 | 336 | for (size_t i = 0; i < count; i++) 337 | buf->data[buf->cursor++] = 0; 338 | 339 | check_cursor(buf); 340 | } 341 | 342 | bool M_BufferEqualsString(const buf_t *buf, const char *s) { 343 | if (strncmp(buf->data + buf->cursor, s, buf->size - buf->cursor) == 0) 344 | return true; 345 | 346 | return false; 347 | } 348 | 349 | bool M_BufferEqualsData(const buf_t *buf, const void *d, size_t size) { 350 | if (buf->cursor + size > buf->size) 351 | return false; 352 | 353 | if (memcmp(buf->data + buf->cursor, d, size) == 0) 354 | return true; 355 | 356 | return false; 357 | } 358 | 359 | bool M_BufferRead(buf_t *buf, void *data, size_t size) { 360 | if (buf->cursor + size > buf->size) 361 | return false; 362 | 363 | if (size == 1) 364 | *((char *)data) = *(buf->data + buf->cursor); 365 | else 366 | memcpy(data, buf->data + buf->cursor, size); 367 | 368 | buf->cursor += size; 369 | 370 | return true; 371 | } 372 | 373 | bool M_BufferReadBool(buf_t *buf, bool *b) { 374 | return M_BufferReadBools(buf, b, 1); 375 | } 376 | 377 | bool M_BufferReadBools(buf_t *buf, bool *b, size_t count) { 378 | return M_BufferRead(buf, b, count * sizeof(bool)); 379 | } 380 | 381 | bool M_BufferReadChar(buf_t *buf, char *c) { 382 | return M_BufferReadChars(buf, c, 1); 383 | } 384 | 385 | bool M_BufferReadChars(buf_t *buf, char *c, size_t count) { 386 | return M_BufferRead(buf, c, count * sizeof(char)); 387 | } 388 | 389 | bool M_BufferReadUChar(buf_t *buf, unsigned char *c) { 390 | return M_BufferReadUChars(buf, c, 1); 391 | } 392 | 393 | bool M_BufferReadUChars(buf_t *buf, unsigned char *c, size_t count) { 394 | return M_BufferRead(buf, c, count * sizeof(unsigned char)); 395 | } 396 | 397 | bool M_BufferReadShort(buf_t *buf, short *s) { 398 | return M_BufferReadShorts(buf, s, 1); 399 | } 400 | 401 | bool M_BufferReadShorts(buf_t *buf, short *s, size_t count) { 402 | return M_BufferRead(buf, s, count * sizeof(short)); 403 | } 404 | 405 | bool M_BufferReadUShort(buf_t *buf, unsigned short *s) { 406 | return M_BufferReadUShorts(buf, s, 1); 407 | } 408 | 409 | bool M_BufferReadUShorts(buf_t *buf, unsigned short *s, size_t count) { 410 | return M_BufferRead(buf, s, count * sizeof(unsigned short)); 411 | } 412 | 413 | bool M_BufferReadInt(buf_t *buf, int *i) { 414 | return M_BufferReadInts(buf, i, 1); 415 | } 416 | 417 | bool M_BufferReadInts(buf_t *buf, int *i, size_t count) { 418 | return M_BufferRead(buf, i, count * sizeof(int)); 419 | } 420 | 421 | bool M_BufferReadUInt(buf_t *buf, unsigned int *i) { 422 | return M_BufferReadUInts(buf, i, 1); 423 | } 424 | 425 | bool M_BufferReadUInts(buf_t *buf, unsigned int *i, size_t count) { 426 | return M_BufferRead(buf, i, count * sizeof(unsigned int)); 427 | } 428 | 429 | bool M_BufferReadLong(buf_t *buf, int64_t *l) { 430 | return M_BufferReadLongs(buf, l, 1); 431 | } 432 | 433 | bool M_BufferReadLongs(buf_t *buf, int64_t *l, size_t count) { 434 | return M_BufferRead(buf, l, count * sizeof(int64_t)); 435 | } 436 | 437 | bool M_BufferReadULong(buf_t *buf, uint64_t *l) { 438 | return M_BufferReadULongs(buf, l, 1); 439 | } 440 | 441 | bool M_BufferReadULongs(buf_t *buf, uint64_t *l, size_t count) { 442 | return M_BufferRead(buf, l, count * sizeof(uint64_t)); 443 | } 444 | 445 | #ifndef CMP_NO_FLOAT 446 | bool M_BufferReadFloat(buf_t *buf, float *f) { 447 | return M_BufferReadFloats(buf, f, 1); 448 | } 449 | 450 | bool M_BufferReadFloats(buf_t *buf, float *f, size_t count) { 451 | return M_BufferRead(buf, f, count * sizeof(float)); 452 | } 453 | 454 | bool M_BufferReadDouble(buf_t *buf, double *d) { 455 | return M_BufferReadDoubles(buf, d, 1); 456 | } 457 | 458 | bool M_BufferReadDoubles(buf_t *buf, double *d, size_t count) { 459 | return M_BufferRead(buf, d, count * sizeof(double)); 460 | } 461 | #endif 462 | 463 | bool M_BufferReadString(buf_t *buf, char *s, size_t length) { 464 | return M_BufferRead(buf, s, length); 465 | } 466 | 467 | bool M_BufferReadStringDup(const buf_t *buf, char **s) { 468 | char *d = buf->data + buf->cursor; 469 | size_t length = strlen(d); 470 | 471 | if (buf->cursor + length > buf->size) 472 | return false; 473 | 474 | (*s) = strdup(buf->data + buf->cursor); 475 | return true; 476 | } 477 | 478 | bool M_BufferCopyString(buf_t *dst, const buf_t *src) { 479 | char *s = src->data + src->cursor; 480 | size_t length = strlen(s); 481 | 482 | if (src->cursor + length >= src->size) 483 | return false; 484 | 485 | M_BufferWriteString(dst, s, length); 486 | return true; 487 | } 488 | 489 | void M_BufferCompact(buf_t *buf) { 490 | if (buf->size < buf->capacity) { 491 | char *new_buf = calloc(buf->size, sizeof(uint8_t)); 492 | 493 | if (buf->data == NULL) 494 | error_and_exit("M_BufferCompact: Allocating new buffer data failed"); 495 | 496 | memcpy(new_buf, buf->data, buf->size); 497 | free(buf->data); 498 | buf->data = new_buf; 499 | buf->capacity = buf->size; 500 | if (buf->cursor > buf->size) 501 | buf->cursor = buf->size; 502 | } 503 | } 504 | 505 | void M_BufferTruncate(buf_t *buf, size_t new_size) { 506 | size_t old_size = buf->size; 507 | 508 | if (new_size >= buf->size) 509 | errorf_and_exit("M_BufferTruncate: %zu >= %zu.", new_size, buf->size); 510 | 511 | memset(buf->data + new_size, 0, old_size - new_size); 512 | buf->size = new_size; 513 | 514 | if (buf->cursor >= buf->size) 515 | buf->cursor = buf->size - 1; 516 | } 517 | 518 | void M_BufferZero(const buf_t *buf) { 519 | memset(buf->data, 0, buf->capacity); 520 | } 521 | 522 | void M_BufferClear(buf_t *buf) { 523 | buf->size = 0; 524 | buf->cursor = 0; 525 | M_BufferZero(buf); 526 | } 527 | 528 | void M_BufferFree(buf_t *buf) { 529 | free(buf->data); 530 | memset(buf, 0, sizeof(buf_t)); 531 | buf->data = NULL; 532 | } 533 | 534 | void M_BufferPrint(const buf_t *buf) { 535 | printf("Buffer capacity, size and cursor: [%zu, %zu, %zu].\n", 536 | buf->capacity, 537 | buf->size, 538 | buf->cursor 539 | ); 540 | 541 | for (size_t i = 0; i < MIN(64, buf->size); i++) { 542 | printf("%02X ", (unsigned char)buf->data[i]); 543 | 544 | if ((i > 0) && (((i + 1) % 25) == 0)) 545 | printf("\n"); 546 | } 547 | 548 | printf("\n"); 549 | } 550 | 551 | void M_BufferPrintAll(const buf_t *buf) { 552 | printf("Buffer capacity, size and cursor: [%zu, %zu, %zu].\n", 553 | buf->capacity, 554 | buf->size, 555 | buf->cursor 556 | ); 557 | 558 | for (size_t i = 0; i < buf->size; i++) { 559 | printf("%02X ", (unsigned char)buf->data[i]); 560 | 561 | if ((i > 0) && (((i + 1) % 25) == 0)) 562 | printf("\n"); 563 | } 564 | 565 | printf("\n"); 566 | } 567 | 568 | /* vi: set et ts=2 sw=2: */ 569 | 570 | -------------------------------------------------------------------------------- /examples/example2.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "cmp.h" 32 | 33 | static bool read_bytes(void *data, size_t sz, FILE *fh) { 34 | return fread(data, sizeof(uint8_t), sz, fh) == (sz * sizeof(uint8_t)); 35 | } 36 | 37 | static bool file_reader(cmp_ctx_t *ctx, void *data, size_t limit) { 38 | return read_bytes(data, limit, (FILE *)ctx->buf); 39 | } 40 | 41 | static bool file_skipper(cmp_ctx_t *ctx, size_t count) { 42 | return fseek((FILE *)ctx->buf, count, SEEK_CUR); 43 | } 44 | 45 | static size_t file_writer(cmp_ctx_t *ctx, const void *data, size_t count) { 46 | return fwrite(data, sizeof(uint8_t), count, (FILE *)ctx->buf); 47 | } 48 | 49 | static void error_and_exit(const char *msg) { 50 | fprintf(stderr, "%s\n\n", msg); 51 | exit(EXIT_FAILURE); 52 | } 53 | 54 | int main(void) { 55 | FILE *fh = {0}; 56 | cmp_ctx_t cmp = {0}; 57 | uint16_t year = 1983; 58 | uint8_t month = 5; 59 | uint8_t day = 28; 60 | int64_t sint = 0; 61 | uint64_t uint = 0; 62 | float flt = 0.0f; 63 | double dbl = 0.0; 64 | bool boolean = false; 65 | uint8_t fake_bool = 0; 66 | uint32_t string_size = 0; 67 | uint32_t array_size = 0; 68 | uint32_t binary_size = 0; 69 | uint32_t map_size = 0; 70 | int8_t ext_type = 0; 71 | uint32_t ext_size = 0; 72 | char sbuf[12] = {0}; 73 | 74 | fh = fopen("cmp_data.dat", "w+b"); 75 | 76 | if (fh == NULL) { 77 | error_and_exit("Error opening data.dat"); 78 | } 79 | 80 | cmp_init(&cmp, fh, file_reader, file_skipper, file_writer); 81 | 82 | /* 83 | * When you write an array, you first specify the number of array 84 | * elements, then you write that many elements. 85 | */ 86 | if (!cmp_write_array(&cmp, 9)) { 87 | error_and_exit(cmp_strerror(&cmp)); 88 | } 89 | 90 | if (!cmp_write_sint(&cmp, -14)) { 91 | error_and_exit(cmp_strerror(&cmp)); 92 | } 93 | 94 | if (!cmp_write_uint(&cmp, 38)) { 95 | error_and_exit(cmp_strerror(&cmp)); 96 | } 97 | 98 | if (!cmp_write_float(&cmp, 1.8f)) { 99 | error_and_exit(cmp_strerror(&cmp)); 100 | } 101 | 102 | if (!cmp_write_double(&cmp, 300.4)) { 103 | error_and_exit(cmp_strerror(&cmp)); 104 | } 105 | 106 | if (!cmp_write_nil(&cmp)) { 107 | error_and_exit(cmp_strerror(&cmp)); 108 | } 109 | 110 | if (!cmp_write_true(&cmp)) { 111 | error_and_exit(cmp_strerror(&cmp)); 112 | } 113 | 114 | if (!cmp_write_false(&cmp)) { 115 | error_and_exit(cmp_strerror(&cmp)); 116 | } 117 | 118 | if (!cmp_write_bool(&cmp, false)) { 119 | error_and_exit(cmp_strerror(&cmp)); 120 | } 121 | 122 | if (!cmp_write_u8_as_bool(&cmp, 1)) { 123 | error_and_exit(cmp_strerror(&cmp)); 124 | } 125 | 126 | /* Array full */ 127 | 128 | /* 129 | * Maps work similar to arrays, but the length is in "pairs", so this 130 | * writes 2 pairs to the map. Subsequently, pairs are written in key, 131 | * value order. 132 | */ 133 | 134 | if (!cmp_write_map(&cmp, 2)) { 135 | error_and_exit(cmp_strerror(&cmp)); 136 | } 137 | 138 | /* You can write string data all at once... */ 139 | 140 | if (!cmp_write_str(&cmp, "Greeting", 8)) { 141 | error_and_exit(cmp_strerror(&cmp)); 142 | } 143 | 144 | if (!cmp_write_str(&cmp, "Hello", 5)) { 145 | error_and_exit(cmp_strerror(&cmp)); 146 | } 147 | 148 | if (!cmp_write_str(&cmp, "Name", 4)) { 149 | error_and_exit(cmp_strerror(&cmp)); 150 | } 151 | 152 | /* ...or in chunks */ 153 | 154 | if (!cmp_write_str_marker(&cmp, 5)) { 155 | error_and_exit(cmp_strerror(&cmp)); 156 | } 157 | 158 | if (file_writer(&cmp, "Li", 2) != 2) { 159 | error_and_exit(strerror(errno)); 160 | } 161 | 162 | if (file_writer(&cmp, "nus", 3) != 3) { 163 | error_and_exit(strerror(errno)); 164 | } 165 | 166 | /* Map full */ 167 | 168 | /* Binary data functions the same as string data */ 169 | 170 | if (!cmp_write_bin(&cmp, "MessagePack", 11)) { 171 | error_and_exit(cmp_strerror(&cmp)); 172 | } 173 | 174 | if (!cmp_write_bin_marker(&cmp, 8)) { 175 | error_and_exit(cmp_strerror(&cmp)); 176 | } 177 | 178 | if (file_writer(&cmp, "is ", 3) != 3) { 179 | error_and_exit(strerror(errno)); 180 | } 181 | 182 | if (file_writer(&cmp, "great", 5) != 5) { 183 | error_and_exit(strerror(errno)); 184 | } 185 | 186 | /* 187 | * With extended types, you can create your own custom types. Here we 188 | * create a simple date type. 189 | */ 190 | 191 | /* cmp_write_ext_marker(type, size) */ 192 | if (!cmp_write_ext_marker(&cmp, 1, 4)) { 193 | error_and_exit(cmp_strerror(&cmp)); 194 | } 195 | 196 | file_writer(&cmp, &year, sizeof(uint16_t)); 197 | file_writer(&cmp, &month, sizeof(uint8_t)); 198 | file_writer(&cmp, &day, sizeof(uint8_t)); 199 | 200 | /* Now we can read the data back just as easily */ 201 | 202 | rewind(fh); 203 | 204 | if (!cmp_read_array(&cmp, &array_size)) { 205 | error_and_exit(cmp_strerror(&cmp)); 206 | } 207 | 208 | if (array_size != 9) { 209 | error_and_exit("Array size was not 9"); 210 | } 211 | 212 | if (!cmp_read_sinteger(&cmp, &sint)) { 213 | error_and_exit(cmp_strerror(&cmp)); 214 | } 215 | 216 | if (sint != -14) { 217 | error_and_exit("Signed int was not -14"); 218 | } 219 | 220 | if (!cmp_read_uinteger(&cmp, &uint)) { 221 | error_and_exit(cmp_strerror(&cmp)); 222 | } 223 | 224 | if (uint != 38) { 225 | error_and_exit("Unsigned int was not 38"); 226 | } 227 | 228 | if (!cmp_read_float(&cmp, &flt)) { 229 | error_and_exit(cmp_strerror(&cmp)); 230 | } 231 | 232 | if (flt != 1.8f) { 233 | error_and_exit("Float was not 1.8f"); 234 | } 235 | 236 | if (!cmp_read_double(&cmp, &dbl)) { 237 | error_and_exit(cmp_strerror(&cmp)); 238 | } 239 | 240 | if (dbl != 300.4) { 241 | error_and_exit("Double was not 300.f"); 242 | } 243 | 244 | if (!cmp_read_nil(&cmp)) { 245 | error_and_exit(cmp_strerror(&cmp)); 246 | } 247 | 248 | if (!cmp_read_bool(&cmp, &boolean)) { 249 | error_and_exit(cmp_strerror(&cmp)); 250 | } 251 | 252 | if (boolean != true) { 253 | error_and_exit("First boolean was not true"); 254 | } 255 | 256 | if (!cmp_read_bool(&cmp, &boolean)) { 257 | error_and_exit(cmp_strerror(&cmp)); 258 | } 259 | 260 | if (boolean != false) { 261 | error_and_exit("Second boolean was not false"); 262 | } 263 | 264 | if (!cmp_read_bool(&cmp, &boolean)) { 265 | error_and_exit(cmp_strerror(&cmp)); 266 | } 267 | 268 | if (boolean != false) { 269 | error_and_exit("Third boolean was not false"); 270 | } 271 | 272 | if (!cmp_read_bool_as_u8(&cmp, &fake_bool)) { 273 | error_and_exit(cmp_strerror(&cmp)); 274 | } 275 | 276 | if (fake_bool != 1) { 277 | fprintf(stderr, "%u.\n", fake_bool); 278 | error_and_exit("Third boolean (u8) was not 1"); 279 | } 280 | 281 | if (!cmp_read_map(&cmp, &map_size)) { 282 | error_and_exit(cmp_strerror(&cmp)); 283 | } 284 | 285 | if (map_size != 2) { 286 | error_and_exit("Map size was not 2"); 287 | } 288 | 289 | /* 290 | * String reading here. Note that normally strings are encoded using 291 | * UTF-8. I have cleverly restricted this example to ASCII, which overlaps 292 | * UTF-8 encoding, but this must not be assumed in real-world code. 293 | * 294 | * You can read strings in two ways. Either you can read the string's size 295 | * in bytes and then read the bytes manually... 296 | */ 297 | 298 | if (!cmp_read_str_size(&cmp, &string_size)) { 299 | error_and_exit(cmp_strerror(&cmp)); 300 | } 301 | 302 | if (string_size != 8) { 303 | error_and_exit("Greeting string key size was not 8"); 304 | } 305 | 306 | if (!read_bytes(sbuf, 8, fh)) { 307 | error_and_exit(strerror(errno)); 308 | } 309 | 310 | sbuf[string_size] = 0; 311 | 312 | if (strncmp(sbuf, "Greeting", 8) != 0) { 313 | error_and_exit("Greeting string key name was not 'Greeting'"); 314 | } 315 | 316 | /* 317 | * ...or you can set the maximum number of bytes to read and do it all in 318 | * one call. cmp_read_str will write no more than "size" bytes, including 319 | * the terminating NULL, to the passed buffer. If the string's size 320 | * exceeds the passed buffer size, the "size" input is set to the number of 321 | * bytes necessary, not including the terminating NULL. Otherwise, the 322 | * "size" input is set to the number of bytes written, not including the 323 | * terminating NULL. 324 | */ 325 | 326 | string_size = sizeof(sbuf); 327 | if (!cmp_read_str(&cmp, sbuf, &string_size)) { 328 | error_and_exit(cmp_strerror(&cmp)); 329 | } 330 | 331 | if (strncmp(sbuf, "Hello", 5) != 0) { 332 | error_and_exit("Greeting string value was not 'Hello'"); 333 | } 334 | 335 | string_size = sizeof(sbuf); 336 | if (!cmp_read_str(&cmp, sbuf, &string_size)) { 337 | error_and_exit(cmp_strerror(&cmp)); 338 | } 339 | 340 | if (strncmp(sbuf, "Name", 4) != 0) { 341 | error_and_exit("Name key name was not 'Name'"); 342 | } 343 | 344 | string_size = sizeof(sbuf); 345 | if (!cmp_read_str(&cmp, sbuf, &string_size)) { 346 | error_and_exit(cmp_strerror(&cmp)); 347 | } 348 | 349 | if (strncmp(sbuf, "Linus", 5) != 0) { 350 | error_and_exit("Name key value was not 'Linus'"); 351 | } 352 | 353 | memset(sbuf, 0, sizeof(sbuf)); 354 | binary_size = sizeof(sbuf); 355 | if (!cmp_read_bin(&cmp, sbuf, &binary_size)) { 356 | error_and_exit(cmp_strerror(&cmp)); 357 | } 358 | 359 | if (memcmp(sbuf, "MessagePack", 11) != 0) { 360 | error_and_exit("1st binary value was not 'MessagePack'"); 361 | } 362 | 363 | memset(sbuf, 0, sizeof(sbuf)); 364 | binary_size = sizeof(sbuf); 365 | if (!cmp_read_bin(&cmp, sbuf, &binary_size)) { 366 | error_and_exit(cmp_strerror(&cmp)); 367 | } 368 | 369 | if (memcmp(sbuf, "is great", 8) != 0) { 370 | error_and_exit("2nd binary value was not 'is great'"); 371 | } 372 | 373 | if (!cmp_read_ext_marker(&cmp, &ext_type, &ext_size)) { 374 | error_and_exit(cmp_strerror(&cmp)); 375 | } 376 | 377 | if (!read_bytes(&year, sizeof(uint16_t), fh)) { 378 | error_and_exit(strerror(errno)); 379 | } 380 | 381 | if (!read_bytes(&month, sizeof(uint8_t), fh)) { 382 | error_and_exit(strerror(errno)); 383 | } 384 | 385 | if (!read_bytes(&day, sizeof(uint8_t), fh)) { 386 | error_and_exit(strerror(errno)); 387 | } 388 | 389 | if (year != 1983) { 390 | error_and_exit("Year was not 1983"); 391 | } 392 | 393 | if (month != 5) { 394 | error_and_exit("Month was not 5"); 395 | } 396 | 397 | if (day != 28) { 398 | error_and_exit("Day was not 28"); 399 | } 400 | 401 | rewind(fh); 402 | 403 | /* Alternately, you can read objects until the stream is empty */ 404 | while (1) { 405 | cmp_object_t obj; 406 | 407 | if (!cmp_read_object(&cmp, &obj)) { 408 | if (feof(fh)) { 409 | break; 410 | } 411 | 412 | error_and_exit(cmp_strerror(&cmp)); 413 | } 414 | 415 | switch (obj.type) { 416 | case CMP_TYPE_POSITIVE_FIXNUM: 417 | case CMP_TYPE_UINT8: 418 | printf("Unsigned Integer: %u\n", obj.as.u8); 419 | break; 420 | case CMP_TYPE_FIXMAP: 421 | case CMP_TYPE_MAP16: 422 | case CMP_TYPE_MAP32: 423 | printf("Map: %u\n", obj.as.map_size); 424 | break; 425 | case CMP_TYPE_FIXARRAY: 426 | case CMP_TYPE_ARRAY16: 427 | case CMP_TYPE_ARRAY32: 428 | printf("Array: %u\n", obj.as.array_size); 429 | break; 430 | case CMP_TYPE_FIXSTR: 431 | case CMP_TYPE_STR8: 432 | case CMP_TYPE_STR16: 433 | case CMP_TYPE_STR32: 434 | if (!read_bytes(sbuf, obj.as.str_size, fh)) { 435 | error_and_exit(strerror(errno)); 436 | } 437 | sbuf[obj.as.str_size] = 0; 438 | printf("String: %s\n", sbuf); 439 | break; 440 | case CMP_TYPE_BIN8: 441 | case CMP_TYPE_BIN16: 442 | case CMP_TYPE_BIN32: 443 | memset(sbuf, 0, sizeof(sbuf)); 444 | if (!read_bytes(sbuf, obj.as.bin_size, fh)) { 445 | error_and_exit(strerror(errno)); 446 | } 447 | printf("Binary: %s\n", sbuf); 448 | break; 449 | case CMP_TYPE_NIL: 450 | printf("NULL\n"); 451 | break; 452 | case CMP_TYPE_BOOLEAN: 453 | if (obj.as.boolean) { 454 | printf("Boolean: true\n"); 455 | } 456 | else { 457 | printf("Boolean: false\n"); 458 | } 459 | break; 460 | case CMP_TYPE_EXT8: 461 | case CMP_TYPE_EXT16: 462 | case CMP_TYPE_EXT32: 463 | case CMP_TYPE_FIXEXT1: 464 | case CMP_TYPE_FIXEXT2: 465 | case CMP_TYPE_FIXEXT4: 466 | case CMP_TYPE_FIXEXT8: 467 | case CMP_TYPE_FIXEXT16: 468 | if (obj.as.ext.type == 1) { /* Date object */ 469 | if (!read_bytes(&year, sizeof(uint16_t), fh)) { 470 | error_and_exit(strerror(errno)); 471 | } 472 | 473 | if (!read_bytes(&month, sizeof(uint8_t), fh)) { 474 | error_and_exit(strerror(errno)); 475 | } 476 | 477 | if (!read_bytes(&day, sizeof(uint8_t), fh)) { 478 | error_and_exit(strerror(errno)); 479 | } 480 | 481 | printf("Date: %u/%u/%u\n", year, month, day); 482 | } 483 | else { 484 | printf("Extended type {%d, %u}: ", 485 | obj.as.ext.type, obj.as.ext.size 486 | ); 487 | while (obj.as.ext.size--) { 488 | read_bytes(sbuf, sizeof(uint8_t), fh); 489 | printf("%02x ", sbuf[0]); 490 | } 491 | printf("\n"); 492 | } 493 | break; 494 | case CMP_TYPE_FLOAT: 495 | printf("Float: %f\n", obj.as.flt); 496 | break; 497 | case CMP_TYPE_DOUBLE: 498 | printf("Double: %f\n", obj.as.dbl); 499 | break; 500 | case CMP_TYPE_UINT16: 501 | printf("Unsigned Integer: %u\n", obj.as.u16); 502 | break; 503 | case CMP_TYPE_UINT32: 504 | printf("Unsigned Integer: %u\n", obj.as.u32); 505 | break; 506 | case CMP_TYPE_UINT64: 507 | printf("Unsigned Integer: %" PRIu64 "\n", obj.as.u64); 508 | break; 509 | case CMP_TYPE_NEGATIVE_FIXNUM: 510 | case CMP_TYPE_SINT8: 511 | printf("Signed Integer: %d\n", obj.as.s8); 512 | break; 513 | case CMP_TYPE_SINT16: 514 | printf("Signed Integer: %d\n", obj.as.s16); 515 | break; 516 | case CMP_TYPE_SINT32: 517 | printf("Signed Integer: %d\n", obj.as.s32); 518 | break; 519 | case CMP_TYPE_SINT64: 520 | printf("Signed Integer: %" PRId64 "\n", obj.as.s64); 521 | break; 522 | default: 523 | printf("Unrecognized object type %u\n", obj.type); 524 | break; 525 | } 526 | } 527 | 528 | fclose(fh); 529 | 530 | return EXIT_SUCCESS; 531 | } 532 | -------------------------------------------------------------------------------- /cmp.h: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #ifndef CMP_H_INCLUDED 26 | #define CMP_H_INCLUDED 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | struct cmp_ctx_s; 33 | 34 | typedef bool (*cmp_reader)(struct cmp_ctx_s *ctx, void *data, size_t limit); 35 | typedef bool (*cmp_skipper)(struct cmp_ctx_s *ctx, size_t count); 36 | typedef size_t (*cmp_writer)(struct cmp_ctx_s *ctx, const void *data, 37 | size_t count); 38 | 39 | enum { 40 | CMP_TYPE_POSITIVE_FIXNUM, /* 0 */ 41 | CMP_TYPE_FIXMAP, /* 1 */ 42 | CMP_TYPE_FIXARRAY, /* 2 */ 43 | CMP_TYPE_FIXSTR, /* 3 */ 44 | CMP_TYPE_NIL, /* 4 */ 45 | CMP_TYPE_BOOLEAN, /* 5 */ 46 | CMP_TYPE_BIN8, /* 6 */ 47 | CMP_TYPE_BIN16, /* 7 */ 48 | CMP_TYPE_BIN32, /* 8 */ 49 | CMP_TYPE_EXT8, /* 9 */ 50 | CMP_TYPE_EXT16, /* 10 */ 51 | CMP_TYPE_EXT32, /* 11 */ 52 | CMP_TYPE_FLOAT, /* 12 */ 53 | CMP_TYPE_DOUBLE, /* 13 */ 54 | CMP_TYPE_UINT8, /* 14 */ 55 | CMP_TYPE_UINT16, /* 15 */ 56 | CMP_TYPE_UINT32, /* 16 */ 57 | CMP_TYPE_UINT64, /* 17 */ 58 | CMP_TYPE_SINT8, /* 18 */ 59 | CMP_TYPE_SINT16, /* 19 */ 60 | CMP_TYPE_SINT32, /* 20 */ 61 | CMP_TYPE_SINT64, /* 21 */ 62 | CMP_TYPE_FIXEXT1, /* 22 */ 63 | CMP_TYPE_FIXEXT2, /* 23 */ 64 | CMP_TYPE_FIXEXT4, /* 24 */ 65 | CMP_TYPE_FIXEXT8, /* 25 */ 66 | CMP_TYPE_FIXEXT16, /* 26 */ 67 | CMP_TYPE_STR8, /* 27 */ 68 | CMP_TYPE_STR16, /* 28 */ 69 | CMP_TYPE_STR32, /* 29 */ 70 | CMP_TYPE_ARRAY16, /* 30 */ 71 | CMP_TYPE_ARRAY32, /* 31 */ 72 | CMP_TYPE_MAP16, /* 32 */ 73 | CMP_TYPE_MAP32, /* 33 */ 74 | CMP_TYPE_NEGATIVE_FIXNUM /* 34 */ 75 | }; 76 | 77 | typedef struct cmp_ext_s { 78 | int8_t type; 79 | uint32_t size; 80 | } cmp_ext_t; 81 | 82 | union cmp_object_data_u { 83 | bool boolean; 84 | uint8_t u8; 85 | uint16_t u16; 86 | uint32_t u32; 87 | uint64_t u64; 88 | int8_t s8; 89 | int16_t s16; 90 | int32_t s32; 91 | int64_t s64; 92 | #ifndef CMP_NO_FLOAT 93 | float flt; 94 | double dbl; 95 | #endif /* CMP_NO_FLOAT */ 96 | uint32_t array_size; 97 | uint32_t map_size; 98 | uint32_t str_size; 99 | uint32_t bin_size; 100 | cmp_ext_t ext; 101 | }; 102 | 103 | typedef struct cmp_ctx_s { 104 | uint8_t error; 105 | void *buf; 106 | cmp_reader read; 107 | cmp_skipper skip; 108 | cmp_writer write; 109 | } cmp_ctx_t; 110 | 111 | typedef struct cmp_object_s { 112 | uint8_t type; 113 | union cmp_object_data_u as; 114 | } cmp_object_t; 115 | 116 | #ifdef __cplusplus 117 | extern "C" { 118 | #endif 119 | 120 | /* 121 | * ============================================================================ 122 | * === Main API 123 | * ============================================================================ 124 | */ 125 | 126 | /* 127 | * Initializes a CMP context 128 | * 129 | * If you don't intend to read, `read` may be NULL, but calling `*read*` 130 | * functions will crash; there is no check. 131 | * 132 | * `skip` may be NULL, in which case skipping functions will use `read`. 133 | * 134 | * If you don't intend to write, `write` may be NULL, but calling `*write*` 135 | * functions will crash; there is no check. 136 | */ 137 | void cmp_init(cmp_ctx_t *ctx, void *buf, cmp_reader read, 138 | cmp_skipper skip, 139 | cmp_writer write); 140 | 141 | /* Returns CMP's version */ 142 | uint32_t cmp_version(void); 143 | 144 | /* Returns the MessagePack version employed by CMP */ 145 | uint32_t cmp_mp_version(void); 146 | 147 | /* Returns a string description of a CMP context's error */ 148 | const char* cmp_strerror(const cmp_ctx_t *ctx); 149 | 150 | /* Writes a signed integer to the backend */ 151 | bool cmp_write_integer(cmp_ctx_t *ctx, int64_t d); 152 | 153 | /* Writes an unsigned integer to the backend */ 154 | bool cmp_write_uinteger(cmp_ctx_t *ctx, uint64_t u); 155 | 156 | /* 157 | * Writes a floating-point value (either single or double-precision) to the 158 | * backend 159 | */ 160 | #ifndef CMP_NO_FLOAT 161 | bool cmp_write_decimal(cmp_ctx_t *ctx, double d); 162 | #endif /* CMP_NO_FLOAT */ 163 | 164 | /* Writes NULL to the backend */ 165 | bool cmp_write_nil(cmp_ctx_t *ctx); 166 | 167 | /* Writes true to the backend */ 168 | bool cmp_write_true(cmp_ctx_t *ctx); 169 | 170 | /* Writes false to the backend */ 171 | bool cmp_write_false(cmp_ctx_t *ctx); 172 | 173 | /* Writes a boolean value to the backend */ 174 | bool cmp_write_bool(cmp_ctx_t *ctx, bool b); 175 | 176 | /* 177 | * Writes an unsigned char's value to the backend as a boolean. This is useful 178 | * if you are using a different boolean type in your application. 179 | */ 180 | bool cmp_write_u8_as_bool(cmp_ctx_t *ctx, uint8_t b); 181 | 182 | /* 183 | * Writes a string to the backend; according to the MessagePack spec, this must 184 | * be encoded using UTF-8, but CMP leaves that job up to the programmer. 185 | */ 186 | bool cmp_write_str(cmp_ctx_t *ctx, const char *data, uint32_t size); 187 | 188 | /* 189 | * Writes a string to the backend. This avoids using the STR8 marker, which 190 | * is unsupported by MessagePack v4, the version implemented by many other 191 | * MessagePack libraries. No encoding is assumed in this case, not that it 192 | * matters. 193 | */ 194 | bool cmp_write_str_v4(cmp_ctx_t *ctx, const char *data, uint32_t size); 195 | 196 | /* 197 | * Writes the string marker to the backend. This is useful if you are writing 198 | * data in chunks instead of a single shot. 199 | */ 200 | bool cmp_write_str_marker(cmp_ctx_t *ctx, uint32_t size); 201 | 202 | /* 203 | * Writes the string marker to the backend. This is useful if you are writing 204 | * data in chunks instead of a single shot. This avoids using the STR8 205 | * marker, which is unsupported by MessagePack v4, the version implemented by 206 | * many other MessagePack libraries. No encoding is assumed in this case, not 207 | * that it matters. 208 | */ 209 | bool cmp_write_str_marker_v4(cmp_ctx_t *ctx, uint32_t size); 210 | 211 | /* Writes binary data to the backend */ 212 | bool cmp_write_bin(cmp_ctx_t *ctx, const void *data, uint32_t size); 213 | 214 | /* 215 | * Writes the binary data marker to the backend. This is useful if you are 216 | * writing data in chunks instead of a single shot. 217 | */ 218 | bool cmp_write_bin_marker(cmp_ctx_t *ctx, uint32_t size); 219 | 220 | /* Writes an array to the backend. */ 221 | bool cmp_write_array(cmp_ctx_t *ctx, uint32_t size); 222 | 223 | /* Writes a map to the backend. */ 224 | bool cmp_write_map(cmp_ctx_t *ctx, uint32_t size); 225 | 226 | /* Writes an extended type to the backend */ 227 | bool cmp_write_ext(cmp_ctx_t *ctx, int8_t type, uint32_t size, 228 | const void *data); 229 | 230 | /* 231 | * Writes the extended type marker to the backend. This is useful if you want 232 | * to write the type's data in chunks instead of a single shot. 233 | */ 234 | bool cmp_write_ext_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size); 235 | 236 | /* Writes an object to the backend */ 237 | bool cmp_write_object(cmp_ctx_t *ctx, const cmp_object_t *obj); 238 | 239 | /* 240 | * Writes an object to the backend. This avoids using the STR8 marker, which 241 | * is unsupported by MessagePack v4, the version implemented by many other 242 | * MessagePack libraries. 243 | */ 244 | bool cmp_write_object_v4(cmp_ctx_t *ctx, const cmp_object_t *obj); 245 | 246 | /* Reads a signed integer that fits inside a signed char */ 247 | bool cmp_read_char(cmp_ctx_t *ctx, int8_t *c); 248 | 249 | /* Reads a signed integer that fits inside a signed short */ 250 | bool cmp_read_short(cmp_ctx_t *ctx, int16_t *s); 251 | 252 | /* Reads a signed integer that fits inside a signed int */ 253 | bool cmp_read_int(cmp_ctx_t *ctx, int32_t *i); 254 | 255 | /* Reads a signed integer that fits inside a signed long */ 256 | bool cmp_read_long(cmp_ctx_t *ctx, int64_t *d); 257 | 258 | /* Reads a signed integer */ 259 | bool cmp_read_integer(cmp_ctx_t *ctx, int64_t *d); 260 | 261 | /* Reads an unsigned integer that fits inside an unsigned char */ 262 | bool cmp_read_uchar(cmp_ctx_t *ctx, uint8_t *c); 263 | 264 | /* Reads an unsigned integer that fits inside an unsigned short */ 265 | bool cmp_read_ushort(cmp_ctx_t *ctx, uint16_t *s); 266 | 267 | /* Reads an unsigned integer that fits inside an unsigned int */ 268 | bool cmp_read_uint(cmp_ctx_t *ctx, uint32_t *i); 269 | 270 | /* Reads an unsigned integer that fits inside an unsigned long */ 271 | bool cmp_read_ulong(cmp_ctx_t *ctx, uint64_t *u); 272 | 273 | /* Reads an unsigned integer */ 274 | bool cmp_read_uinteger(cmp_ctx_t *ctx, uint64_t *u); 275 | 276 | /* 277 | * Reads a floating point value (either single or double-precision) from the 278 | * backend 279 | */ 280 | #ifndef CMP_NO_FLOAT 281 | bool cmp_read_decimal(cmp_ctx_t *ctx, double *d); 282 | #endif /* CMP_NO_FLOAT */ 283 | 284 | /* "Reads" (more like "skips") a NULL value from the backend */ 285 | bool cmp_read_nil(cmp_ctx_t *ctx); 286 | 287 | /* Reads a boolean from the backend */ 288 | bool cmp_read_bool(cmp_ctx_t *ctx, bool *b); 289 | 290 | /* 291 | * Reads a boolean as an unsigned char from the backend; this is useful if your 292 | * application uses a different boolean type. 293 | */ 294 | bool cmp_read_bool_as_u8(cmp_ctx_t *ctx, uint8_t *b); 295 | 296 | /* Reads a string's size from the backend */ 297 | bool cmp_read_str_size(cmp_ctx_t *ctx, uint32_t *size); 298 | 299 | /* 300 | * Reads a string from the backend; according to the spec, the string's data 301 | * ought to be encoded using UTF-8, but CMP leaves that job up to the programmer. 302 | */ 303 | bool cmp_read_str(cmp_ctx_t *ctx, char *data, uint32_t *size); 304 | 305 | /* Reads the size of packed binary data from the backend */ 306 | bool cmp_read_bin_size(cmp_ctx_t *ctx, uint32_t *size); 307 | 308 | /* Reads packed binary data from the backend */ 309 | bool cmp_read_bin(cmp_ctx_t *ctx, void *data, uint32_t *size); 310 | 311 | /* Reads an array from the backend */ 312 | bool cmp_read_array(cmp_ctx_t *ctx, uint32_t *size); 313 | 314 | /* Reads a map from the backend */ 315 | bool cmp_read_map(cmp_ctx_t *ctx, uint32_t *size); 316 | 317 | /* Reads the extended type's marker from the backend */ 318 | bool cmp_read_ext_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size); 319 | 320 | /* Reads an extended type from the backend */ 321 | bool cmp_read_ext(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data); 322 | 323 | /* Reads an object from the backend */ 324 | bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj); 325 | 326 | /* 327 | * Skips the next object from the backend. If that object is an array or map, 328 | * this function will: 329 | * - If `obj` is not `NULL`, fill in `obj` with that object 330 | * - Set `ctx->error` to `SKIP_DEPTH_LIMIT_EXCEEDED_ERROR` 331 | * - Return `false` 332 | * Otherwise: 333 | * - (Don't touch `obj`) 334 | * - Return `true` 335 | */ 336 | bool cmp_skip_object(cmp_ctx_t *ctx, cmp_object_t *obj); 337 | 338 | /* 339 | * This is similar to `cmp_skip_object`, except it tolerates flat arrays and 340 | * maps. If when skipping such an array or map this function encounters 341 | * another array/map, it will: 342 | * - If `obj` is not `NULL`, fill in `obj` with that (nested) object 343 | * - Set `ctx->error` to `SKIP_DEPTH_LIMIT_EXCEEDED_ERROR` 344 | * - Return `false` 345 | * Otherwise: 346 | * - (Don't touch `obj`) 347 | * - Return `true` 348 | * 349 | * WARNING: This can cause your application to spend an unbounded amount of 350 | * time reading nested data structures. Unless you completely trust 351 | * the data source, you should use `cmp_skip_object`. 352 | */ 353 | bool cmp_skip_object_flat(cmp_ctx_t *ctx, cmp_object_t *obj); 354 | 355 | /* 356 | * This is similar to `cmp_skip_object`, except it will continually skip 357 | * nested data structures. 358 | * 359 | * WARNING: This can cause your application to spend an unbounded amount of 360 | * time reading nested data structures. Unless you completely trust 361 | * the data source, you should use `cmp_skip_object`. 362 | */ 363 | bool cmp_skip_object_no_limit(cmp_ctx_t *ctx); 364 | 365 | /* 366 | * WARNING: THIS FUNCTION IS DEPRECATED AND WILL BE REMOVED IN A FUTURE RELEASE 367 | * 368 | * There is no way to track depths across elements without allocation. For 369 | * example, an array constructed as: `[ [] [] [] [] [] [] [] [] [] [] ]` 370 | * should be able to be skipped with `cmp_skip_object_limit(&cmp, &obj, 2)`. 371 | * However, because we cannot track depth across the elements, there's no way 372 | * to reset it after descending down into each element. 373 | * 374 | * This is similar to `cmp_skip_object`, except it tolerates up to `limit` 375 | * levels of nesting. For example, in order to skip an array that contains a 376 | * map, call `cmp_skip_object_limit(ctx, &obj, 2)`. Or in other words, 377 | * `cmp_skip_object(ctx, &obj)` acts similarly to `cmp_skip_object_limit(ctx, 378 | * &obj, 0)` 379 | * 380 | * Specifically, `limit` refers to depth, not breadth. So in order to skip an 381 | * array that contains two arrays that each contain 3 strings, you would call 382 | * `cmp_skip_object_limit(ctx, &obj, 2). In order to skip an array that 383 | * contains 4 arrays that each contain 1 string, you would still call 384 | * `cmp_skip_object_limit(ctx, &obj, 2). 385 | */ 386 | bool cmp_skip_object_limit(cmp_ctx_t *ctx, cmp_object_t *obj, uint32_t limit) 387 | #ifdef __GNUC__ 388 | __attribute__((deprecated)) 389 | #endif 390 | ; 391 | 392 | #ifdef _MSC_VER 393 | #pragma deprecated(cmp_skip_object_limit) 394 | #endif 395 | 396 | /* 397 | * ============================================================================ 398 | * === Specific API 399 | * ============================================================================ 400 | */ 401 | 402 | bool cmp_write_pfix(cmp_ctx_t *ctx, uint8_t c); 403 | bool cmp_write_nfix(cmp_ctx_t *ctx, int8_t c); 404 | 405 | bool cmp_write_sfix(cmp_ctx_t *ctx, int8_t c); 406 | bool cmp_write_s8(cmp_ctx_t *ctx, int8_t c); 407 | bool cmp_write_s16(cmp_ctx_t *ctx, int16_t s); 408 | bool cmp_write_s32(cmp_ctx_t *ctx, int32_t i); 409 | bool cmp_write_s64(cmp_ctx_t *ctx, int64_t l); 410 | 411 | bool cmp_write_ufix(cmp_ctx_t *ctx, uint8_t c); 412 | bool cmp_write_u8(cmp_ctx_t *ctx, uint8_t c); 413 | bool cmp_write_u16(cmp_ctx_t *ctx, uint16_t s); 414 | bool cmp_write_u32(cmp_ctx_t *ctx, uint32_t i); 415 | bool cmp_write_u64(cmp_ctx_t *ctx, uint64_t l); 416 | 417 | #ifndef CMP_NO_FLOAT 418 | bool cmp_write_float(cmp_ctx_t *ctx, float f); 419 | bool cmp_write_double(cmp_ctx_t *ctx, double d); 420 | #endif /* CMP_NO_FLOAT */ 421 | 422 | bool cmp_write_fixstr_marker(cmp_ctx_t *ctx, uint8_t size); 423 | bool cmp_write_fixstr(cmp_ctx_t *ctx, const char *data, uint8_t size); 424 | bool cmp_write_str8_marker(cmp_ctx_t *ctx, uint8_t size); 425 | bool cmp_write_str8(cmp_ctx_t *ctx, const char *data, uint8_t size); 426 | bool cmp_write_str16_marker(cmp_ctx_t *ctx, uint16_t size); 427 | bool cmp_write_str16(cmp_ctx_t *ctx, const char *data, uint16_t size); 428 | bool cmp_write_str32_marker(cmp_ctx_t *ctx, uint32_t size); 429 | bool cmp_write_str32(cmp_ctx_t *ctx, const char *data, uint32_t size); 430 | 431 | bool cmp_write_bin8_marker(cmp_ctx_t *ctx, uint8_t size); 432 | bool cmp_write_bin8(cmp_ctx_t *ctx, const void *data, uint8_t size); 433 | bool cmp_write_bin16_marker(cmp_ctx_t *ctx, uint16_t size); 434 | bool cmp_write_bin16(cmp_ctx_t *ctx, const void *data, uint16_t size); 435 | bool cmp_write_bin32_marker(cmp_ctx_t *ctx, uint32_t size); 436 | bool cmp_write_bin32(cmp_ctx_t *ctx, const void *data, uint32_t size); 437 | 438 | bool cmp_write_fixarray(cmp_ctx_t *ctx, uint8_t size); 439 | bool cmp_write_array16(cmp_ctx_t *ctx, uint16_t size); 440 | bool cmp_write_array32(cmp_ctx_t *ctx, uint32_t size); 441 | 442 | bool cmp_write_fixmap(cmp_ctx_t *ctx, uint8_t size); 443 | bool cmp_write_map16(cmp_ctx_t *ctx, uint16_t size); 444 | bool cmp_write_map32(cmp_ctx_t *ctx, uint32_t size); 445 | 446 | bool cmp_write_fixext1_marker(cmp_ctx_t *ctx, int8_t type); 447 | bool cmp_write_fixext1(cmp_ctx_t *ctx, int8_t type, const void *data); 448 | bool cmp_write_fixext2_marker(cmp_ctx_t *ctx, int8_t type); 449 | bool cmp_write_fixext2(cmp_ctx_t *ctx, int8_t type, const void *data); 450 | bool cmp_write_fixext4_marker(cmp_ctx_t *ctx, int8_t type); 451 | bool cmp_write_fixext4(cmp_ctx_t *ctx, int8_t type, const void *data); 452 | bool cmp_write_fixext8_marker(cmp_ctx_t *ctx, int8_t type); 453 | bool cmp_write_fixext8(cmp_ctx_t *ctx, int8_t type, const void *data); 454 | bool cmp_write_fixext16_marker(cmp_ctx_t *ctx, int8_t type); 455 | bool cmp_write_fixext16(cmp_ctx_t *ctx, int8_t type, const void *data); 456 | 457 | bool cmp_write_ext8_marker(cmp_ctx_t *ctx, int8_t type, uint8_t size); 458 | bool cmp_write_ext8(cmp_ctx_t *ctx, int8_t type, uint8_t size, 459 | const void *data); 460 | bool cmp_write_ext16_marker(cmp_ctx_t *ctx, int8_t type, uint16_t size); 461 | bool cmp_write_ext16(cmp_ctx_t *ctx, int8_t type, uint16_t size, 462 | const void *data); 463 | bool cmp_write_ext32_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size); 464 | bool cmp_write_ext32(cmp_ctx_t *ctx, int8_t type, uint32_t size, 465 | const void *data); 466 | 467 | bool cmp_read_pfix(cmp_ctx_t *ctx, uint8_t *c); 468 | bool cmp_read_nfix(cmp_ctx_t *ctx, int8_t *c); 469 | 470 | bool cmp_read_sfix(cmp_ctx_t *ctx, int8_t *c); 471 | bool cmp_read_s8(cmp_ctx_t *ctx, int8_t *c); 472 | bool cmp_read_s16(cmp_ctx_t *ctx, int16_t *s); 473 | bool cmp_read_s32(cmp_ctx_t *ctx, int32_t *i); 474 | bool cmp_read_s64(cmp_ctx_t *ctx, int64_t *l); 475 | 476 | bool cmp_read_ufix(cmp_ctx_t *ctx, uint8_t *c); 477 | bool cmp_read_u8(cmp_ctx_t *ctx, uint8_t *c); 478 | bool cmp_read_u16(cmp_ctx_t *ctx, uint16_t *s); 479 | bool cmp_read_u32(cmp_ctx_t *ctx, uint32_t *i); 480 | bool cmp_read_u64(cmp_ctx_t *ctx, uint64_t *l); 481 | 482 | #ifndef CMP_NO_FLOAT 483 | bool cmp_read_float(cmp_ctx_t *ctx, float *f); 484 | bool cmp_read_double(cmp_ctx_t *ctx, double *d); 485 | #endif /* CMP_NO_FLOAT */ 486 | 487 | bool cmp_read_fixext1_marker(cmp_ctx_t *ctx, int8_t *type); 488 | bool cmp_read_fixext1(cmp_ctx_t *ctx, int8_t *type, void *data); 489 | bool cmp_read_fixext2_marker(cmp_ctx_t *ctx, int8_t *type); 490 | bool cmp_read_fixext2(cmp_ctx_t *ctx, int8_t *type, void *data); 491 | bool cmp_read_fixext4_marker(cmp_ctx_t *ctx, int8_t *type); 492 | bool cmp_read_fixext4(cmp_ctx_t *ctx, int8_t *type, void *data); 493 | bool cmp_read_fixext8_marker(cmp_ctx_t *ctx, int8_t *type); 494 | bool cmp_read_fixext8(cmp_ctx_t *ctx, int8_t *type, void *data); 495 | bool cmp_read_fixext16_marker(cmp_ctx_t *ctx, int8_t *type); 496 | bool cmp_read_fixext16(cmp_ctx_t *ctx, int8_t *type, void *data); 497 | 498 | bool cmp_read_ext8_marker(cmp_ctx_t *ctx, int8_t *type, uint8_t *size); 499 | bool cmp_read_ext8(cmp_ctx_t *ctx, int8_t *type, uint8_t *size, void *data); 500 | bool cmp_read_ext16_marker(cmp_ctx_t *ctx, int8_t *type, uint16_t *size); 501 | bool cmp_read_ext16(cmp_ctx_t *ctx, int8_t *type, uint16_t *size, void *data); 502 | bool cmp_read_ext32_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size); 503 | bool cmp_read_ext32(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data); 504 | 505 | /* 506 | * ============================================================================ 507 | * === Object API 508 | * ============================================================================ 509 | */ 510 | 511 | bool cmp_object_is_char(const cmp_object_t *obj); 512 | bool cmp_object_is_short(const cmp_object_t *obj); 513 | bool cmp_object_is_int(const cmp_object_t *obj); 514 | bool cmp_object_is_long(const cmp_object_t *obj); 515 | bool cmp_object_is_sinteger(const cmp_object_t *obj); 516 | bool cmp_object_is_uchar(const cmp_object_t *obj); 517 | bool cmp_object_is_ushort(const cmp_object_t *obj); 518 | bool cmp_object_is_uint(const cmp_object_t *obj); 519 | bool cmp_object_is_ulong(const cmp_object_t *obj); 520 | bool cmp_object_is_uinteger(const cmp_object_t *obj); 521 | bool cmp_object_is_float(const cmp_object_t *obj); 522 | bool cmp_object_is_double(const cmp_object_t *obj); 523 | bool cmp_object_is_nil(const cmp_object_t *obj); 524 | bool cmp_object_is_bool(const cmp_object_t *obj); 525 | bool cmp_object_is_str(const cmp_object_t *obj); 526 | bool cmp_object_is_bin(const cmp_object_t *obj); 527 | bool cmp_object_is_array(const cmp_object_t *obj); 528 | bool cmp_object_is_map(const cmp_object_t *obj); 529 | bool cmp_object_is_ext(const cmp_object_t *obj); 530 | 531 | bool cmp_object_as_char(const cmp_object_t *obj, int8_t *c); 532 | bool cmp_object_as_short(const cmp_object_t *obj, int16_t *s); 533 | bool cmp_object_as_int(const cmp_object_t *obj, int32_t *i); 534 | bool cmp_object_as_long(const cmp_object_t *obj, int64_t *d); 535 | bool cmp_object_as_sinteger(const cmp_object_t *obj, int64_t *d); 536 | bool cmp_object_as_uchar(const cmp_object_t *obj, uint8_t *c); 537 | bool cmp_object_as_ushort(const cmp_object_t *obj, uint16_t *s); 538 | bool cmp_object_as_uint(const cmp_object_t *obj, uint32_t *i); 539 | bool cmp_object_as_ulong(const cmp_object_t *obj, uint64_t *u); 540 | bool cmp_object_as_uinteger(const cmp_object_t *obj, uint64_t *u); 541 | bool cmp_object_as_float(const cmp_object_t *obj, float *f); 542 | bool cmp_object_as_double(const cmp_object_t *obj, double *d); 543 | bool cmp_object_as_bool(const cmp_object_t *obj, bool *b); 544 | bool cmp_object_as_str(const cmp_object_t *obj, uint32_t *size); 545 | bool cmp_object_as_bin(const cmp_object_t *obj, uint32_t *size); 546 | bool cmp_object_as_array(const cmp_object_t *obj, uint32_t *size); 547 | bool cmp_object_as_map(const cmp_object_t *obj, uint32_t *size); 548 | bool cmp_object_as_ext(const cmp_object_t *obj, int8_t *type, uint32_t *size); 549 | 550 | bool cmp_object_to_str(cmp_ctx_t *ctx, const cmp_object_t *obj, char *data, uint32_t buf_size); 551 | bool cmp_object_to_bin(cmp_ctx_t *ctx, const cmp_object_t *obj, void *data, uint32_t buf_size); 552 | 553 | #ifdef __cplusplus 554 | } /* extern "C" */ 555 | #endif 556 | 557 | /* 558 | * ============================================================================ 559 | * === Backwards compatibility defines 560 | * ============================================================================ 561 | */ 562 | 563 | #define cmp_write_int cmp_write_integer 564 | #define cmp_write_sint cmp_write_integer 565 | #define cmp_write_sinteger cmp_write_integer 566 | #define cmp_write_uint cmp_write_uinteger 567 | #define cmp_read_sinteger cmp_read_integer 568 | 569 | #endif /* CMP_H_INCLUDED */ 570 | 571 | /* vi: set et ts=2 sw=2: */ 572 | 573 | -------------------------------------------------------------------------------- /cmp.c: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 Charles Gunyon 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | */ 24 | 25 | #include "cmp.h" 26 | 27 | static const uint32_t cmp_version_ = 20; 28 | static const uint32_t cmp_mp_version_ = 5; 29 | 30 | enum { 31 | POSITIVE_FIXNUM_MARKER = 0x00, 32 | FIXMAP_MARKER = 0x80, 33 | FIXARRAY_MARKER = 0x90, 34 | FIXSTR_MARKER = 0xA0, 35 | NIL_MARKER = 0xC0, 36 | FALSE_MARKER = 0xC2, 37 | TRUE_MARKER = 0xC3, 38 | BIN8_MARKER = 0xC4, 39 | BIN16_MARKER = 0xC5, 40 | BIN32_MARKER = 0xC6, 41 | EXT8_MARKER = 0xC7, 42 | EXT16_MARKER = 0xC8, 43 | EXT32_MARKER = 0xC9, 44 | FLOAT_MARKER = 0xCA, 45 | DOUBLE_MARKER = 0xCB, 46 | U8_MARKER = 0xCC, 47 | U16_MARKER = 0xCD, 48 | U32_MARKER = 0xCE, 49 | U64_MARKER = 0xCF, 50 | S8_MARKER = 0xD0, 51 | S16_MARKER = 0xD1, 52 | S32_MARKER = 0xD2, 53 | S64_MARKER = 0xD3, 54 | FIXEXT1_MARKER = 0xD4, 55 | FIXEXT2_MARKER = 0xD5, 56 | FIXEXT4_MARKER = 0xD6, 57 | FIXEXT8_MARKER = 0xD7, 58 | FIXEXT16_MARKER = 0xD8, 59 | STR8_MARKER = 0xD9, 60 | STR16_MARKER = 0xDA, 61 | STR32_MARKER = 0xDB, 62 | ARRAY16_MARKER = 0xDC, 63 | ARRAY32_MARKER = 0xDD, 64 | MAP16_MARKER = 0xDE, 65 | MAP32_MARKER = 0xDF, 66 | NEGATIVE_FIXNUM_MARKER = 0xE0 67 | }; 68 | 69 | enum { 70 | FIXARRAY_SIZE = 0xF, 71 | FIXMAP_SIZE = 0xF, 72 | FIXSTR_SIZE = 0x1F 73 | }; 74 | 75 | typedef enum cmp_error_e { 76 | CMP_ERROR_NONE, 77 | CMP_ERROR_STR_DATA_LENGTH_TOO_LONG, 78 | CMP_ERROR_BIN_DATA_LENGTH_TOO_LONG, 79 | CMP_ERROR_ARRAY_LENGTH_TOO_LONG, 80 | CMP_ERROR_MAP_LENGTH_TOO_LONG, 81 | CMP_ERROR_INPUT_VALUE_TOO_LARGE, 82 | CMP_ERROR_FIXED_VALUE_WRITING, 83 | CMP_ERROR_TYPE_MARKER_READING, 84 | CMP_ERROR_TYPE_MARKER_WRITING, 85 | CMP_ERROR_DATA_READING, 86 | CMP_ERROR_DATA_WRITING, 87 | CMP_ERROR_EXT_TYPE_READING, 88 | CMP_ERROR_EXT_TYPE_WRITING, 89 | CMP_ERROR_INVALID_TYPE, 90 | CMP_ERROR_LENGTH_READING, 91 | CMP_ERROR_LENGTH_WRITING, 92 | CMP_ERROR_SKIP_DEPTH_LIMIT_EXCEEDED, 93 | CMP_ERROR_INTERNAL, 94 | CMP_ERROR_DISABLED_FLOATING_POINT, 95 | CMP_ERROR_MAX 96 | } cmp_error_t; 97 | 98 | static const char *cmp_error_message(cmp_error_t error) { 99 | switch (error) { 100 | case CMP_ERROR_NONE: return "No Error"; 101 | case CMP_ERROR_STR_DATA_LENGTH_TOO_LONG: return "Specified string data length is too long (> 0xFFFFFFFF)"; 102 | case CMP_ERROR_BIN_DATA_LENGTH_TOO_LONG: return "Specified binary data length is too long (> 0xFFFFFFFF)"; 103 | case CMP_ERROR_ARRAY_LENGTH_TOO_LONG: return "Specified array length is too long (> 0xFFFFFFFF)"; 104 | case CMP_ERROR_MAP_LENGTH_TOO_LONG: return "Specified map length is too long (> 0xFFFFFFFF)"; 105 | case CMP_ERROR_INPUT_VALUE_TOO_LARGE: return "Input value is too large"; 106 | case CMP_ERROR_FIXED_VALUE_WRITING: return "Error writing fixed value"; 107 | case CMP_ERROR_TYPE_MARKER_READING: return "Error reading type marker"; 108 | case CMP_ERROR_TYPE_MARKER_WRITING: return "Error writing type marker"; 109 | case CMP_ERROR_DATA_READING: return "Error reading packed data"; 110 | case CMP_ERROR_DATA_WRITING: return "Error writing packed data"; 111 | case CMP_ERROR_EXT_TYPE_READING: return "Error reading ext type"; 112 | case CMP_ERROR_EXT_TYPE_WRITING: return "Error writing ext type"; 113 | case CMP_ERROR_INVALID_TYPE: return "Invalid type"; 114 | case CMP_ERROR_LENGTH_READING: return "Error reading size"; 115 | case CMP_ERROR_LENGTH_WRITING: return "Error writing size"; 116 | case CMP_ERROR_SKIP_DEPTH_LIMIT_EXCEEDED: return "Depth limit exceeded while skipping"; 117 | case CMP_ERROR_INTERNAL: return "Internal error"; 118 | case CMP_ERROR_DISABLED_FLOATING_POINT: return "Floating point operations disabled"; 119 | case CMP_ERROR_MAX: return "Max Error"; 120 | } 121 | return ""; 122 | } 123 | 124 | static bool is_bigendian(void) { 125 | #ifdef WORDS_BIGENDIAN 126 | return WORDS_BIGENDIAN; 127 | #else 128 | const int32_t one = 1; 129 | const char *one_bytes = (const char *)&one; 130 | return *one_bytes == 0; 131 | #endif 132 | } 133 | 134 | static uint16_t be16(uint16_t x) { 135 | if (!is_bigendian()) 136 | return ((x >> 8) & 0x00ff) 137 | | ((x << 8) & 0xff00); 138 | 139 | return x; 140 | } 141 | 142 | static int16_t sbe16(int16_t x) { 143 | return (int16_t)be16((uint16_t)x); 144 | } 145 | 146 | static uint32_t be32(uint32_t x) { 147 | if (!is_bigendian()) 148 | return ((uint32_t)be16((uint16_t)(x >> 16))) 149 | | ((uint32_t)be16((uint16_t)(x & 0xffff)) << 16); 150 | 151 | return x; 152 | } 153 | 154 | static int32_t sbe32(int32_t x) { 155 | return (int32_t)be32((uint32_t)x); 156 | } 157 | 158 | static uint64_t be64(uint64_t x) { 159 | if (!is_bigendian()) 160 | return ((uint64_t)be32((uint32_t)(x >> 32))) 161 | | ((uint64_t)be32((uint32_t)(x & 0xffffffff)) << 32); 162 | 163 | return x; 164 | } 165 | 166 | static int64_t sbe64(int64_t x) { 167 | return (int64_t)be64((uint64_t)x); 168 | } 169 | 170 | #ifndef CMP_NO_FLOAT 171 | static float decode_befloat(const char *b) { 172 | float f = 0.; 173 | char *fb = (char *)&f; 174 | 175 | if (!is_bigendian()) { 176 | fb[0] = b[3]; 177 | fb[1] = b[2]; 178 | fb[2] = b[1]; 179 | fb[3] = b[0]; 180 | } 181 | else { 182 | fb[0] = b[0]; 183 | fb[1] = b[1]; 184 | fb[2] = b[2]; 185 | fb[3] = b[3]; 186 | } 187 | 188 | return f; 189 | } 190 | 191 | static double decode_bedouble(const char *b) { 192 | double d = 0.; 193 | char *db = (char *)&d; 194 | 195 | if (!is_bigendian()) { 196 | db[0] = b[7]; 197 | db[1] = b[6]; 198 | db[2] = b[5]; 199 | db[3] = b[4]; 200 | db[4] = b[3]; 201 | db[5] = b[2]; 202 | db[6] = b[1]; 203 | db[7] = b[0]; 204 | } 205 | else { 206 | db[0] = b[0]; 207 | db[1] = b[1]; 208 | db[2] = b[2]; 209 | db[3] = b[3]; 210 | db[4] = b[4]; 211 | db[5] = b[5]; 212 | db[6] = b[6]; 213 | db[7] = b[7]; 214 | } 215 | 216 | return d; 217 | } 218 | #endif /* CMP_NO_FLOAT */ 219 | 220 | static bool read_byte(cmp_ctx_t *ctx, uint8_t *x) { 221 | return ctx->read(ctx, x, sizeof(uint8_t)); 222 | } 223 | 224 | static bool write_byte(cmp_ctx_t *ctx, uint8_t x) { 225 | return ctx->write(ctx, &x, sizeof(uint8_t)) == sizeof(uint8_t); 226 | } 227 | 228 | static bool skip_bytes(cmp_ctx_t *ctx, size_t count) { 229 | if (ctx->skip) { 230 | return ctx->skip(ctx, count); 231 | } 232 | else { 233 | size_t i; 234 | 235 | for (i = 0; i < count; ++i) { 236 | uint8_t floor; 237 | if (!ctx->read(ctx, &floor, sizeof(uint8_t))) { 238 | return false; 239 | } 240 | } 241 | 242 | return true; 243 | } 244 | } 245 | 246 | static bool read_type_marker(cmp_ctx_t *ctx, uint8_t *marker) { 247 | if (read_byte(ctx, marker)) { 248 | return true; 249 | } 250 | 251 | ctx->error = CMP_ERROR_TYPE_MARKER_READING; 252 | return false; 253 | } 254 | 255 | static bool write_type_marker(cmp_ctx_t *ctx, uint8_t marker) { 256 | if (write_byte(ctx, marker)) 257 | return true; 258 | 259 | ctx->error = CMP_ERROR_TYPE_MARKER_WRITING; 260 | return false; 261 | } 262 | 263 | static bool write_fixed_value(cmp_ctx_t *ctx, uint8_t value) { 264 | if (write_byte(ctx, value)) 265 | return true; 266 | 267 | ctx->error = CMP_ERROR_FIXED_VALUE_WRITING; 268 | return false; 269 | } 270 | 271 | static bool type_marker_to_cmp_type(uint8_t type_marker, uint8_t *cmp_type) { 272 | if (type_marker <= 0x7F) { 273 | *cmp_type = CMP_TYPE_POSITIVE_FIXNUM; 274 | return true; 275 | } 276 | 277 | if (type_marker <= 0x8F) { 278 | *cmp_type = CMP_TYPE_FIXMAP; 279 | return true; 280 | } 281 | 282 | if (type_marker <= 0x9F) { 283 | *cmp_type = CMP_TYPE_FIXARRAY; 284 | return true; 285 | } 286 | 287 | if (type_marker <= 0xBF) { 288 | *cmp_type = CMP_TYPE_FIXSTR; 289 | return true; 290 | } 291 | 292 | if (type_marker >= 0xE0) { 293 | *cmp_type = CMP_TYPE_NEGATIVE_FIXNUM; 294 | return true; 295 | } 296 | 297 | switch (type_marker) { 298 | case NIL_MARKER: 299 | *cmp_type = CMP_TYPE_NIL; 300 | return true; 301 | case FALSE_MARKER: 302 | *cmp_type = CMP_TYPE_BOOLEAN; 303 | return true; 304 | case TRUE_MARKER: 305 | *cmp_type = CMP_TYPE_BOOLEAN; 306 | return true; 307 | case BIN8_MARKER: 308 | *cmp_type = CMP_TYPE_BIN8; 309 | return true; 310 | case BIN16_MARKER: 311 | *cmp_type = CMP_TYPE_BIN16; 312 | return true; 313 | case BIN32_MARKER: 314 | *cmp_type = CMP_TYPE_BIN32; 315 | return true; 316 | case EXT8_MARKER: 317 | *cmp_type = CMP_TYPE_EXT8; 318 | return true; 319 | case EXT16_MARKER: 320 | *cmp_type = CMP_TYPE_EXT16; 321 | return true; 322 | case EXT32_MARKER: 323 | *cmp_type = CMP_TYPE_EXT32; 324 | return true; 325 | case FLOAT_MARKER: 326 | *cmp_type = CMP_TYPE_FLOAT; 327 | return true; 328 | case DOUBLE_MARKER: 329 | *cmp_type = CMP_TYPE_DOUBLE; 330 | return true; 331 | case U8_MARKER: 332 | *cmp_type = CMP_TYPE_UINT8; 333 | return true; 334 | case U16_MARKER: 335 | *cmp_type = CMP_TYPE_UINT16; 336 | return true; 337 | case U32_MARKER: 338 | *cmp_type = CMP_TYPE_UINT32; 339 | return true; 340 | case U64_MARKER: 341 | *cmp_type = CMP_TYPE_UINT64; 342 | return true; 343 | case S8_MARKER: 344 | *cmp_type = CMP_TYPE_SINT8; 345 | return true; 346 | case S16_MARKER: 347 | *cmp_type = CMP_TYPE_SINT16; 348 | return true; 349 | case S32_MARKER: 350 | *cmp_type = CMP_TYPE_SINT32; 351 | return true; 352 | case S64_MARKER: 353 | *cmp_type = CMP_TYPE_SINT64; 354 | return true; 355 | case FIXEXT1_MARKER: 356 | *cmp_type = CMP_TYPE_FIXEXT1; 357 | return true; 358 | case FIXEXT2_MARKER: 359 | *cmp_type = CMP_TYPE_FIXEXT2; 360 | return true; 361 | case FIXEXT4_MARKER: 362 | *cmp_type = CMP_TYPE_FIXEXT4; 363 | return true; 364 | case FIXEXT8_MARKER: 365 | *cmp_type = CMP_TYPE_FIXEXT8; 366 | return true; 367 | case FIXEXT16_MARKER: 368 | *cmp_type = CMP_TYPE_FIXEXT16; 369 | return true; 370 | case STR8_MARKER: 371 | *cmp_type = CMP_TYPE_STR8; 372 | return true; 373 | case STR16_MARKER: 374 | *cmp_type = CMP_TYPE_STR16; 375 | return true; 376 | case STR32_MARKER: 377 | *cmp_type = CMP_TYPE_STR32; 378 | return true; 379 | case ARRAY16_MARKER: 380 | *cmp_type = CMP_TYPE_ARRAY16; 381 | return true; 382 | case ARRAY32_MARKER: 383 | *cmp_type = CMP_TYPE_ARRAY32; 384 | return true; 385 | case MAP16_MARKER: 386 | *cmp_type = CMP_TYPE_MAP16; 387 | return true; 388 | case MAP32_MARKER: 389 | *cmp_type = CMP_TYPE_MAP32; 390 | return true; 391 | default: 392 | return false; 393 | } 394 | } 395 | 396 | static bool read_type_size(cmp_ctx_t *ctx, uint8_t type_marker, 397 | uint8_t cmp_type, 398 | uint32_t *size) { 399 | uint8_t u8temp = 0; 400 | uint16_t u16temp = 0; 401 | uint32_t u32temp = 0; 402 | 403 | switch (cmp_type) { 404 | case CMP_TYPE_POSITIVE_FIXNUM: 405 | *size = 0; 406 | return true; 407 | case CMP_TYPE_FIXMAP: 408 | *size = (type_marker & FIXMAP_SIZE); 409 | return true; 410 | case CMP_TYPE_FIXARRAY: 411 | *size = (type_marker & FIXARRAY_SIZE); 412 | return true; 413 | case CMP_TYPE_FIXSTR: 414 | *size = (type_marker & FIXSTR_SIZE); 415 | return true; 416 | case CMP_TYPE_NIL: 417 | *size = 0; 418 | return true; 419 | case CMP_TYPE_BOOLEAN: 420 | *size = 0; 421 | return true; 422 | case CMP_TYPE_BIN8: 423 | if (!ctx->read(ctx, &u8temp, sizeof(uint8_t))) { 424 | ctx->error = CMP_ERROR_LENGTH_READING; 425 | return false; 426 | } 427 | *size = u8temp; 428 | return true; 429 | case CMP_TYPE_BIN16: 430 | if (!ctx->read(ctx, &u16temp, sizeof(uint16_t))) { 431 | ctx->error = CMP_ERROR_LENGTH_READING; 432 | return false; 433 | } 434 | *size = be16(u16temp); 435 | return true; 436 | case CMP_TYPE_BIN32: 437 | if (!ctx->read(ctx, &u32temp, sizeof(uint32_t))) { 438 | ctx->error = CMP_ERROR_LENGTH_READING; 439 | return false; 440 | } 441 | *size = be32(u32temp); 442 | return true; 443 | case CMP_TYPE_EXT8: 444 | if (!ctx->read(ctx, &u8temp, sizeof(uint8_t))) { 445 | ctx->error = CMP_ERROR_LENGTH_READING; 446 | return false; 447 | } 448 | *size = u8temp; 449 | return true; 450 | case CMP_TYPE_EXT16: 451 | if (!ctx->read(ctx, &u16temp, sizeof(uint16_t))) { 452 | ctx->error = CMP_ERROR_LENGTH_READING; 453 | return false; 454 | } 455 | *size = be16(u16temp); 456 | return true; 457 | case CMP_TYPE_EXT32: 458 | if (!ctx->read(ctx, &u32temp, sizeof(uint32_t))) { 459 | ctx->error = CMP_ERROR_LENGTH_READING; 460 | return false; 461 | } 462 | *size = be32(u32temp); 463 | return true; 464 | case CMP_TYPE_FLOAT: 465 | *size = 4; 466 | return true; 467 | case CMP_TYPE_DOUBLE: 468 | *size = 8; 469 | return true; 470 | case CMP_TYPE_UINT8: 471 | *size = 1; 472 | return true; 473 | case CMP_TYPE_UINT16: 474 | *size = 2; 475 | return true; 476 | case CMP_TYPE_UINT32: 477 | *size = 4; 478 | return true; 479 | case CMP_TYPE_UINT64: 480 | *size = 8; 481 | return true; 482 | case CMP_TYPE_SINT8: 483 | *size = 1; 484 | return true; 485 | case CMP_TYPE_SINT16: 486 | *size = 2; 487 | return true; 488 | case CMP_TYPE_SINT32: 489 | *size = 4; 490 | return true; 491 | case CMP_TYPE_SINT64: 492 | *size = 8; 493 | return true; 494 | case CMP_TYPE_FIXEXT1: 495 | *size = 1; 496 | return true; 497 | case CMP_TYPE_FIXEXT2: 498 | *size = 2; 499 | return true; 500 | case CMP_TYPE_FIXEXT4: 501 | *size = 4; 502 | return true; 503 | case CMP_TYPE_FIXEXT8: 504 | *size = 8; 505 | return true; 506 | case CMP_TYPE_FIXEXT16: 507 | *size = 16; 508 | return true; 509 | case CMP_TYPE_STR8: 510 | if (!ctx->read(ctx, &u8temp, sizeof(uint8_t))) { 511 | ctx->error = CMP_ERROR_DATA_READING; 512 | return false; 513 | } 514 | *size = u8temp; 515 | return true; 516 | case CMP_TYPE_STR16: 517 | if (!ctx->read(ctx, &u16temp, sizeof(uint16_t))) { 518 | ctx->error = CMP_ERROR_DATA_READING; 519 | return false; 520 | } 521 | *size = be16(u16temp); 522 | return true; 523 | case CMP_TYPE_STR32: 524 | if (!ctx->read(ctx, &u32temp, sizeof(uint32_t))) { 525 | ctx->error = CMP_ERROR_DATA_READING; 526 | return false; 527 | } 528 | *size = be32(u32temp); 529 | return true; 530 | case CMP_TYPE_ARRAY16: 531 | if (!ctx->read(ctx, &u16temp, sizeof(uint16_t))) { 532 | ctx->error = CMP_ERROR_DATA_READING; 533 | return false; 534 | } 535 | *size = be16(u16temp); 536 | return true; 537 | case CMP_TYPE_ARRAY32: 538 | if (!ctx->read(ctx, &u32temp, sizeof(uint32_t))) { 539 | ctx->error = CMP_ERROR_DATA_READING; 540 | return false; 541 | } 542 | *size = be32(u32temp); 543 | return true; 544 | case CMP_TYPE_MAP16: 545 | if (!ctx->read(ctx, &u16temp, sizeof(uint16_t))) { 546 | ctx->error = CMP_ERROR_DATA_READING; 547 | return false; 548 | } 549 | *size = be16(u16temp); 550 | return true; 551 | case CMP_TYPE_MAP32: 552 | if (!ctx->read(ctx, &u32temp, sizeof(uint32_t))) { 553 | ctx->error = CMP_ERROR_DATA_READING; 554 | return false; 555 | } 556 | *size = be32(u32temp); 557 | return true; 558 | case CMP_TYPE_NEGATIVE_FIXNUM: 559 | *size = 0; 560 | return true; 561 | default: 562 | ctx->error = CMP_ERROR_INVALID_TYPE; 563 | return false; 564 | } 565 | } 566 | 567 | static bool read_obj_data(cmp_ctx_t *ctx, uint8_t type_marker, 568 | cmp_object_t *obj) { 569 | switch (obj->type) { 570 | case CMP_TYPE_POSITIVE_FIXNUM: 571 | obj->as.u8 = type_marker; 572 | return true; 573 | case CMP_TYPE_NEGATIVE_FIXNUM: 574 | obj->as.s8 = (int8_t)type_marker; 575 | return true; 576 | case CMP_TYPE_NIL: 577 | obj->as.u8 = 0; 578 | return true; 579 | case CMP_TYPE_BOOLEAN: 580 | switch (type_marker) { 581 | case TRUE_MARKER: 582 | obj->as.boolean = true; 583 | return true; 584 | case FALSE_MARKER: 585 | obj->as.boolean = false; 586 | return true; 587 | default: 588 | break; 589 | } 590 | ctx->error = CMP_ERROR_INTERNAL; 591 | return false; 592 | case CMP_TYPE_UINT8: 593 | if (!ctx->read(ctx, &obj->as.u8, sizeof(uint8_t))) { 594 | ctx->error = CMP_ERROR_DATA_READING; 595 | return false; 596 | } 597 | return true; 598 | case CMP_TYPE_UINT16: 599 | if (!ctx->read(ctx, &obj->as.u16, sizeof(uint16_t))) { 600 | ctx->error = CMP_ERROR_DATA_READING; 601 | return false; 602 | } 603 | obj->as.u16 = be16(obj->as.u16); 604 | return true; 605 | case CMP_TYPE_UINT32: 606 | if (!ctx->read(ctx, &obj->as.u32, sizeof(uint32_t))) { 607 | ctx->error = CMP_ERROR_DATA_READING; 608 | return false; 609 | } 610 | obj->as.u32 = be32(obj->as.u32); 611 | return true; 612 | case CMP_TYPE_UINT64: 613 | if (!ctx->read(ctx, &obj->as.u64, sizeof(uint64_t))) { 614 | ctx->error = CMP_ERROR_DATA_READING; 615 | return false; 616 | } 617 | obj->as.u64 = be64(obj->as.u64); 618 | return true; 619 | case CMP_TYPE_SINT8: 620 | if (!ctx->read(ctx, &obj->as.s8, sizeof(int8_t))) { 621 | ctx->error = CMP_ERROR_DATA_READING; 622 | return false; 623 | } 624 | return true; 625 | case CMP_TYPE_SINT16: 626 | if (!ctx->read(ctx, &obj->as.s16, sizeof(int16_t))) { 627 | ctx->error = CMP_ERROR_DATA_READING; 628 | return false; 629 | } 630 | obj->as.s16 = sbe16(obj->as.s16); 631 | return true; 632 | case CMP_TYPE_SINT32: 633 | if (!ctx->read(ctx, &obj->as.s32, sizeof(int32_t))) { 634 | ctx->error = CMP_ERROR_DATA_READING; 635 | return false; 636 | } 637 | obj->as.s32 = sbe32(obj->as.s32); 638 | return true; 639 | case CMP_TYPE_SINT64: 640 | if (!ctx->read(ctx, &obj->as.s64, sizeof(int64_t))) { 641 | ctx->error = CMP_ERROR_DATA_READING; 642 | return false; 643 | } 644 | obj->as.s64 = sbe64(obj->as.s64); 645 | return true; 646 | case CMP_TYPE_FLOAT: 647 | { 648 | #ifndef CMP_NO_FLOAT 649 | char bytes[4]; 650 | 651 | if (!ctx->read(ctx, bytes, 4)) { 652 | ctx->error = CMP_ERROR_DATA_READING; 653 | return false; 654 | } 655 | obj->as.flt = decode_befloat(bytes); 656 | return true; 657 | #else /* CMP_NO_FLOAT */ 658 | ctx->error = CMP_ERROR_DISABLED_FLOATING_POINT; 659 | return false; 660 | #endif /* CMP_NO_FLOAT */ 661 | } 662 | case CMP_TYPE_DOUBLE: 663 | { 664 | #ifndef CMP_NO_FLOAT 665 | char bytes[8]; 666 | 667 | if (!ctx->read(ctx, bytes, 8)) { 668 | ctx->error = CMP_ERROR_DATA_READING; 669 | return false; 670 | } 671 | obj->as.dbl = decode_bedouble(bytes); 672 | return true; 673 | #else /* CMP_NO_FLOAT */ 674 | ctx->error = CMP_ERROR_DISABLED_FLOATING_POINT; 675 | return false; 676 | #endif /* CMP_NO_FLOAT */ 677 | } 678 | case CMP_TYPE_BIN8: 679 | case CMP_TYPE_BIN16: 680 | case CMP_TYPE_BIN32: 681 | return read_type_size(ctx, type_marker, obj->type, &obj->as.bin_size); 682 | case CMP_TYPE_FIXSTR: 683 | case CMP_TYPE_STR8: 684 | case CMP_TYPE_STR16: 685 | case CMP_TYPE_STR32: 686 | return read_type_size(ctx, type_marker, obj->type, &obj->as.str_size); 687 | case CMP_TYPE_FIXARRAY: 688 | case CMP_TYPE_ARRAY16: 689 | case CMP_TYPE_ARRAY32: 690 | return read_type_size(ctx, type_marker, obj->type, &obj->as.array_size); 691 | case CMP_TYPE_FIXMAP: 692 | case CMP_TYPE_MAP16: 693 | case CMP_TYPE_MAP32: 694 | return read_type_size(ctx, type_marker, obj->type, &obj->as.map_size); 695 | case CMP_TYPE_FIXEXT1: 696 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 697 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 698 | return false; 699 | } 700 | obj->as.ext.size = 1; 701 | return true; 702 | case CMP_TYPE_FIXEXT2: 703 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 704 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 705 | return false; 706 | } 707 | obj->as.ext.size = 2; 708 | return true; 709 | case CMP_TYPE_FIXEXT4: 710 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 711 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 712 | return false; 713 | } 714 | obj->as.ext.size = 4; 715 | return true; 716 | case CMP_TYPE_FIXEXT8: 717 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 718 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 719 | return false; 720 | } 721 | obj->as.ext.size = 8; 722 | return true; 723 | case CMP_TYPE_FIXEXT16: 724 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 725 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 726 | return false; 727 | } 728 | obj->as.ext.size = 16; 729 | return true; 730 | case CMP_TYPE_EXT8: 731 | if (!read_type_size(ctx, type_marker, obj->type, &obj->as.ext.size)) { 732 | return false; 733 | } 734 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 735 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 736 | return false; 737 | } 738 | return true; 739 | case CMP_TYPE_EXT16: 740 | if (!read_type_size(ctx, type_marker, obj->type, &obj->as.ext.size)) { 741 | return false; 742 | } 743 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 744 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 745 | return false; 746 | } 747 | return true; 748 | case CMP_TYPE_EXT32: 749 | if (!read_type_size(ctx, type_marker, obj->type, &obj->as.ext.size)) { 750 | return false; 751 | } 752 | if (!ctx->read(ctx, &obj->as.ext.type, sizeof(int8_t))) { 753 | ctx->error = CMP_ERROR_EXT_TYPE_READING; 754 | return false; 755 | } 756 | return true; 757 | default: 758 | break; 759 | } 760 | 761 | ctx->error = CMP_ERROR_INVALID_TYPE; 762 | return false; 763 | } 764 | 765 | void cmp_init(cmp_ctx_t *ctx, void *buf, cmp_reader read, 766 | cmp_skipper skip, 767 | cmp_writer write) { 768 | ctx->error = CMP_ERROR_NONE; 769 | ctx->buf = buf; 770 | ctx->read = read; 771 | ctx->skip = skip; 772 | ctx->write = write; 773 | } 774 | 775 | uint32_t cmp_version(void) { 776 | return cmp_version_; 777 | } 778 | 779 | uint32_t cmp_mp_version(void) { 780 | return cmp_mp_version_; 781 | } 782 | 783 | const char* cmp_strerror(const cmp_ctx_t *ctx) { 784 | if (ctx->error > CMP_ERROR_NONE && ctx->error < CMP_ERROR_MAX) 785 | return cmp_error_message((cmp_error_t)ctx->error); 786 | 787 | return ""; 788 | } 789 | 790 | bool cmp_write_pfix(cmp_ctx_t *ctx, uint8_t c) { 791 | if (c <= 0x7F) 792 | return write_fixed_value(ctx, c); 793 | 794 | ctx->error = CMP_ERROR_INPUT_VALUE_TOO_LARGE; 795 | return false; 796 | } 797 | 798 | bool cmp_write_nfix(cmp_ctx_t *ctx, int8_t c) { 799 | if (c >= -0x20 && c <= -1) 800 | return write_fixed_value(ctx, (uint8_t)c); 801 | 802 | ctx->error = CMP_ERROR_INPUT_VALUE_TOO_LARGE; 803 | return false; 804 | } 805 | 806 | bool cmp_write_sfix(cmp_ctx_t *ctx, int8_t c) { 807 | if (c >= 0) 808 | return cmp_write_pfix(ctx, (uint8_t)c); 809 | if (c >= -0x20 && c <= -1) 810 | return cmp_write_nfix(ctx, c); 811 | 812 | ctx->error = CMP_ERROR_INPUT_VALUE_TOO_LARGE; 813 | return false; 814 | } 815 | 816 | bool cmp_write_s8(cmp_ctx_t *ctx, int8_t c) { 817 | if (!write_type_marker(ctx, S8_MARKER)) 818 | return false; 819 | 820 | return ctx->write(ctx, &c, sizeof(int8_t)) == sizeof(int8_t); 821 | } 822 | 823 | bool cmp_write_s16(cmp_ctx_t *ctx, int16_t s) { 824 | if (!write_type_marker(ctx, S16_MARKER)) 825 | return false; 826 | 827 | s = sbe16(s); 828 | 829 | return ctx->write(ctx, &s, sizeof(int16_t)) == sizeof(int16_t); 830 | } 831 | 832 | bool cmp_write_s32(cmp_ctx_t *ctx, int32_t i) { 833 | if (!write_type_marker(ctx, S32_MARKER)) 834 | return false; 835 | 836 | i = sbe32(i); 837 | 838 | return ctx->write(ctx, &i, sizeof(int32_t)) == sizeof(int32_t); 839 | } 840 | 841 | bool cmp_write_s64(cmp_ctx_t *ctx, int64_t l) { 842 | if (!write_type_marker(ctx, S64_MARKER)) 843 | return false; 844 | 845 | l = sbe64(l); 846 | 847 | return ctx->write(ctx, &l, sizeof(int64_t)) == sizeof(int64_t); 848 | } 849 | 850 | bool cmp_write_integer(cmp_ctx_t *ctx, int64_t d) { 851 | if (d >= 0) 852 | return cmp_write_uinteger(ctx, (uint64_t)d); 853 | if (d >= -0x20) 854 | return cmp_write_nfix(ctx, (int8_t)d); 855 | if (d >= -0x80) 856 | return cmp_write_s8(ctx, (int8_t)d); 857 | if (d >= -0x8000) 858 | return cmp_write_s16(ctx, (int16_t)d); 859 | if (d >= -INT64_C(0x80000000)) 860 | return cmp_write_s32(ctx, (int32_t)d); 861 | 862 | return cmp_write_s64(ctx, d); 863 | } 864 | 865 | bool cmp_write_ufix(cmp_ctx_t *ctx, uint8_t c) { 866 | return cmp_write_pfix(ctx, c); 867 | } 868 | 869 | bool cmp_write_u8(cmp_ctx_t *ctx, uint8_t c) { 870 | if (!write_type_marker(ctx, U8_MARKER)) 871 | return false; 872 | 873 | return ctx->write(ctx, &c, sizeof(uint8_t)) == sizeof(uint8_t); 874 | } 875 | 876 | bool cmp_write_u16(cmp_ctx_t *ctx, uint16_t s) { 877 | if (!write_type_marker(ctx, U16_MARKER)) 878 | return false; 879 | 880 | s = be16(s); 881 | 882 | return ctx->write(ctx, &s, sizeof(uint16_t)) == sizeof(uint16_t); 883 | } 884 | 885 | bool cmp_write_u32(cmp_ctx_t *ctx, uint32_t i) { 886 | if (!write_type_marker(ctx, U32_MARKER)) 887 | return false; 888 | 889 | i = be32(i); 890 | 891 | return ctx->write(ctx, &i, sizeof(uint32_t)) == sizeof(uint32_t); 892 | } 893 | 894 | bool cmp_write_u64(cmp_ctx_t *ctx, uint64_t l) { 895 | if (!write_type_marker(ctx, U64_MARKER)) 896 | return false; 897 | 898 | l = be64(l); 899 | 900 | return ctx->write(ctx, &l, sizeof(uint64_t)) == sizeof(uint64_t); 901 | } 902 | 903 | bool cmp_write_uinteger(cmp_ctx_t *ctx, uint64_t u) { 904 | if (u <= 0x7F) 905 | return cmp_write_pfix(ctx, (uint8_t)u); 906 | if (u <= 0xFF) 907 | return cmp_write_u8(ctx, (uint8_t)u); 908 | if (u <= 0xFFFF) 909 | return cmp_write_u16(ctx, (uint16_t)u); 910 | if (u <= 0xFFFFFFFF) 911 | return cmp_write_u32(ctx, (uint32_t)u); 912 | 913 | return cmp_write_u64(ctx, u); 914 | } 915 | 916 | #ifndef CMP_NO_FLOAT 917 | bool cmp_write_float(cmp_ctx_t *ctx, float f) { 918 | if (!write_type_marker(ctx, FLOAT_MARKER)) 919 | return false; 920 | 921 | /* 922 | * We may need to swap the float's bytes, but we can't just swap them inside 923 | * the float because the swapped bytes may not constitute a valid float. 924 | * Therefore, we have to create a buffer and swap the bytes there. 925 | */ 926 | if (!is_bigendian()) { 927 | char swapped[sizeof(float)]; 928 | char *fbuf = (char *)&f; 929 | size_t i; 930 | 931 | for (i = 0; i < sizeof(float); ++i) 932 | swapped[i] = fbuf[sizeof(float) - i - 1]; 933 | 934 | return ctx->write(ctx, swapped, sizeof(float)) == sizeof(float); 935 | } 936 | 937 | return ctx->write(ctx, &f, sizeof(float)) == sizeof(float); 938 | } 939 | 940 | bool cmp_write_double(cmp_ctx_t *ctx, double d) { 941 | if (!write_type_marker(ctx, DOUBLE_MARKER)) 942 | return false; 943 | 944 | /* Same deal for doubles */ 945 | if (!is_bigendian()) { 946 | char swapped[sizeof(double)]; 947 | char *dbuf = (char *)&d; 948 | size_t i; 949 | 950 | for (i = 0; i < sizeof(double); ++i) 951 | swapped[i] = dbuf[sizeof(double) - i - 1]; 952 | 953 | return ctx->write(ctx, swapped, sizeof(double)) == sizeof(double); 954 | } 955 | 956 | return ctx->write(ctx, &d, sizeof(double)) == sizeof(double); 957 | } 958 | 959 | bool cmp_write_decimal(cmp_ctx_t *ctx, double d) { 960 | float f = (float)d; 961 | double df = (double)f; 962 | 963 | if (df == d) 964 | return cmp_write_float(ctx, f); 965 | else 966 | return cmp_write_double(ctx, d); 967 | } 968 | #endif /* CMP_NO_FLOAT */ 969 | 970 | bool cmp_write_nil(cmp_ctx_t *ctx) { 971 | return write_type_marker(ctx, NIL_MARKER); 972 | } 973 | 974 | bool cmp_write_true(cmp_ctx_t *ctx) { 975 | return write_type_marker(ctx, TRUE_MARKER); 976 | } 977 | 978 | bool cmp_write_false(cmp_ctx_t *ctx) { 979 | return write_type_marker(ctx, FALSE_MARKER); 980 | } 981 | 982 | bool cmp_write_bool(cmp_ctx_t *ctx, bool b) { 983 | if (b) 984 | return cmp_write_true(ctx); 985 | 986 | return cmp_write_false(ctx); 987 | } 988 | 989 | bool cmp_write_u8_as_bool(cmp_ctx_t *ctx, uint8_t b) { 990 | if (b) 991 | return cmp_write_true(ctx); 992 | 993 | return cmp_write_false(ctx); 994 | } 995 | 996 | bool cmp_write_fixstr_marker(cmp_ctx_t *ctx, uint8_t size) { 997 | if (size <= FIXSTR_SIZE) 998 | return write_fixed_value(ctx, FIXSTR_MARKER | size); 999 | 1000 | ctx->error = CMP_ERROR_INPUT_VALUE_TOO_LARGE; 1001 | return false; 1002 | } 1003 | 1004 | bool cmp_write_fixstr(cmp_ctx_t *ctx, const char *data, uint8_t size) { 1005 | if (!cmp_write_fixstr_marker(ctx, size)) 1006 | return false; 1007 | 1008 | if (size == 0) 1009 | return true; 1010 | 1011 | if (ctx->write(ctx, data, size) == size) 1012 | return true; 1013 | 1014 | ctx->error = CMP_ERROR_DATA_WRITING; 1015 | return false; 1016 | } 1017 | 1018 | bool cmp_write_str8_marker(cmp_ctx_t *ctx, uint8_t size) { 1019 | if (!write_type_marker(ctx, STR8_MARKER)) 1020 | return false; 1021 | 1022 | if (ctx->write(ctx, &size, sizeof(uint8_t)) == sizeof(uint8_t)) 1023 | return true; 1024 | 1025 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1026 | return false; 1027 | } 1028 | 1029 | bool cmp_write_str8(cmp_ctx_t *ctx, const char *data, uint8_t size) { 1030 | if (!cmp_write_str8_marker(ctx, size)) 1031 | return false; 1032 | 1033 | if (size == 0) 1034 | return true; 1035 | 1036 | if (ctx->write(ctx, data, size) == size) 1037 | return true; 1038 | 1039 | ctx->error = CMP_ERROR_DATA_WRITING; 1040 | return false; 1041 | } 1042 | 1043 | bool cmp_write_str16_marker(cmp_ctx_t *ctx, uint16_t size) { 1044 | if (!write_type_marker(ctx, STR16_MARKER)) 1045 | return false; 1046 | 1047 | size = be16(size); 1048 | 1049 | if (ctx->write(ctx, &size, sizeof(uint16_t)) == sizeof(uint16_t)) 1050 | return true; 1051 | 1052 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1053 | return false; 1054 | } 1055 | 1056 | bool cmp_write_str16(cmp_ctx_t *ctx, const char *data, uint16_t size) { 1057 | if (!cmp_write_str16_marker(ctx, size)) 1058 | return false; 1059 | 1060 | if (size == 0) 1061 | return true; 1062 | 1063 | if (ctx->write(ctx, data, size) == size) 1064 | return true; 1065 | 1066 | ctx->error = CMP_ERROR_DATA_WRITING; 1067 | return false; 1068 | } 1069 | 1070 | bool cmp_write_str32_marker(cmp_ctx_t *ctx, uint32_t size) { 1071 | if (!write_type_marker(ctx, STR32_MARKER)) 1072 | return false; 1073 | 1074 | size = be32(size); 1075 | 1076 | if (ctx->write(ctx, &size, sizeof(uint32_t)) == sizeof(uint32_t)) 1077 | return true; 1078 | 1079 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1080 | return false; 1081 | } 1082 | 1083 | bool cmp_write_str32(cmp_ctx_t *ctx, const char *data, uint32_t size) { 1084 | if (!cmp_write_str32_marker(ctx, size)) 1085 | return false; 1086 | 1087 | if (size == 0) 1088 | return true; 1089 | 1090 | if (ctx->write(ctx, data, size) == size) 1091 | return true; 1092 | 1093 | ctx->error = CMP_ERROR_DATA_WRITING; 1094 | return false; 1095 | } 1096 | 1097 | bool cmp_write_str_marker(cmp_ctx_t *ctx, uint32_t size) { 1098 | if (size <= FIXSTR_SIZE) 1099 | return cmp_write_fixstr_marker(ctx, (uint8_t)size); 1100 | if (size <= 0xFF) 1101 | return cmp_write_str8_marker(ctx, (uint8_t)size); 1102 | if (size <= 0xFFFF) 1103 | return cmp_write_str16_marker(ctx, (uint16_t)size); 1104 | 1105 | return cmp_write_str32_marker(ctx, size); 1106 | } 1107 | 1108 | bool cmp_write_str_marker_v4(cmp_ctx_t *ctx, uint32_t size) { 1109 | if (size <= FIXSTR_SIZE) 1110 | return cmp_write_fixstr_marker(ctx, (uint8_t)size); 1111 | if (size <= 0xFFFF) 1112 | return cmp_write_str16_marker(ctx, (uint16_t)size); 1113 | 1114 | return cmp_write_str32_marker(ctx, size); 1115 | } 1116 | 1117 | bool cmp_write_str(cmp_ctx_t *ctx, const char *data, uint32_t size) { 1118 | if (size <= FIXSTR_SIZE) 1119 | return cmp_write_fixstr(ctx, data, (uint8_t)size); 1120 | if (size <= 0xFF) 1121 | return cmp_write_str8(ctx, data, (uint8_t)size); 1122 | if (size <= 0xFFFF) 1123 | return cmp_write_str16(ctx, data, (uint16_t)size); 1124 | 1125 | return cmp_write_str32(ctx, data, size); 1126 | } 1127 | 1128 | bool cmp_write_str_v4(cmp_ctx_t *ctx, const char *data, uint32_t size) { 1129 | if (size <= FIXSTR_SIZE) 1130 | return cmp_write_fixstr(ctx, data, (uint8_t)size); 1131 | if (size <= 0xFFFF) 1132 | return cmp_write_str16(ctx, data, (uint16_t)size); 1133 | 1134 | return cmp_write_str32(ctx, data, size); 1135 | } 1136 | 1137 | bool cmp_write_bin8_marker(cmp_ctx_t *ctx, uint8_t size) { 1138 | if (!write_type_marker(ctx, BIN8_MARKER)) 1139 | return false; 1140 | 1141 | if (ctx->write(ctx, &size, sizeof(uint8_t)) == sizeof(uint8_t)) 1142 | return true; 1143 | 1144 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1145 | return false; 1146 | } 1147 | 1148 | bool cmp_write_bin8(cmp_ctx_t *ctx, const void *data, uint8_t size) { 1149 | if (!cmp_write_bin8_marker(ctx, size)) 1150 | return false; 1151 | 1152 | if (size == 0) 1153 | return true; 1154 | 1155 | if (ctx->write(ctx, data, size) == size) 1156 | return true; 1157 | 1158 | ctx->error = CMP_ERROR_DATA_WRITING; 1159 | return false; 1160 | } 1161 | 1162 | bool cmp_write_bin16_marker(cmp_ctx_t *ctx, uint16_t size) { 1163 | if (!write_type_marker(ctx, BIN16_MARKER)) 1164 | return false; 1165 | 1166 | size = be16(size); 1167 | 1168 | if (ctx->write(ctx, &size, sizeof(uint16_t)) == sizeof(uint16_t)) 1169 | return true; 1170 | 1171 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1172 | return false; 1173 | } 1174 | 1175 | bool cmp_write_bin16(cmp_ctx_t *ctx, const void *data, uint16_t size) { 1176 | if (!cmp_write_bin16_marker(ctx, size)) 1177 | return false; 1178 | 1179 | if (size == 0) 1180 | return true; 1181 | 1182 | if (ctx->write(ctx, data, size) == size) 1183 | return true; 1184 | 1185 | ctx->error = CMP_ERROR_DATA_WRITING; 1186 | return false; 1187 | } 1188 | 1189 | bool cmp_write_bin32_marker(cmp_ctx_t *ctx, uint32_t size) { 1190 | if (!write_type_marker(ctx, BIN32_MARKER)) 1191 | return false; 1192 | 1193 | size = be32(size); 1194 | 1195 | if (ctx->write(ctx, &size, sizeof(uint32_t)) == sizeof(uint32_t)) 1196 | return true; 1197 | 1198 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1199 | return false; 1200 | } 1201 | 1202 | bool cmp_write_bin32(cmp_ctx_t *ctx, const void *data, uint32_t size) { 1203 | if (!cmp_write_bin32_marker(ctx, size)) 1204 | return false; 1205 | 1206 | if (size == 0) 1207 | return true; 1208 | 1209 | if (ctx->write(ctx, data, size) == size) 1210 | return true; 1211 | 1212 | ctx->error = CMP_ERROR_DATA_WRITING; 1213 | return false; 1214 | } 1215 | 1216 | bool cmp_write_bin_marker(cmp_ctx_t *ctx, uint32_t size) { 1217 | if (size <= 0xFF) 1218 | return cmp_write_bin8_marker(ctx, (uint8_t)size); 1219 | if (size <= 0xFFFF) 1220 | return cmp_write_bin16_marker(ctx, (uint16_t)size); 1221 | 1222 | return cmp_write_bin32_marker(ctx, size); 1223 | } 1224 | 1225 | bool cmp_write_bin(cmp_ctx_t *ctx, const void *data, uint32_t size) { 1226 | if (size <= 0xFF) 1227 | return cmp_write_bin8(ctx, data, (uint8_t)size); 1228 | if (size <= 0xFFFF) 1229 | return cmp_write_bin16(ctx, data, (uint16_t)size); 1230 | 1231 | return cmp_write_bin32(ctx, data, size); 1232 | } 1233 | 1234 | bool cmp_write_fixarray(cmp_ctx_t *ctx, uint8_t size) { 1235 | if (size <= FIXARRAY_SIZE) 1236 | return write_fixed_value(ctx, FIXARRAY_MARKER | size); 1237 | 1238 | ctx->error = CMP_ERROR_INPUT_VALUE_TOO_LARGE; 1239 | return false; 1240 | } 1241 | 1242 | bool cmp_write_array16(cmp_ctx_t *ctx, uint16_t size) { 1243 | if (!write_type_marker(ctx, ARRAY16_MARKER)) 1244 | return false; 1245 | 1246 | size = be16(size); 1247 | 1248 | if (ctx->write(ctx, &size, sizeof(uint16_t)) == sizeof(uint16_t)) 1249 | return true; 1250 | 1251 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1252 | return false; 1253 | } 1254 | 1255 | bool cmp_write_array32(cmp_ctx_t *ctx, uint32_t size) { 1256 | if (!write_type_marker(ctx, ARRAY32_MARKER)) 1257 | return false; 1258 | 1259 | size = be32(size); 1260 | 1261 | if (ctx->write(ctx, &size, sizeof(uint32_t)) == sizeof(uint32_t)) 1262 | return true; 1263 | 1264 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1265 | return false; 1266 | } 1267 | 1268 | bool cmp_write_array(cmp_ctx_t *ctx, uint32_t size) { 1269 | if (size <= FIXARRAY_SIZE) 1270 | return cmp_write_fixarray(ctx, (uint8_t)size); 1271 | if (size <= 0xFFFF) 1272 | return cmp_write_array16(ctx, (uint16_t)size); 1273 | 1274 | return cmp_write_array32(ctx, size); 1275 | } 1276 | 1277 | bool cmp_write_fixmap(cmp_ctx_t *ctx, uint8_t size) { 1278 | if (size <= FIXMAP_SIZE) 1279 | return write_fixed_value(ctx, FIXMAP_MARKER | size); 1280 | 1281 | ctx->error = CMP_ERROR_INPUT_VALUE_TOO_LARGE; 1282 | return false; 1283 | } 1284 | 1285 | bool cmp_write_map16(cmp_ctx_t *ctx, uint16_t size) { 1286 | if (!write_type_marker(ctx, MAP16_MARKER)) 1287 | return false; 1288 | 1289 | size = be16(size); 1290 | 1291 | if (ctx->write(ctx, &size, sizeof(uint16_t)) == sizeof(uint16_t)) 1292 | return true; 1293 | 1294 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1295 | return false; 1296 | } 1297 | 1298 | bool cmp_write_map32(cmp_ctx_t *ctx, uint32_t size) { 1299 | if (!write_type_marker(ctx, MAP32_MARKER)) 1300 | return false; 1301 | 1302 | size = be32(size); 1303 | 1304 | if (ctx->write(ctx, &size, sizeof(uint32_t)) == sizeof(uint32_t)) 1305 | return true; 1306 | 1307 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1308 | return false; 1309 | } 1310 | 1311 | bool cmp_write_map(cmp_ctx_t *ctx, uint32_t size) { 1312 | if (size <= FIXMAP_SIZE) 1313 | return cmp_write_fixmap(ctx, (uint8_t)size); 1314 | if (size <= 0xFFFF) 1315 | return cmp_write_map16(ctx, (uint16_t)size); 1316 | 1317 | return cmp_write_map32(ctx, size); 1318 | } 1319 | 1320 | bool cmp_write_fixext1_marker(cmp_ctx_t *ctx, int8_t type) { 1321 | if (!write_type_marker(ctx, FIXEXT1_MARKER)) 1322 | return false; 1323 | 1324 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1325 | return true; 1326 | 1327 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1328 | return false; 1329 | } 1330 | 1331 | bool cmp_write_fixext1(cmp_ctx_t *ctx, int8_t type, const void *data) { 1332 | if (!cmp_write_fixext1_marker(ctx, type)) 1333 | return false; 1334 | 1335 | if (ctx->write(ctx, data, 1) == 1) 1336 | return true; 1337 | 1338 | ctx->error = CMP_ERROR_DATA_WRITING; 1339 | return false; 1340 | } 1341 | 1342 | bool cmp_write_fixext2_marker(cmp_ctx_t *ctx, int8_t type) { 1343 | if (!write_type_marker(ctx, FIXEXT2_MARKER)) 1344 | return false; 1345 | 1346 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1347 | return true; 1348 | 1349 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1350 | return false; 1351 | } 1352 | 1353 | bool cmp_write_fixext2(cmp_ctx_t *ctx, int8_t type, const void *data) { 1354 | if (!cmp_write_fixext2_marker(ctx, type)) 1355 | return false; 1356 | 1357 | if (ctx->write(ctx, data, 2) == 2) 1358 | return true; 1359 | 1360 | ctx->error = CMP_ERROR_DATA_WRITING; 1361 | return false; 1362 | } 1363 | 1364 | bool cmp_write_fixext4_marker(cmp_ctx_t *ctx, int8_t type) { 1365 | if (!write_type_marker(ctx, FIXEXT4_MARKER)) 1366 | return false; 1367 | 1368 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1369 | return true; 1370 | 1371 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1372 | return false; 1373 | } 1374 | 1375 | bool cmp_write_fixext4(cmp_ctx_t *ctx, int8_t type, const void *data) { 1376 | if (!cmp_write_fixext4_marker(ctx, type)) 1377 | return false; 1378 | 1379 | if (ctx->write(ctx, data, 4) == 4) 1380 | return true; 1381 | 1382 | ctx->error = CMP_ERROR_DATA_WRITING; 1383 | return false; 1384 | } 1385 | 1386 | bool cmp_write_fixext8_marker(cmp_ctx_t *ctx, int8_t type) { 1387 | if (!write_type_marker(ctx, FIXEXT8_MARKER)) 1388 | return false; 1389 | 1390 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1391 | return true; 1392 | 1393 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1394 | return false; 1395 | } 1396 | 1397 | bool cmp_write_fixext8(cmp_ctx_t *ctx, int8_t type, const void *data) { 1398 | if (!cmp_write_fixext8_marker(ctx, type)) 1399 | return false; 1400 | 1401 | if (ctx->write(ctx, data, 8) == 8) 1402 | return true; 1403 | 1404 | ctx->error = CMP_ERROR_DATA_WRITING; 1405 | return false; 1406 | } 1407 | 1408 | bool cmp_write_fixext16_marker(cmp_ctx_t *ctx, int8_t type) { 1409 | if (!write_type_marker(ctx, FIXEXT16_MARKER)) 1410 | return false; 1411 | 1412 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1413 | return true; 1414 | 1415 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1416 | return false; 1417 | } 1418 | 1419 | bool cmp_write_fixext16(cmp_ctx_t *ctx, int8_t type, const void *data) { 1420 | if (!cmp_write_fixext16_marker(ctx, type)) 1421 | return false; 1422 | 1423 | if (ctx->write(ctx, data, 16) == 16) 1424 | return true; 1425 | 1426 | ctx->error = CMP_ERROR_DATA_WRITING; 1427 | return false; 1428 | } 1429 | 1430 | bool cmp_write_ext8_marker(cmp_ctx_t *ctx, int8_t type, uint8_t size) { 1431 | if (!write_type_marker(ctx, EXT8_MARKER)) 1432 | return false; 1433 | 1434 | if (ctx->write(ctx, &size, sizeof(uint8_t)) != sizeof(uint8_t)) { 1435 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1436 | return false; 1437 | } 1438 | 1439 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1440 | return true; 1441 | 1442 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1443 | return false; 1444 | } 1445 | 1446 | bool cmp_write_ext8(cmp_ctx_t *ctx, int8_t type, uint8_t size, const void *data) { 1447 | if (!cmp_write_ext8_marker(ctx, type, size)) 1448 | return false; 1449 | 1450 | if (ctx->write(ctx, data, size) == size) 1451 | return true; 1452 | 1453 | ctx->error = CMP_ERROR_DATA_WRITING; 1454 | return false; 1455 | } 1456 | 1457 | bool cmp_write_ext16_marker(cmp_ctx_t *ctx, int8_t type, uint16_t size) { 1458 | if (!write_type_marker(ctx, EXT16_MARKER)) 1459 | return false; 1460 | 1461 | size = be16(size); 1462 | 1463 | if (ctx->write(ctx, &size, sizeof(uint16_t)) != sizeof(uint16_t)) { 1464 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1465 | return false; 1466 | } 1467 | 1468 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1469 | return true; 1470 | 1471 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1472 | return false; 1473 | } 1474 | 1475 | bool cmp_write_ext16(cmp_ctx_t *ctx, int8_t type, uint16_t size, const void *data) { 1476 | if (!cmp_write_ext16_marker(ctx, type, size)) 1477 | return false; 1478 | 1479 | if (ctx->write(ctx, data, size) == size) 1480 | return true; 1481 | 1482 | ctx->error = CMP_ERROR_DATA_WRITING; 1483 | return false; 1484 | } 1485 | 1486 | bool cmp_write_ext32_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size) { 1487 | if (!write_type_marker(ctx, EXT32_MARKER)) 1488 | return false; 1489 | 1490 | size = be32(size); 1491 | 1492 | if (ctx->write(ctx, &size, sizeof(uint32_t)) != sizeof(uint32_t)) { 1493 | ctx->error = CMP_ERROR_LENGTH_WRITING; 1494 | return false; 1495 | } 1496 | 1497 | if (ctx->write(ctx, &type, sizeof(int8_t)) == sizeof(int8_t)) 1498 | return true; 1499 | 1500 | ctx->error = CMP_ERROR_EXT_TYPE_WRITING; 1501 | return false; 1502 | } 1503 | 1504 | bool cmp_write_ext32(cmp_ctx_t *ctx, int8_t type, uint32_t size, const void *data) { 1505 | if (!cmp_write_ext32_marker(ctx, type, size)) 1506 | return false; 1507 | 1508 | if (ctx->write(ctx, data, size) == size) 1509 | return true; 1510 | 1511 | ctx->error = CMP_ERROR_DATA_WRITING; 1512 | return false; 1513 | } 1514 | 1515 | bool cmp_write_ext_marker(cmp_ctx_t *ctx, int8_t type, uint32_t size) { 1516 | if (size == 1) 1517 | return cmp_write_fixext1_marker(ctx, type); 1518 | if (size == 2) 1519 | return cmp_write_fixext2_marker(ctx, type); 1520 | if (size == 4) 1521 | return cmp_write_fixext4_marker(ctx, type); 1522 | if (size == 8) 1523 | return cmp_write_fixext8_marker(ctx, type); 1524 | if (size == 16) 1525 | return cmp_write_fixext16_marker(ctx, type); 1526 | if (size <= 0xFF) 1527 | return cmp_write_ext8_marker(ctx, type, (uint8_t)size); 1528 | if (size <= 0xFFFF) 1529 | return cmp_write_ext16_marker(ctx, type, (uint16_t)size); 1530 | 1531 | return cmp_write_ext32_marker(ctx, type, size); 1532 | } 1533 | 1534 | bool cmp_write_ext(cmp_ctx_t *ctx, int8_t type, uint32_t size, const void *data) { 1535 | if (size == 1) 1536 | return cmp_write_fixext1(ctx, type, data); 1537 | if (size == 2) 1538 | return cmp_write_fixext2(ctx, type, data); 1539 | if (size == 4) 1540 | return cmp_write_fixext4(ctx, type, data); 1541 | if (size == 8) 1542 | return cmp_write_fixext8(ctx, type, data); 1543 | if (size == 16) 1544 | return cmp_write_fixext16(ctx, type, data); 1545 | if (size <= 0xFF) 1546 | return cmp_write_ext8(ctx, type, (uint8_t)size, data); 1547 | if (size <= 0xFFFF) 1548 | return cmp_write_ext16(ctx, type, (uint16_t)size, data); 1549 | 1550 | return cmp_write_ext32(ctx, type, size, data); 1551 | } 1552 | 1553 | bool cmp_write_object(cmp_ctx_t *ctx, const cmp_object_t *obj) { 1554 | switch(obj->type) { 1555 | case CMP_TYPE_POSITIVE_FIXNUM: 1556 | return cmp_write_pfix(ctx, obj->as.u8); 1557 | case CMP_TYPE_FIXMAP: 1558 | return cmp_write_fixmap(ctx, (uint8_t)obj->as.map_size); 1559 | case CMP_TYPE_FIXARRAY: 1560 | return cmp_write_fixarray(ctx, (uint8_t)obj->as.array_size); 1561 | case CMP_TYPE_FIXSTR: 1562 | return cmp_write_fixstr_marker(ctx, (uint8_t)obj->as.str_size); 1563 | case CMP_TYPE_NIL: 1564 | return cmp_write_nil(ctx); 1565 | case CMP_TYPE_BOOLEAN: 1566 | if (obj->as.boolean) 1567 | return cmp_write_true(ctx); 1568 | return cmp_write_false(ctx); 1569 | case CMP_TYPE_BIN8: 1570 | return cmp_write_bin8_marker(ctx, (uint8_t)obj->as.bin_size); 1571 | case CMP_TYPE_BIN16: 1572 | return cmp_write_bin16_marker(ctx, (uint16_t)obj->as.bin_size); 1573 | case CMP_TYPE_BIN32: 1574 | return cmp_write_bin32_marker(ctx, obj->as.bin_size); 1575 | case CMP_TYPE_EXT8: 1576 | return cmp_write_ext8_marker( 1577 | ctx, obj->as.ext.type, (uint8_t)obj->as.ext.size 1578 | ); 1579 | case CMP_TYPE_EXT16: 1580 | return cmp_write_ext16_marker( 1581 | ctx, obj->as.ext.type, (uint16_t)obj->as.ext.size 1582 | ); 1583 | case CMP_TYPE_EXT32: 1584 | return cmp_write_ext32_marker(ctx, obj->as.ext.type, obj->as.ext.size); 1585 | case CMP_TYPE_FLOAT: 1586 | #ifndef CMP_NO_FLOAT 1587 | return cmp_write_float(ctx, obj->as.flt); 1588 | #else /* CMP_NO_FLOAT */ 1589 | ctx->error = CMP_ERROR_DISABLED_FLOATING_POINT; 1590 | return false; 1591 | #endif /* CMP_NO_FLOAT */ 1592 | case CMP_TYPE_DOUBLE: 1593 | #ifndef CMP_NO_FLOAT 1594 | return cmp_write_double(ctx, obj->as.dbl); 1595 | #else /* CMP_NO_FLOAT */ 1596 | ctx->error = CMP_ERROR_DISABLED_FLOATING_POINT; 1597 | return false; 1598 | #endif 1599 | case CMP_TYPE_UINT8: 1600 | return cmp_write_u8(ctx, obj->as.u8); 1601 | case CMP_TYPE_UINT16: 1602 | return cmp_write_u16(ctx, obj->as.u16); 1603 | case CMP_TYPE_UINT32: 1604 | return cmp_write_u32(ctx, obj->as.u32); 1605 | case CMP_TYPE_UINT64: 1606 | return cmp_write_u64(ctx, obj->as.u64); 1607 | case CMP_TYPE_SINT8: 1608 | return cmp_write_s8(ctx, obj->as.s8); 1609 | case CMP_TYPE_SINT16: 1610 | return cmp_write_s16(ctx, obj->as.s16); 1611 | case CMP_TYPE_SINT32: 1612 | return cmp_write_s32(ctx, obj->as.s32); 1613 | case CMP_TYPE_SINT64: 1614 | return cmp_write_s64(ctx, obj->as.s64); 1615 | case CMP_TYPE_FIXEXT1: 1616 | return cmp_write_fixext1_marker(ctx, obj->as.ext.type); 1617 | case CMP_TYPE_FIXEXT2: 1618 | return cmp_write_fixext2_marker(ctx, obj->as.ext.type); 1619 | case CMP_TYPE_FIXEXT4: 1620 | return cmp_write_fixext4_marker(ctx, obj->as.ext.type); 1621 | case CMP_TYPE_FIXEXT8: 1622 | return cmp_write_fixext8_marker(ctx, obj->as.ext.type); 1623 | case CMP_TYPE_FIXEXT16: 1624 | return cmp_write_fixext16_marker(ctx, obj->as.ext.type); 1625 | case CMP_TYPE_STR8: 1626 | return cmp_write_str8_marker(ctx, (uint8_t)obj->as.str_size); 1627 | case CMP_TYPE_STR16: 1628 | return cmp_write_str16_marker(ctx, (uint16_t)obj->as.str_size); 1629 | case CMP_TYPE_STR32: 1630 | return cmp_write_str32_marker(ctx, obj->as.str_size); 1631 | case CMP_TYPE_ARRAY16: 1632 | return cmp_write_array16(ctx, (uint16_t)obj->as.array_size); 1633 | case CMP_TYPE_ARRAY32: 1634 | return cmp_write_array32(ctx, obj->as.array_size); 1635 | case CMP_TYPE_MAP16: 1636 | return cmp_write_map16(ctx, (uint16_t)obj->as.map_size); 1637 | case CMP_TYPE_MAP32: 1638 | return cmp_write_map32(ctx, obj->as.map_size); 1639 | case CMP_TYPE_NEGATIVE_FIXNUM: 1640 | return cmp_write_nfix(ctx, obj->as.s8); 1641 | default: 1642 | ctx->error = CMP_ERROR_INVALID_TYPE; 1643 | return false; 1644 | } 1645 | } 1646 | 1647 | bool cmp_write_object_v4(cmp_ctx_t *ctx, const cmp_object_t *obj) { 1648 | switch(obj->type) { 1649 | case CMP_TYPE_POSITIVE_FIXNUM: 1650 | return cmp_write_pfix(ctx, obj->as.u8); 1651 | case CMP_TYPE_FIXMAP: 1652 | return cmp_write_fixmap(ctx, (uint8_t)obj->as.map_size); 1653 | case CMP_TYPE_FIXARRAY: 1654 | return cmp_write_fixarray(ctx, (uint8_t)obj->as.array_size); 1655 | case CMP_TYPE_FIXSTR: 1656 | return cmp_write_fixstr_marker(ctx, (uint8_t)obj->as.str_size); 1657 | case CMP_TYPE_NIL: 1658 | return cmp_write_nil(ctx); 1659 | case CMP_TYPE_BOOLEAN: 1660 | if (obj->as.boolean) 1661 | return cmp_write_true(ctx); 1662 | return cmp_write_false(ctx); 1663 | case CMP_TYPE_EXT8: 1664 | return cmp_write_ext8_marker(ctx, obj->as.ext.type, (uint8_t)obj->as.ext.size); 1665 | case CMP_TYPE_EXT16: 1666 | return cmp_write_ext16_marker( 1667 | ctx, obj->as.ext.type, (uint16_t)obj->as.ext.size 1668 | ); 1669 | case CMP_TYPE_EXT32: 1670 | return cmp_write_ext32_marker(ctx, obj->as.ext.type, obj->as.ext.size); 1671 | case CMP_TYPE_FLOAT: 1672 | #ifndef CMP_NO_FLOAT 1673 | return cmp_write_float(ctx, obj->as.flt); 1674 | #else /* CMP_NO_FLOAT */ 1675 | ctx->error = CMP_ERROR_DISABLED_FLOATING_POINT; 1676 | return false; 1677 | #endif 1678 | case CMP_TYPE_DOUBLE: 1679 | #ifndef CMP_NO_FLOAT 1680 | return cmp_write_double(ctx, obj->as.dbl); 1681 | #else 1682 | ctx->error = CMP_ERROR_DISABLED_FLOATING_POINT; 1683 | return false; 1684 | #endif 1685 | case CMP_TYPE_UINT8: 1686 | return cmp_write_u8(ctx, obj->as.u8); 1687 | case CMP_TYPE_UINT16: 1688 | return cmp_write_u16(ctx, obj->as.u16); 1689 | case CMP_TYPE_UINT32: 1690 | return cmp_write_u32(ctx, obj->as.u32); 1691 | case CMP_TYPE_UINT64: 1692 | return cmp_write_u64(ctx, obj->as.u64); 1693 | case CMP_TYPE_SINT8: 1694 | return cmp_write_s8(ctx, obj->as.s8); 1695 | case CMP_TYPE_SINT16: 1696 | return cmp_write_s16(ctx, obj->as.s16); 1697 | case CMP_TYPE_SINT32: 1698 | return cmp_write_s32(ctx, obj->as.s32); 1699 | case CMP_TYPE_SINT64: 1700 | return cmp_write_s64(ctx, obj->as.s64); 1701 | case CMP_TYPE_FIXEXT1: 1702 | return cmp_write_fixext1_marker(ctx, obj->as.ext.type); 1703 | case CMP_TYPE_FIXEXT2: 1704 | return cmp_write_fixext2_marker(ctx, obj->as.ext.type); 1705 | case CMP_TYPE_FIXEXT4: 1706 | return cmp_write_fixext4_marker(ctx, obj->as.ext.type); 1707 | case CMP_TYPE_FIXEXT8: 1708 | return cmp_write_fixext8_marker(ctx, obj->as.ext.type); 1709 | case CMP_TYPE_FIXEXT16: 1710 | return cmp_write_fixext16_marker(ctx, obj->as.ext.type); 1711 | case CMP_TYPE_STR16: 1712 | return cmp_write_str16_marker(ctx, (uint16_t)obj->as.str_size); 1713 | case CMP_TYPE_STR32: 1714 | return cmp_write_str32_marker(ctx, obj->as.str_size); 1715 | case CMP_TYPE_ARRAY16: 1716 | return cmp_write_array16(ctx, (uint16_t)obj->as.array_size); 1717 | case CMP_TYPE_ARRAY32: 1718 | return cmp_write_array32(ctx, obj->as.array_size); 1719 | case CMP_TYPE_MAP16: 1720 | return cmp_write_map16(ctx, (uint16_t)obj->as.map_size); 1721 | case CMP_TYPE_MAP32: 1722 | return cmp_write_map32(ctx, obj->as.map_size); 1723 | case CMP_TYPE_NEGATIVE_FIXNUM: 1724 | return cmp_write_nfix(ctx, obj->as.s8); 1725 | default: 1726 | ctx->error = CMP_ERROR_INVALID_TYPE; 1727 | return false; 1728 | } 1729 | } 1730 | 1731 | bool cmp_read_pfix(cmp_ctx_t *ctx, uint8_t *c) { 1732 | cmp_object_t obj; 1733 | 1734 | if (!cmp_read_object(ctx, &obj)) 1735 | return false; 1736 | 1737 | if (obj.type != CMP_TYPE_POSITIVE_FIXNUM) { 1738 | ctx->error = CMP_ERROR_INVALID_TYPE; 1739 | return false; 1740 | } 1741 | 1742 | *c = obj.as.u8; 1743 | return true; 1744 | } 1745 | 1746 | bool cmp_read_nfix(cmp_ctx_t *ctx, int8_t *c) { 1747 | cmp_object_t obj; 1748 | 1749 | if (!cmp_read_object(ctx, &obj)) 1750 | return false; 1751 | 1752 | if (obj.type != CMP_TYPE_NEGATIVE_FIXNUM) { 1753 | ctx->error = CMP_ERROR_INVALID_TYPE; 1754 | return false; 1755 | } 1756 | 1757 | *c = obj.as.s8; 1758 | return true; 1759 | } 1760 | 1761 | bool cmp_read_sfix(cmp_ctx_t *ctx, int8_t *c) { 1762 | cmp_object_t obj; 1763 | 1764 | if (!cmp_read_object(ctx, &obj)) 1765 | return false; 1766 | 1767 | switch (obj.type) { 1768 | case CMP_TYPE_POSITIVE_FIXNUM: 1769 | case CMP_TYPE_NEGATIVE_FIXNUM: 1770 | *c = obj.as.s8; 1771 | return true; 1772 | default: 1773 | ctx->error = CMP_ERROR_INVALID_TYPE; 1774 | return false; 1775 | } 1776 | } 1777 | 1778 | bool cmp_read_s8(cmp_ctx_t *ctx, int8_t *c) { 1779 | cmp_object_t obj; 1780 | 1781 | if (!cmp_read_object(ctx, &obj)) 1782 | return false; 1783 | 1784 | if (obj.type != CMP_TYPE_SINT8) { 1785 | ctx->error = CMP_ERROR_INVALID_TYPE; 1786 | return false; 1787 | } 1788 | 1789 | *c = obj.as.s8; 1790 | return true; 1791 | } 1792 | 1793 | bool cmp_read_s16(cmp_ctx_t *ctx, int16_t *s) { 1794 | cmp_object_t obj; 1795 | 1796 | if (!cmp_read_object(ctx, &obj)) 1797 | return false; 1798 | 1799 | if (obj.type != CMP_TYPE_SINT16) { 1800 | ctx->error = CMP_ERROR_INVALID_TYPE; 1801 | return false; 1802 | } 1803 | 1804 | *s = obj.as.s16; 1805 | return true; 1806 | } 1807 | 1808 | bool cmp_read_s32(cmp_ctx_t *ctx, int32_t *i) { 1809 | cmp_object_t obj; 1810 | 1811 | if (!cmp_read_object(ctx, &obj)) 1812 | return false; 1813 | 1814 | if (obj.type != CMP_TYPE_SINT32) { 1815 | ctx->error = CMP_ERROR_INVALID_TYPE; 1816 | return false; 1817 | } 1818 | 1819 | *i = obj.as.s32; 1820 | return true; 1821 | } 1822 | 1823 | bool cmp_read_s64(cmp_ctx_t *ctx, int64_t *l) { 1824 | cmp_object_t obj; 1825 | 1826 | if (!cmp_read_object(ctx, &obj)) 1827 | return false; 1828 | 1829 | if (obj.type != CMP_TYPE_SINT64) { 1830 | ctx->error = CMP_ERROR_INVALID_TYPE; 1831 | return false; 1832 | } 1833 | 1834 | *l = obj.as.s64; 1835 | return true; 1836 | } 1837 | 1838 | bool cmp_read_char(cmp_ctx_t *ctx, int8_t *c) { 1839 | cmp_object_t obj; 1840 | 1841 | if (!cmp_read_object(ctx, &obj)) 1842 | return false; 1843 | 1844 | switch (obj.type) { 1845 | case CMP_TYPE_POSITIVE_FIXNUM: 1846 | case CMP_TYPE_NEGATIVE_FIXNUM: 1847 | case CMP_TYPE_SINT8: 1848 | *c = obj.as.s8; 1849 | return true; 1850 | case CMP_TYPE_UINT8: 1851 | if (obj.as.u8 <= 0x7F) { 1852 | *c = (int8_t)obj.as.u8; 1853 | return true; 1854 | } 1855 | break; 1856 | default: 1857 | break; 1858 | } 1859 | 1860 | ctx->error = CMP_ERROR_INVALID_TYPE; 1861 | return false; 1862 | } 1863 | 1864 | bool cmp_read_short(cmp_ctx_t *ctx, int16_t *s) { 1865 | cmp_object_t obj; 1866 | 1867 | if (!cmp_read_object(ctx, &obj)) 1868 | return false; 1869 | 1870 | switch (obj.type) { 1871 | case CMP_TYPE_POSITIVE_FIXNUM: 1872 | case CMP_TYPE_NEGATIVE_FIXNUM: 1873 | case CMP_TYPE_SINT8: 1874 | *s = obj.as.s8; 1875 | return true; 1876 | case CMP_TYPE_UINT8: 1877 | *s = obj.as.u8; 1878 | return true; 1879 | case CMP_TYPE_SINT16: 1880 | *s = obj.as.s16; 1881 | return true; 1882 | case CMP_TYPE_UINT16: 1883 | if (obj.as.u16 <= 0x7FFF) { 1884 | *s = (int16_t)obj.as.u16; 1885 | return true; 1886 | } 1887 | break; 1888 | default: 1889 | break; 1890 | } 1891 | 1892 | ctx->error = CMP_ERROR_INVALID_TYPE; 1893 | return false; 1894 | } 1895 | 1896 | bool cmp_read_int(cmp_ctx_t *ctx, int32_t *i) { 1897 | cmp_object_t obj; 1898 | 1899 | if (!cmp_read_object(ctx, &obj)) 1900 | return false; 1901 | 1902 | switch (obj.type) { 1903 | case CMP_TYPE_POSITIVE_FIXNUM: 1904 | case CMP_TYPE_NEGATIVE_FIXNUM: 1905 | case CMP_TYPE_SINT8: 1906 | *i = obj.as.s8; 1907 | return true; 1908 | case CMP_TYPE_UINT8: 1909 | *i = obj.as.u8; 1910 | return true; 1911 | case CMP_TYPE_SINT16: 1912 | *i = obj.as.s16; 1913 | return true; 1914 | case CMP_TYPE_UINT16: 1915 | *i = obj.as.u16; 1916 | return true; 1917 | case CMP_TYPE_SINT32: 1918 | *i = obj.as.s32; 1919 | return true; 1920 | case CMP_TYPE_UINT32: 1921 | if (obj.as.u32 <= 0x7FFFFFFF) { 1922 | *i = (int32_t)obj.as.u32; 1923 | return true; 1924 | } 1925 | break; 1926 | default: 1927 | break; 1928 | } 1929 | 1930 | ctx->error = CMP_ERROR_INVALID_TYPE; 1931 | return false; 1932 | } 1933 | 1934 | bool cmp_read_long(cmp_ctx_t *ctx, int64_t *d) { 1935 | cmp_object_t obj; 1936 | 1937 | if (!cmp_read_object(ctx, &obj)) 1938 | return false; 1939 | 1940 | switch (obj.type) { 1941 | case CMP_TYPE_POSITIVE_FIXNUM: 1942 | case CMP_TYPE_NEGATIVE_FIXNUM: 1943 | case CMP_TYPE_SINT8: 1944 | *d = obj.as.s8; 1945 | return true; 1946 | case CMP_TYPE_UINT8: 1947 | *d = obj.as.u8; 1948 | return true; 1949 | case CMP_TYPE_SINT16: 1950 | *d = obj.as.s16; 1951 | return true; 1952 | case CMP_TYPE_UINT16: 1953 | *d = obj.as.u16; 1954 | return true; 1955 | case CMP_TYPE_SINT32: 1956 | *d = obj.as.s32; 1957 | return true; 1958 | case CMP_TYPE_UINT32: 1959 | *d = obj.as.u32; 1960 | return true; 1961 | case CMP_TYPE_SINT64: 1962 | *d = obj.as.s64; 1963 | return true; 1964 | case CMP_TYPE_UINT64: 1965 | if (obj.as.u64 <= UINT64_C(0x7FFFFFFFFFFFFFFF)) { 1966 | *d = (int64_t)obj.as.u64; 1967 | return true; 1968 | } 1969 | break; 1970 | default: 1971 | break; 1972 | } 1973 | 1974 | ctx->error = CMP_ERROR_INVALID_TYPE; 1975 | return false; 1976 | } 1977 | 1978 | bool cmp_read_integer(cmp_ctx_t *ctx, int64_t *d) { 1979 | return cmp_read_long(ctx, d); 1980 | } 1981 | 1982 | bool cmp_read_ufix(cmp_ctx_t *ctx, uint8_t *c) { 1983 | return cmp_read_pfix(ctx, c); 1984 | } 1985 | 1986 | bool cmp_read_u8(cmp_ctx_t *ctx, uint8_t *c) { 1987 | cmp_object_t obj; 1988 | 1989 | if (!cmp_read_object(ctx, &obj)) 1990 | return false; 1991 | 1992 | if (obj.type != CMP_TYPE_UINT8) { 1993 | ctx->error = CMP_ERROR_INVALID_TYPE; 1994 | return false; 1995 | } 1996 | 1997 | *c = obj.as.u8; 1998 | return true; 1999 | } 2000 | 2001 | bool cmp_read_u16(cmp_ctx_t *ctx, uint16_t *s) { 2002 | cmp_object_t obj; 2003 | 2004 | if (!cmp_read_object(ctx, &obj)) 2005 | return false; 2006 | 2007 | if (obj.type != CMP_TYPE_UINT16) { 2008 | ctx->error = CMP_ERROR_INVALID_TYPE; 2009 | return false; 2010 | } 2011 | 2012 | *s = obj.as.u16; 2013 | return true; 2014 | } 2015 | 2016 | bool cmp_read_u32(cmp_ctx_t *ctx, uint32_t *i) { 2017 | cmp_object_t obj; 2018 | 2019 | if (!cmp_read_object(ctx, &obj)) 2020 | return false; 2021 | 2022 | if (obj.type != CMP_TYPE_UINT32) { 2023 | ctx->error = CMP_ERROR_INVALID_TYPE; 2024 | return false; 2025 | } 2026 | 2027 | *i = obj.as.u32; 2028 | return true; 2029 | } 2030 | 2031 | bool cmp_read_u64(cmp_ctx_t *ctx, uint64_t *l) { 2032 | cmp_object_t obj; 2033 | 2034 | if (!cmp_read_object(ctx, &obj)) 2035 | return false; 2036 | 2037 | if (obj.type != CMP_TYPE_UINT64) { 2038 | ctx->error = CMP_ERROR_INVALID_TYPE; 2039 | return false; 2040 | } 2041 | 2042 | *l = obj.as.u64; 2043 | return true; 2044 | } 2045 | 2046 | bool cmp_read_uchar(cmp_ctx_t *ctx, uint8_t *c) { 2047 | cmp_object_t obj; 2048 | 2049 | if (!cmp_read_object(ctx, &obj)) 2050 | return false; 2051 | 2052 | switch (obj.type) { 2053 | case CMP_TYPE_POSITIVE_FIXNUM: 2054 | case CMP_TYPE_UINT8: 2055 | *c = obj.as.u8; 2056 | return true; 2057 | case CMP_TYPE_NEGATIVE_FIXNUM: 2058 | case CMP_TYPE_SINT8: 2059 | if (obj.as.s8 >= 0) { 2060 | *c = (uint8_t)obj.as.s8; 2061 | return true; 2062 | } 2063 | break; 2064 | default: 2065 | break; 2066 | } 2067 | 2068 | ctx->error = CMP_ERROR_INVALID_TYPE; 2069 | return false; 2070 | } 2071 | 2072 | bool cmp_read_ushort(cmp_ctx_t *ctx, uint16_t *s) { 2073 | cmp_object_t obj; 2074 | 2075 | if (!cmp_read_object(ctx, &obj)) 2076 | return false; 2077 | 2078 | switch (obj.type) { 2079 | case CMP_TYPE_POSITIVE_FIXNUM: 2080 | case CMP_TYPE_UINT8: 2081 | *s = obj.as.u8; 2082 | return true; 2083 | case CMP_TYPE_UINT16: 2084 | *s = obj.as.u16; 2085 | return true; 2086 | case CMP_TYPE_NEGATIVE_FIXNUM: 2087 | case CMP_TYPE_SINT8: 2088 | if (obj.as.s8 >= 0) { 2089 | *s = (uint8_t)obj.as.s8; 2090 | return true; 2091 | } 2092 | break; 2093 | case CMP_TYPE_SINT16: 2094 | if (obj.as.s16 >= 0) { 2095 | *s = (uint16_t)obj.as.s16; 2096 | return true; 2097 | } 2098 | break; 2099 | default: 2100 | break; 2101 | } 2102 | 2103 | ctx->error = CMP_ERROR_INVALID_TYPE; 2104 | return false; 2105 | } 2106 | 2107 | bool cmp_read_uint(cmp_ctx_t *ctx, uint32_t *i) { 2108 | cmp_object_t obj; 2109 | 2110 | if (!cmp_read_object(ctx, &obj)) 2111 | return false; 2112 | 2113 | switch (obj.type) { 2114 | case CMP_TYPE_POSITIVE_FIXNUM: 2115 | case CMP_TYPE_UINT8: 2116 | *i = obj.as.u8; 2117 | return true; 2118 | case CMP_TYPE_UINT16: 2119 | *i = obj.as.u16; 2120 | return true; 2121 | case CMP_TYPE_UINT32: 2122 | *i = obj.as.u32; 2123 | return true; 2124 | case CMP_TYPE_NEGATIVE_FIXNUM: 2125 | case CMP_TYPE_SINT8: 2126 | if (obj.as.s8 >= 0) { 2127 | *i = (uint8_t)obj.as.s8; 2128 | return true; 2129 | } 2130 | break; 2131 | case CMP_TYPE_SINT16: 2132 | if (obj.as.s16 >= 0) { 2133 | *i = (uint16_t)obj.as.s16; 2134 | return true; 2135 | } 2136 | break; 2137 | case CMP_TYPE_SINT32: 2138 | if (obj.as.s32 >= 0) { 2139 | *i = (uint32_t)obj.as.s32; 2140 | return true; 2141 | } 2142 | break; 2143 | default: 2144 | break; 2145 | } 2146 | 2147 | ctx->error = CMP_ERROR_INVALID_TYPE; 2148 | return false; 2149 | } 2150 | 2151 | bool cmp_read_ulong(cmp_ctx_t *ctx, uint64_t *u) { 2152 | cmp_object_t obj; 2153 | 2154 | if (!cmp_read_object(ctx, &obj)) 2155 | return false; 2156 | 2157 | switch (obj.type) { 2158 | case CMP_TYPE_POSITIVE_FIXNUM: 2159 | case CMP_TYPE_UINT8: 2160 | *u = obj.as.u8; 2161 | return true; 2162 | case CMP_TYPE_UINT16: 2163 | *u = obj.as.u16; 2164 | return true; 2165 | case CMP_TYPE_UINT32: 2166 | *u = obj.as.u32; 2167 | return true; 2168 | case CMP_TYPE_UINT64: 2169 | *u = obj.as.u64; 2170 | return true; 2171 | case CMP_TYPE_NEGATIVE_FIXNUM: 2172 | case CMP_TYPE_SINT8: 2173 | if (obj.as.s8 >= 0) { 2174 | *u = (uint8_t)obj.as.s8; 2175 | return true; 2176 | } 2177 | break; 2178 | case CMP_TYPE_SINT16: 2179 | if (obj.as.s16 >= 0) { 2180 | *u = (uint16_t)obj.as.s16; 2181 | return true; 2182 | } 2183 | break; 2184 | case CMP_TYPE_SINT32: 2185 | if (obj.as.s32 >= 0) { 2186 | *u = (uint32_t)obj.as.s32; 2187 | return true; 2188 | } 2189 | break; 2190 | case CMP_TYPE_SINT64: 2191 | if (obj.as.s64 >= 0) { 2192 | *u = (uint64_t)obj.as.s64; 2193 | return true; 2194 | } 2195 | break; 2196 | default: 2197 | break; 2198 | } 2199 | 2200 | ctx->error = CMP_ERROR_INVALID_TYPE; 2201 | return false; 2202 | } 2203 | 2204 | bool cmp_read_uinteger(cmp_ctx_t *ctx, uint64_t *u) { 2205 | return cmp_read_ulong(ctx, u); 2206 | } 2207 | 2208 | #ifndef CMP_NO_FLOAT 2209 | bool cmp_read_float(cmp_ctx_t *ctx, float *f) { 2210 | cmp_object_t obj; 2211 | 2212 | if (!cmp_read_object(ctx, &obj)) 2213 | return false; 2214 | 2215 | if (obj.type != CMP_TYPE_FLOAT) { 2216 | ctx->error = CMP_ERROR_INVALID_TYPE; 2217 | return false; 2218 | } 2219 | 2220 | *f = obj.as.flt; 2221 | 2222 | return true; 2223 | } 2224 | 2225 | bool cmp_read_double(cmp_ctx_t *ctx, double *d) { 2226 | cmp_object_t obj; 2227 | 2228 | if (!cmp_read_object(ctx, &obj)) 2229 | return false; 2230 | 2231 | if (obj.type != CMP_TYPE_DOUBLE) { 2232 | ctx->error = CMP_ERROR_INVALID_TYPE; 2233 | return false; 2234 | } 2235 | 2236 | *d = obj.as.dbl; 2237 | 2238 | return true; 2239 | } 2240 | 2241 | bool cmp_read_decimal(cmp_ctx_t *ctx, double *d) { 2242 | cmp_object_t obj; 2243 | 2244 | if (!cmp_read_object(ctx, &obj)) 2245 | return false; 2246 | 2247 | switch (obj.type) { 2248 | case CMP_TYPE_FLOAT: 2249 | *d = (double)obj.as.flt; 2250 | return true; 2251 | case CMP_TYPE_DOUBLE: 2252 | *d = obj.as.dbl; 2253 | return true; 2254 | default: 2255 | ctx->error = CMP_ERROR_INVALID_TYPE; 2256 | return false; 2257 | } 2258 | } 2259 | #endif /* CMP_NO_FLOAT */ 2260 | 2261 | bool cmp_read_nil(cmp_ctx_t *ctx) { 2262 | cmp_object_t obj; 2263 | 2264 | if (!cmp_read_object(ctx, &obj)) 2265 | return false; 2266 | 2267 | if (obj.type == CMP_TYPE_NIL) 2268 | return true; 2269 | 2270 | ctx->error = CMP_ERROR_INVALID_TYPE; 2271 | return false; 2272 | } 2273 | 2274 | bool cmp_read_bool(cmp_ctx_t *ctx, bool *b) { 2275 | cmp_object_t obj; 2276 | 2277 | if (!cmp_read_object(ctx, &obj)) 2278 | return false; 2279 | 2280 | if (obj.type != CMP_TYPE_BOOLEAN) { 2281 | ctx->error = CMP_ERROR_INVALID_TYPE; 2282 | return false; 2283 | } 2284 | 2285 | if (obj.as.boolean) 2286 | *b = true; 2287 | else 2288 | *b = false; 2289 | 2290 | return true; 2291 | } 2292 | 2293 | bool cmp_read_bool_as_u8(cmp_ctx_t *ctx, uint8_t *b) { 2294 | cmp_object_t obj; 2295 | 2296 | if (!cmp_read_object(ctx, &obj)) 2297 | return false; 2298 | 2299 | if (obj.type != CMP_TYPE_BOOLEAN) { 2300 | ctx->error = CMP_ERROR_INVALID_TYPE; 2301 | return false; 2302 | } 2303 | 2304 | if (obj.as.boolean) 2305 | *b = 1; 2306 | else 2307 | *b = 0; 2308 | 2309 | return true; 2310 | } 2311 | 2312 | bool cmp_read_str_size(cmp_ctx_t *ctx, uint32_t *size) { 2313 | cmp_object_t obj; 2314 | 2315 | if (!cmp_read_object(ctx, &obj)) 2316 | return false; 2317 | 2318 | switch (obj.type) { 2319 | case CMP_TYPE_FIXSTR: 2320 | case CMP_TYPE_STR8: 2321 | case CMP_TYPE_STR16: 2322 | case CMP_TYPE_STR32: 2323 | *size = obj.as.str_size; 2324 | return true; 2325 | default: 2326 | ctx->error = CMP_ERROR_INVALID_TYPE; 2327 | return false; 2328 | } 2329 | } 2330 | 2331 | bool cmp_read_str(cmp_ctx_t *ctx, char *data, uint32_t *size) { 2332 | uint32_t str_size = 0; 2333 | 2334 | if (!cmp_read_str_size(ctx, &str_size)) 2335 | return false; 2336 | 2337 | if (str_size >= *size) { 2338 | *size = str_size; 2339 | ctx->error = CMP_ERROR_STR_DATA_LENGTH_TOO_LONG; 2340 | return false; 2341 | } 2342 | 2343 | if (!ctx->read(ctx, data, str_size)) { 2344 | ctx->error = CMP_ERROR_DATA_READING; 2345 | return false; 2346 | } 2347 | 2348 | data[str_size] = 0; 2349 | 2350 | *size = str_size; 2351 | return true; 2352 | } 2353 | 2354 | bool cmp_read_bin_size(cmp_ctx_t *ctx, uint32_t *size) { 2355 | cmp_object_t obj; 2356 | 2357 | if (!cmp_read_object(ctx, &obj)) 2358 | return false; 2359 | 2360 | switch (obj.type) { 2361 | case CMP_TYPE_BIN8: 2362 | case CMP_TYPE_BIN16: 2363 | case CMP_TYPE_BIN32: 2364 | *size = obj.as.bin_size; 2365 | return true; 2366 | default: 2367 | ctx->error = CMP_ERROR_INVALID_TYPE; 2368 | return false; 2369 | } 2370 | } 2371 | 2372 | bool cmp_read_bin(cmp_ctx_t *ctx, void *data, uint32_t *size) { 2373 | uint32_t bin_size = 0; 2374 | 2375 | if (!cmp_read_bin_size(ctx, &bin_size)) 2376 | return false; 2377 | 2378 | if (bin_size > *size) { 2379 | ctx->error = CMP_ERROR_BIN_DATA_LENGTH_TOO_LONG; 2380 | return false; 2381 | } 2382 | 2383 | if (!ctx->read(ctx, data, bin_size)) { 2384 | ctx->error = CMP_ERROR_DATA_READING; 2385 | return false; 2386 | } 2387 | 2388 | *size = bin_size; 2389 | return true; 2390 | } 2391 | 2392 | bool cmp_read_array(cmp_ctx_t *ctx, uint32_t *size) { 2393 | cmp_object_t obj; 2394 | 2395 | if (!cmp_read_object(ctx, &obj)) 2396 | return false; 2397 | 2398 | switch (obj.type) { 2399 | case CMP_TYPE_FIXARRAY: 2400 | case CMP_TYPE_ARRAY16: 2401 | case CMP_TYPE_ARRAY32: 2402 | *size = obj.as.array_size; 2403 | return true; 2404 | default: 2405 | ctx->error = CMP_ERROR_INVALID_TYPE; 2406 | return false; 2407 | } 2408 | } 2409 | 2410 | bool cmp_read_map(cmp_ctx_t *ctx, uint32_t *size) { 2411 | cmp_object_t obj; 2412 | 2413 | if (!cmp_read_object(ctx, &obj)) 2414 | return false; 2415 | 2416 | switch (obj.type) { 2417 | case CMP_TYPE_FIXMAP: 2418 | case CMP_TYPE_MAP16: 2419 | case CMP_TYPE_MAP32: 2420 | *size = obj.as.map_size; 2421 | return true; 2422 | default: 2423 | ctx->error = CMP_ERROR_INVALID_TYPE; 2424 | return false; 2425 | } 2426 | } 2427 | 2428 | bool cmp_read_fixext1_marker(cmp_ctx_t *ctx, int8_t *type) { 2429 | cmp_object_t obj; 2430 | 2431 | if (!cmp_read_object(ctx, &obj)) 2432 | return false; 2433 | 2434 | if (obj.type != CMP_TYPE_FIXEXT1) { 2435 | ctx->error = CMP_ERROR_INVALID_TYPE; 2436 | return false; 2437 | } 2438 | 2439 | *type = obj.as.ext.type; 2440 | return true; 2441 | } 2442 | 2443 | bool cmp_read_fixext1(cmp_ctx_t *ctx, int8_t *type, void *data) { 2444 | if (!cmp_read_fixext1_marker(ctx, type)) 2445 | return false; 2446 | 2447 | if (ctx->read(ctx, data, 1)) 2448 | return true; 2449 | 2450 | ctx->error = CMP_ERROR_DATA_READING; 2451 | return false; 2452 | } 2453 | 2454 | bool cmp_read_fixext2_marker(cmp_ctx_t *ctx, int8_t *type) { 2455 | cmp_object_t obj; 2456 | 2457 | if (!cmp_read_object(ctx, &obj)) 2458 | return false; 2459 | 2460 | if (obj.type != CMP_TYPE_FIXEXT2) { 2461 | ctx->error = CMP_ERROR_INVALID_TYPE; 2462 | return false; 2463 | } 2464 | 2465 | *type = obj.as.ext.type; 2466 | return true; 2467 | } 2468 | 2469 | bool cmp_read_fixext2(cmp_ctx_t *ctx, int8_t *type, void *data) { 2470 | if (!cmp_read_fixext2_marker(ctx, type)) 2471 | return false; 2472 | 2473 | if (ctx->read(ctx, data, 2)) 2474 | return true; 2475 | 2476 | ctx->error = CMP_ERROR_DATA_READING; 2477 | return false; 2478 | } 2479 | 2480 | bool cmp_read_fixext4_marker(cmp_ctx_t *ctx, int8_t *type) { 2481 | cmp_object_t obj; 2482 | 2483 | if (!cmp_read_object(ctx, &obj)) 2484 | return false; 2485 | 2486 | if (obj.type != CMP_TYPE_FIXEXT4) { 2487 | ctx->error = CMP_ERROR_INVALID_TYPE; 2488 | return false; 2489 | } 2490 | 2491 | *type = obj.as.ext.type; 2492 | return true; 2493 | } 2494 | 2495 | bool cmp_read_fixext4(cmp_ctx_t *ctx, int8_t *type, void *data) { 2496 | if (!cmp_read_fixext4_marker(ctx, type)) 2497 | return false; 2498 | 2499 | if (ctx->read(ctx, data, 4)) 2500 | return true; 2501 | 2502 | ctx->error = CMP_ERROR_DATA_READING; 2503 | return false; 2504 | } 2505 | 2506 | bool cmp_read_fixext8_marker(cmp_ctx_t *ctx, int8_t *type) { 2507 | cmp_object_t obj; 2508 | 2509 | if (!cmp_read_object(ctx, &obj)) 2510 | return false; 2511 | 2512 | if (obj.type != CMP_TYPE_FIXEXT8) { 2513 | ctx->error = CMP_ERROR_INVALID_TYPE; 2514 | return false; 2515 | } 2516 | 2517 | *type = obj.as.ext.type; 2518 | return true; 2519 | } 2520 | 2521 | bool cmp_read_fixext8(cmp_ctx_t *ctx, int8_t *type, void *data) { 2522 | if (!cmp_read_fixext8_marker(ctx, type)) 2523 | return false; 2524 | 2525 | if (ctx->read(ctx, data, 8)) 2526 | return true; 2527 | 2528 | ctx->error = CMP_ERROR_DATA_READING; 2529 | return false; 2530 | } 2531 | 2532 | bool cmp_read_fixext16_marker(cmp_ctx_t *ctx, int8_t *type) { 2533 | cmp_object_t obj; 2534 | 2535 | if (!cmp_read_object(ctx, &obj)) 2536 | return false; 2537 | 2538 | if (obj.type != CMP_TYPE_FIXEXT16) { 2539 | ctx->error = CMP_ERROR_INVALID_TYPE; 2540 | return false; 2541 | } 2542 | 2543 | *type = obj.as.ext.type; 2544 | return true; 2545 | } 2546 | 2547 | bool cmp_read_fixext16(cmp_ctx_t *ctx, int8_t *type, void *data) { 2548 | if (!cmp_read_fixext16_marker(ctx, type)) 2549 | return false; 2550 | 2551 | if (ctx->read(ctx, data, 16)) 2552 | return true; 2553 | 2554 | ctx->error = CMP_ERROR_DATA_READING; 2555 | return false; 2556 | } 2557 | 2558 | bool cmp_read_ext8_marker(cmp_ctx_t *ctx, int8_t *type, uint8_t *size) { 2559 | cmp_object_t obj; 2560 | 2561 | if (!cmp_read_object(ctx, &obj)) 2562 | return false; 2563 | 2564 | if (obj.type != CMP_TYPE_EXT8) { 2565 | ctx->error = CMP_ERROR_INVALID_TYPE; 2566 | return false; 2567 | } 2568 | 2569 | *type = obj.as.ext.type; 2570 | *size = (uint8_t)obj.as.ext.size; 2571 | 2572 | return true; 2573 | } 2574 | 2575 | bool cmp_read_ext8(cmp_ctx_t *ctx, int8_t *type, uint8_t *size, void *data) { 2576 | if (!cmp_read_ext8_marker(ctx, type, size)) 2577 | return false; 2578 | 2579 | if (ctx->read(ctx, data, *size)) 2580 | return true; 2581 | 2582 | ctx->error = CMP_ERROR_DATA_READING; 2583 | return false; 2584 | } 2585 | 2586 | bool cmp_read_ext16_marker(cmp_ctx_t *ctx, int8_t *type, uint16_t *size) { 2587 | cmp_object_t obj; 2588 | 2589 | if (!cmp_read_object(ctx, &obj)) 2590 | return false; 2591 | 2592 | if (obj.type != CMP_TYPE_EXT16) { 2593 | ctx->error = CMP_ERROR_INVALID_TYPE; 2594 | return false; 2595 | } 2596 | 2597 | *type = obj.as.ext.type; 2598 | *size = (uint16_t)obj.as.ext.size; 2599 | 2600 | return true; 2601 | } 2602 | 2603 | bool cmp_read_ext16(cmp_ctx_t *ctx, int8_t *type, uint16_t *size, void *data) { 2604 | if (!cmp_read_ext16_marker(ctx, type, size)) 2605 | return false; 2606 | 2607 | if (ctx->read(ctx, data, *size)) 2608 | return true; 2609 | 2610 | ctx->error = CMP_ERROR_DATA_READING; 2611 | return false; 2612 | } 2613 | 2614 | bool cmp_read_ext32_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size) { 2615 | cmp_object_t obj; 2616 | 2617 | if (!cmp_read_object(ctx, &obj)) 2618 | return false; 2619 | 2620 | if (obj.type != CMP_TYPE_EXT32) { 2621 | ctx->error = CMP_ERROR_INVALID_TYPE; 2622 | return false; 2623 | } 2624 | 2625 | *type = obj.as.ext.type; 2626 | *size = obj.as.ext.size; 2627 | 2628 | return true; 2629 | } 2630 | 2631 | bool cmp_read_ext32(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data) { 2632 | if (!cmp_read_ext32_marker(ctx, type, size)) 2633 | return false; 2634 | 2635 | if (ctx->read(ctx, data, *size)) 2636 | return true; 2637 | 2638 | ctx->error = CMP_ERROR_DATA_READING; 2639 | return false; 2640 | } 2641 | 2642 | bool cmp_read_ext_marker(cmp_ctx_t *ctx, int8_t *type, uint32_t *size) { 2643 | cmp_object_t obj; 2644 | 2645 | if (!cmp_read_object(ctx, &obj)) 2646 | return false; 2647 | 2648 | switch (obj.type) { 2649 | case CMP_TYPE_FIXEXT1: 2650 | case CMP_TYPE_FIXEXT2: 2651 | case CMP_TYPE_FIXEXT4: 2652 | case CMP_TYPE_FIXEXT8: 2653 | case CMP_TYPE_FIXEXT16: 2654 | case CMP_TYPE_EXT8: 2655 | case CMP_TYPE_EXT16: 2656 | case CMP_TYPE_EXT32: 2657 | *type = obj.as.ext.type; 2658 | *size = obj.as.ext.size; 2659 | return true; 2660 | default: 2661 | ctx->error = CMP_ERROR_INVALID_TYPE; 2662 | return false; 2663 | } 2664 | } 2665 | 2666 | bool cmp_read_ext(cmp_ctx_t *ctx, int8_t *type, uint32_t *size, void *data) { 2667 | if (!cmp_read_ext_marker(ctx, type, size)) 2668 | return false; 2669 | 2670 | if (ctx->read(ctx, data, *size)) 2671 | return true; 2672 | 2673 | ctx->error = CMP_ERROR_DATA_READING; 2674 | return false; 2675 | } 2676 | 2677 | bool cmp_read_object(cmp_ctx_t *ctx, cmp_object_t *obj) { 2678 | uint8_t type_marker = 0; 2679 | 2680 | if (!read_type_marker(ctx, &type_marker)) 2681 | return false; 2682 | 2683 | if (!type_marker_to_cmp_type(type_marker, &obj->type)) { 2684 | ctx->error = CMP_ERROR_INVALID_TYPE; 2685 | return false; 2686 | } 2687 | 2688 | return read_obj_data(ctx, type_marker, obj); 2689 | } 2690 | 2691 | bool cmp_skip_object(cmp_ctx_t *ctx, cmp_object_t *obj) { 2692 | uint8_t type_marker = 0; 2693 | uint8_t cmp_type; 2694 | uint32_t size = 0; 2695 | 2696 | if (!read_type_marker(ctx, &type_marker)) { 2697 | return false; 2698 | } 2699 | 2700 | if (!type_marker_to_cmp_type(type_marker, &cmp_type)) { 2701 | ctx->error = CMP_ERROR_INVALID_TYPE; 2702 | return false; 2703 | } 2704 | 2705 | switch (cmp_type) { 2706 | case CMP_TYPE_FIXARRAY: 2707 | case CMP_TYPE_ARRAY16: 2708 | case CMP_TYPE_ARRAY32: 2709 | case CMP_TYPE_FIXMAP: 2710 | case CMP_TYPE_MAP16: 2711 | case CMP_TYPE_MAP32: 2712 | obj->type = cmp_type; 2713 | 2714 | if (!read_obj_data(ctx, type_marker, obj)) { 2715 | return false; 2716 | } 2717 | 2718 | ctx->error = CMP_ERROR_SKIP_DEPTH_LIMIT_EXCEEDED; 2719 | 2720 | return false; 2721 | default: 2722 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2723 | return false; 2724 | } 2725 | 2726 | if (size) { 2727 | switch (cmp_type) { 2728 | case CMP_TYPE_FIXEXT1: 2729 | case CMP_TYPE_FIXEXT2: 2730 | case CMP_TYPE_FIXEXT4: 2731 | case CMP_TYPE_FIXEXT8: 2732 | case CMP_TYPE_FIXEXT16: 2733 | case CMP_TYPE_EXT8: 2734 | case CMP_TYPE_EXT16: 2735 | case CMP_TYPE_EXT32: 2736 | ++size; 2737 | break; 2738 | default: 2739 | break; 2740 | } 2741 | 2742 | if (!skip_bytes(ctx, size)) { 2743 | return false; 2744 | } 2745 | } 2746 | } 2747 | 2748 | return true; 2749 | } 2750 | 2751 | bool cmp_skip_object_flat(cmp_ctx_t *ctx, cmp_object_t *obj) { 2752 | size_t element_count = 1; 2753 | bool in_container = false; 2754 | 2755 | while (element_count) { 2756 | uint8_t type_marker = 0; 2757 | uint8_t cmp_type; 2758 | uint32_t size = 0; 2759 | 2760 | if (!read_type_marker(ctx, &type_marker)) { 2761 | return false; 2762 | } 2763 | 2764 | if (!type_marker_to_cmp_type(type_marker, &cmp_type)) { 2765 | ctx->error = CMP_ERROR_INVALID_TYPE; 2766 | return false; 2767 | } 2768 | 2769 | switch (cmp_type) { 2770 | case CMP_TYPE_FIXARRAY: 2771 | case CMP_TYPE_ARRAY16: 2772 | case CMP_TYPE_ARRAY32: 2773 | case CMP_TYPE_FIXMAP: 2774 | case CMP_TYPE_MAP16: 2775 | case CMP_TYPE_MAP32: 2776 | if (in_container) { 2777 | obj->type = cmp_type; 2778 | 2779 | if (!read_obj_data(ctx, type_marker, obj)) { 2780 | return false; 2781 | } 2782 | 2783 | ctx->error = CMP_ERROR_SKIP_DEPTH_LIMIT_EXCEEDED; 2784 | return false; 2785 | } 2786 | 2787 | in_container = true; 2788 | 2789 | break; 2790 | default: 2791 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2792 | return false; 2793 | } 2794 | 2795 | if (size) { 2796 | switch (cmp_type) { 2797 | case CMP_TYPE_FIXEXT1: 2798 | case CMP_TYPE_FIXEXT2: 2799 | case CMP_TYPE_FIXEXT4: 2800 | case CMP_TYPE_FIXEXT8: 2801 | case CMP_TYPE_FIXEXT16: 2802 | case CMP_TYPE_EXT8: 2803 | case CMP_TYPE_EXT16: 2804 | case CMP_TYPE_EXT32: 2805 | ++size; 2806 | break; 2807 | default: 2808 | break; 2809 | } 2810 | 2811 | if (!skip_bytes(ctx, size)) { 2812 | return false; 2813 | } 2814 | } 2815 | } 2816 | 2817 | element_count--; 2818 | 2819 | switch (cmp_type) { 2820 | case CMP_TYPE_FIXARRAY: 2821 | case CMP_TYPE_ARRAY16: 2822 | case CMP_TYPE_ARRAY32: 2823 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2824 | return false; 2825 | } 2826 | element_count += size; 2827 | break; 2828 | case CMP_TYPE_FIXMAP: 2829 | case CMP_TYPE_MAP16: 2830 | case CMP_TYPE_MAP32: 2831 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2832 | return false; 2833 | } 2834 | element_count += ((size_t)size) * 2; 2835 | break; 2836 | default: 2837 | break; 2838 | } 2839 | } 2840 | 2841 | return true; 2842 | } 2843 | 2844 | bool cmp_skip_object_no_limit(cmp_ctx_t *ctx) { 2845 | size_t element_count = 1; 2846 | 2847 | while (element_count) { 2848 | uint8_t type_marker = 0; 2849 | uint8_t cmp_type = 0; 2850 | uint32_t size = 0; 2851 | 2852 | if (!read_type_marker(ctx, &type_marker)) { 2853 | return false; 2854 | } 2855 | 2856 | if (!type_marker_to_cmp_type(type_marker, &cmp_type)) { 2857 | ctx->error = CMP_ERROR_INVALID_TYPE; 2858 | return false; 2859 | } 2860 | 2861 | switch (cmp_type) { 2862 | case CMP_TYPE_FIXARRAY: 2863 | case CMP_TYPE_ARRAY16: 2864 | case CMP_TYPE_ARRAY32: 2865 | case CMP_TYPE_FIXMAP: 2866 | case CMP_TYPE_MAP16: 2867 | case CMP_TYPE_MAP32: 2868 | break; 2869 | default: 2870 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2871 | return false; 2872 | } 2873 | 2874 | if (size) { 2875 | switch (cmp_type) { 2876 | case CMP_TYPE_FIXEXT1: 2877 | case CMP_TYPE_FIXEXT2: 2878 | case CMP_TYPE_FIXEXT4: 2879 | case CMP_TYPE_FIXEXT8: 2880 | case CMP_TYPE_FIXEXT16: 2881 | case CMP_TYPE_EXT8: 2882 | case CMP_TYPE_EXT16: 2883 | case CMP_TYPE_EXT32: 2884 | ++size; 2885 | break; 2886 | default: 2887 | break; 2888 | } 2889 | 2890 | if (!skip_bytes(ctx, size)) { 2891 | return false; 2892 | } 2893 | } 2894 | } 2895 | 2896 | element_count--; 2897 | 2898 | switch (cmp_type) { 2899 | case CMP_TYPE_FIXARRAY: 2900 | case CMP_TYPE_ARRAY16: 2901 | case CMP_TYPE_ARRAY32: 2902 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2903 | return false; 2904 | } 2905 | element_count += size; 2906 | break; 2907 | case CMP_TYPE_FIXMAP: 2908 | case CMP_TYPE_MAP16: 2909 | case CMP_TYPE_MAP32: 2910 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2911 | return false; 2912 | } 2913 | element_count += ((size_t)size) * 2; 2914 | break; 2915 | default: 2916 | break; 2917 | } 2918 | } 2919 | 2920 | return true; 2921 | } 2922 | 2923 | bool cmp_skip_object_limit(cmp_ctx_t *ctx, cmp_object_t *obj, uint32_t limit) { 2924 | size_t element_count = 1; 2925 | uint32_t depth = 0; 2926 | 2927 | while (element_count) { 2928 | uint8_t type_marker = 0; 2929 | uint8_t cmp_type; 2930 | uint32_t size = 0; 2931 | 2932 | if (!read_type_marker(ctx, &type_marker)) { 2933 | return false; 2934 | } 2935 | 2936 | if (!type_marker_to_cmp_type(type_marker, &cmp_type)) { 2937 | ctx->error = CMP_ERROR_INVALID_TYPE; 2938 | return false; 2939 | } 2940 | 2941 | switch (cmp_type) { 2942 | case CMP_TYPE_FIXARRAY: 2943 | case CMP_TYPE_ARRAY16: 2944 | case CMP_TYPE_ARRAY32: 2945 | case CMP_TYPE_FIXMAP: 2946 | case CMP_TYPE_MAP16: 2947 | case CMP_TYPE_MAP32: 2948 | ++depth; 2949 | 2950 | if (depth > limit) { 2951 | obj->type = cmp_type; 2952 | 2953 | if (!read_obj_data(ctx, type_marker, obj)) { 2954 | return false; 2955 | } 2956 | 2957 | ctx->error = CMP_ERROR_SKIP_DEPTH_LIMIT_EXCEEDED; 2958 | 2959 | return false; 2960 | } 2961 | 2962 | break; 2963 | default: 2964 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2965 | return false; 2966 | } 2967 | 2968 | if (size) { 2969 | switch (cmp_type) { 2970 | case CMP_TYPE_FIXEXT1: 2971 | case CMP_TYPE_FIXEXT2: 2972 | case CMP_TYPE_FIXEXT4: 2973 | case CMP_TYPE_FIXEXT8: 2974 | case CMP_TYPE_FIXEXT16: 2975 | case CMP_TYPE_EXT8: 2976 | case CMP_TYPE_EXT16: 2977 | case CMP_TYPE_EXT32: 2978 | ++size; 2979 | break; 2980 | default: 2981 | break; 2982 | } 2983 | 2984 | if (!skip_bytes(ctx, size)) { 2985 | return false; 2986 | } 2987 | } 2988 | } 2989 | 2990 | element_count--; 2991 | 2992 | switch (cmp_type) { 2993 | case CMP_TYPE_FIXARRAY: 2994 | case CMP_TYPE_ARRAY16: 2995 | case CMP_TYPE_ARRAY32: 2996 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 2997 | return false; 2998 | } 2999 | element_count += size; 3000 | break; 3001 | case CMP_TYPE_FIXMAP: 3002 | case CMP_TYPE_MAP16: 3003 | case CMP_TYPE_MAP32: 3004 | if (!read_type_size(ctx, type_marker, cmp_type, &size)) { 3005 | return false; 3006 | } 3007 | element_count += ((size_t)size) * 2; 3008 | break; 3009 | default: 3010 | break; 3011 | } 3012 | } 3013 | 3014 | return true; 3015 | } 3016 | 3017 | bool cmp_object_is_char(const cmp_object_t *obj) { 3018 | switch (obj->type) { 3019 | case CMP_TYPE_NEGATIVE_FIXNUM: 3020 | case CMP_TYPE_SINT8: 3021 | return true; 3022 | default: 3023 | return false; 3024 | } 3025 | } 3026 | 3027 | bool cmp_object_is_short(const cmp_object_t *obj) { 3028 | switch (obj->type) { 3029 | case CMP_TYPE_NEGATIVE_FIXNUM: 3030 | case CMP_TYPE_SINT8: 3031 | case CMP_TYPE_SINT16: 3032 | return true; 3033 | default: 3034 | return false; 3035 | } 3036 | } 3037 | 3038 | bool cmp_object_is_int(const cmp_object_t *obj) { 3039 | switch (obj->type) { 3040 | case CMP_TYPE_NEGATIVE_FIXNUM: 3041 | case CMP_TYPE_SINT8: 3042 | case CMP_TYPE_SINT16: 3043 | case CMP_TYPE_SINT32: 3044 | return true; 3045 | default: 3046 | return false; 3047 | } 3048 | } 3049 | 3050 | bool cmp_object_is_long(const cmp_object_t *obj) { 3051 | switch (obj->type) { 3052 | case CMP_TYPE_NEGATIVE_FIXNUM: 3053 | case CMP_TYPE_SINT8: 3054 | case CMP_TYPE_SINT16: 3055 | case CMP_TYPE_SINT32: 3056 | case CMP_TYPE_SINT64: 3057 | return true; 3058 | default: 3059 | return false; 3060 | } 3061 | } 3062 | 3063 | bool cmp_object_is_sinteger(const cmp_object_t *obj) { 3064 | return cmp_object_is_long(obj); 3065 | } 3066 | 3067 | bool cmp_object_is_uchar(const cmp_object_t *obj) { 3068 | switch (obj->type) { 3069 | case CMP_TYPE_POSITIVE_FIXNUM: 3070 | case CMP_TYPE_UINT8: 3071 | return true; 3072 | default: 3073 | return false; 3074 | } 3075 | } 3076 | 3077 | bool cmp_object_is_ushort(const cmp_object_t *obj) { 3078 | switch (obj->type) { 3079 | case CMP_TYPE_POSITIVE_FIXNUM: 3080 | case CMP_TYPE_UINT8: 3081 | return true; 3082 | case CMP_TYPE_UINT16: 3083 | return true; 3084 | default: 3085 | return false; 3086 | } 3087 | } 3088 | 3089 | bool cmp_object_is_uint(const cmp_object_t *obj) { 3090 | switch (obj->type) { 3091 | case CMP_TYPE_POSITIVE_FIXNUM: 3092 | case CMP_TYPE_UINT8: 3093 | case CMP_TYPE_UINT16: 3094 | case CMP_TYPE_UINT32: 3095 | return true; 3096 | default: 3097 | return false; 3098 | } 3099 | } 3100 | 3101 | bool cmp_object_is_ulong(const cmp_object_t *obj) { 3102 | switch (obj->type) { 3103 | case CMP_TYPE_POSITIVE_FIXNUM: 3104 | case CMP_TYPE_UINT8: 3105 | case CMP_TYPE_UINT16: 3106 | case CMP_TYPE_UINT32: 3107 | case CMP_TYPE_UINT64: 3108 | return true; 3109 | default: 3110 | return false; 3111 | } 3112 | } 3113 | 3114 | bool cmp_object_is_uinteger(const cmp_object_t *obj) { 3115 | return cmp_object_is_ulong(obj); 3116 | } 3117 | 3118 | bool cmp_object_is_float(const cmp_object_t *obj) { 3119 | if (obj->type == CMP_TYPE_FLOAT) 3120 | return true; 3121 | 3122 | return false; 3123 | } 3124 | 3125 | bool cmp_object_is_double(const cmp_object_t *obj) { 3126 | if (obj->type == CMP_TYPE_DOUBLE) 3127 | return true; 3128 | 3129 | return false; 3130 | } 3131 | 3132 | bool cmp_object_is_nil(const cmp_object_t *obj) { 3133 | if (obj->type == CMP_TYPE_NIL) 3134 | return true; 3135 | 3136 | return false; 3137 | } 3138 | 3139 | bool cmp_object_is_bool(const cmp_object_t *obj) { 3140 | if (obj->type == CMP_TYPE_BOOLEAN) 3141 | return true; 3142 | 3143 | return false; 3144 | } 3145 | 3146 | bool cmp_object_is_str(const cmp_object_t *obj) { 3147 | switch (obj->type) { 3148 | case CMP_TYPE_FIXSTR: 3149 | case CMP_TYPE_STR8: 3150 | case CMP_TYPE_STR16: 3151 | case CMP_TYPE_STR32: 3152 | return true; 3153 | default: 3154 | return false; 3155 | } 3156 | } 3157 | 3158 | bool cmp_object_is_bin(const cmp_object_t *obj) { 3159 | switch (obj->type) { 3160 | case CMP_TYPE_BIN8: 3161 | case CMP_TYPE_BIN16: 3162 | case CMP_TYPE_BIN32: 3163 | return true; 3164 | default: 3165 | return false; 3166 | } 3167 | } 3168 | 3169 | bool cmp_object_is_array(const cmp_object_t *obj) { 3170 | switch (obj->type) { 3171 | case CMP_TYPE_FIXARRAY: 3172 | case CMP_TYPE_ARRAY16: 3173 | case CMP_TYPE_ARRAY32: 3174 | return true; 3175 | default: 3176 | return false; 3177 | } 3178 | } 3179 | 3180 | bool cmp_object_is_map(const cmp_object_t *obj) { 3181 | switch (obj->type) { 3182 | case CMP_TYPE_FIXMAP: 3183 | case CMP_TYPE_MAP16: 3184 | case CMP_TYPE_MAP32: 3185 | return true; 3186 | default: 3187 | return false; 3188 | } 3189 | } 3190 | 3191 | bool cmp_object_is_ext(const cmp_object_t *obj) { 3192 | switch (obj->type) { 3193 | case CMP_TYPE_FIXEXT1: 3194 | case CMP_TYPE_FIXEXT2: 3195 | case CMP_TYPE_FIXEXT4: 3196 | case CMP_TYPE_FIXEXT8: 3197 | case CMP_TYPE_FIXEXT16: 3198 | case CMP_TYPE_EXT8: 3199 | case CMP_TYPE_EXT16: 3200 | case CMP_TYPE_EXT32: 3201 | return true; 3202 | default: 3203 | return false; 3204 | } 3205 | } 3206 | 3207 | bool cmp_object_as_char(const cmp_object_t *obj, int8_t *c) { 3208 | switch (obj->type) { 3209 | case CMP_TYPE_POSITIVE_FIXNUM: 3210 | case CMP_TYPE_NEGATIVE_FIXNUM: 3211 | case CMP_TYPE_SINT8: 3212 | *c = obj->as.s8; 3213 | return true; 3214 | case CMP_TYPE_UINT8: 3215 | if (obj->as.u8 <= 0x7F) { 3216 | *c = obj->as.s8; 3217 | return true; 3218 | } 3219 | else { 3220 | return false; 3221 | } 3222 | default: 3223 | return false; 3224 | } 3225 | } 3226 | 3227 | bool cmp_object_as_short(const cmp_object_t *obj, int16_t *s) { 3228 | switch (obj->type) { 3229 | case CMP_TYPE_POSITIVE_FIXNUM: 3230 | case CMP_TYPE_NEGATIVE_FIXNUM: 3231 | case CMP_TYPE_SINT8: 3232 | *s = obj->as.s8; 3233 | return true; 3234 | case CMP_TYPE_UINT8: 3235 | *s = obj->as.u8; 3236 | return true; 3237 | case CMP_TYPE_SINT16: 3238 | *s = obj->as.s16; 3239 | return true; 3240 | case CMP_TYPE_UINT16: 3241 | if (obj->as.u16 <= 0x7FFF) { 3242 | *s = (int16_t)obj->as.u16; 3243 | return true; 3244 | } 3245 | else { 3246 | return false; 3247 | } 3248 | default: 3249 | return false; 3250 | } 3251 | } 3252 | 3253 | bool cmp_object_as_int(const cmp_object_t *obj, int32_t *i) { 3254 | switch (obj->type) { 3255 | case CMP_TYPE_POSITIVE_FIXNUM: 3256 | case CMP_TYPE_NEGATIVE_FIXNUM: 3257 | case CMP_TYPE_SINT8: 3258 | *i = obj->as.s8; 3259 | return true; 3260 | case CMP_TYPE_UINT8: 3261 | *i = obj->as.u8; 3262 | return true; 3263 | case CMP_TYPE_SINT16: 3264 | *i = obj->as.s16; 3265 | return true; 3266 | case CMP_TYPE_UINT16: 3267 | *i = obj->as.u16; 3268 | return true; 3269 | case CMP_TYPE_SINT32: 3270 | *i = obj->as.s32; 3271 | return true; 3272 | case CMP_TYPE_UINT32: 3273 | if (obj->as.u32 <= 0x7FFFFFFF) { 3274 | *i = (int32_t)obj->as.u32; 3275 | return true; 3276 | } 3277 | else { 3278 | return false; 3279 | } 3280 | default: 3281 | return false; 3282 | } 3283 | } 3284 | 3285 | bool cmp_object_as_long(const cmp_object_t *obj, int64_t *d) { 3286 | switch (obj->type) { 3287 | case CMP_TYPE_POSITIVE_FIXNUM: 3288 | case CMP_TYPE_NEGATIVE_FIXNUM: 3289 | case CMP_TYPE_SINT8: 3290 | *d = obj->as.s8; 3291 | return true; 3292 | case CMP_TYPE_UINT8: 3293 | *d = obj->as.u8; 3294 | return true; 3295 | case CMP_TYPE_SINT16: 3296 | *d = obj->as.s16; 3297 | return true; 3298 | case CMP_TYPE_UINT16: 3299 | *d = obj->as.u16; 3300 | return true; 3301 | case CMP_TYPE_SINT32: 3302 | *d = obj->as.s32; 3303 | return true; 3304 | case CMP_TYPE_UINT32: 3305 | *d = obj->as.u32; 3306 | return true; 3307 | case CMP_TYPE_SINT64: 3308 | *d = obj->as.s64; 3309 | return true; 3310 | case CMP_TYPE_UINT64: 3311 | if (obj->as.u64 <= UINT64_C(0x7FFFFFFFFFFFFFFF)) { 3312 | *d = (int64_t)obj->as.u64; 3313 | return true; 3314 | } 3315 | else { 3316 | return false; 3317 | } 3318 | default: 3319 | return false; 3320 | } 3321 | } 3322 | 3323 | bool cmp_object_as_sinteger(const cmp_object_t *obj, int64_t *d) { 3324 | return cmp_object_as_long(obj, d); 3325 | } 3326 | 3327 | bool cmp_object_as_uchar(const cmp_object_t *obj, uint8_t *c) { 3328 | switch (obj->type) { 3329 | case CMP_TYPE_POSITIVE_FIXNUM: 3330 | case CMP_TYPE_UINT8: 3331 | *c = obj->as.u8; 3332 | return true; 3333 | default: 3334 | return false; 3335 | } 3336 | } 3337 | 3338 | bool cmp_object_as_ushort(const cmp_object_t *obj, uint16_t *s) { 3339 | switch (obj->type) { 3340 | case CMP_TYPE_POSITIVE_FIXNUM: 3341 | case CMP_TYPE_UINT8: 3342 | *s = obj->as.u8; 3343 | return true; 3344 | case CMP_TYPE_UINT16: 3345 | *s = obj->as.u16; 3346 | return true; 3347 | default: 3348 | return false; 3349 | } 3350 | } 3351 | 3352 | bool cmp_object_as_uint(const cmp_object_t *obj, uint32_t *i) { 3353 | switch (obj->type) { 3354 | case CMP_TYPE_POSITIVE_FIXNUM: 3355 | case CMP_TYPE_UINT8: 3356 | *i = obj->as.u8; 3357 | return true; 3358 | case CMP_TYPE_UINT16: 3359 | *i = obj->as.u16; 3360 | return true; 3361 | case CMP_TYPE_UINT32: 3362 | *i = obj->as.u32; 3363 | return true; 3364 | default: 3365 | return false; 3366 | } 3367 | } 3368 | 3369 | bool cmp_object_as_ulong(const cmp_object_t *obj, uint64_t *u) { 3370 | switch (obj->type) { 3371 | case CMP_TYPE_POSITIVE_FIXNUM: 3372 | case CMP_TYPE_UINT8: 3373 | *u = obj->as.u8; 3374 | return true; 3375 | case CMP_TYPE_UINT16: 3376 | *u = obj->as.u16; 3377 | return true; 3378 | case CMP_TYPE_UINT32: 3379 | *u = obj->as.u32; 3380 | return true; 3381 | case CMP_TYPE_UINT64: 3382 | *u = obj->as.u64; 3383 | return true; 3384 | default: 3385 | return false; 3386 | } 3387 | } 3388 | 3389 | bool cmp_object_as_uinteger(const cmp_object_t *obj, uint64_t *u) { 3390 | return cmp_object_as_ulong(obj, u); 3391 | } 3392 | 3393 | #ifndef CMP_NO_FLOAT 3394 | bool cmp_object_as_float(const cmp_object_t *obj, float *f) { 3395 | if (obj->type == CMP_TYPE_FLOAT) { 3396 | *f = obj->as.flt; 3397 | return true; 3398 | } 3399 | 3400 | return false; 3401 | } 3402 | 3403 | bool cmp_object_as_double(const cmp_object_t *obj, double *d) { 3404 | if (obj->type == CMP_TYPE_DOUBLE) { 3405 | *d = obj->as.dbl; 3406 | return true; 3407 | } 3408 | 3409 | return false; 3410 | } 3411 | #endif /* CMP_NO_FLOAT */ 3412 | 3413 | bool cmp_object_as_bool(const cmp_object_t *obj, bool *b) { 3414 | if (obj->type == CMP_TYPE_BOOLEAN) { 3415 | if (obj->as.boolean) 3416 | *b = true; 3417 | else 3418 | *b = false; 3419 | 3420 | return true; 3421 | } 3422 | 3423 | return false; 3424 | } 3425 | 3426 | bool cmp_object_as_str(const cmp_object_t *obj, uint32_t *size) { 3427 | switch (obj->type) { 3428 | case CMP_TYPE_FIXSTR: 3429 | case CMP_TYPE_STR8: 3430 | case CMP_TYPE_STR16: 3431 | case CMP_TYPE_STR32: 3432 | *size = obj->as.str_size; 3433 | return true; 3434 | default: 3435 | return false; 3436 | } 3437 | } 3438 | 3439 | bool cmp_object_as_bin(const cmp_object_t *obj, uint32_t *size) { 3440 | switch (obj->type) { 3441 | case CMP_TYPE_BIN8: 3442 | case CMP_TYPE_BIN16: 3443 | case CMP_TYPE_BIN32: 3444 | *size = obj->as.bin_size; 3445 | return true; 3446 | default: 3447 | return false; 3448 | } 3449 | } 3450 | 3451 | bool cmp_object_as_array(const cmp_object_t *obj, uint32_t *size) { 3452 | switch (obj->type) { 3453 | case CMP_TYPE_FIXARRAY: 3454 | case CMP_TYPE_ARRAY16: 3455 | case CMP_TYPE_ARRAY32: 3456 | *size = obj->as.array_size; 3457 | return true; 3458 | default: 3459 | return false; 3460 | } 3461 | } 3462 | 3463 | bool cmp_object_as_map(const cmp_object_t *obj, uint32_t *size) { 3464 | switch (obj->type) { 3465 | case CMP_TYPE_FIXMAP: 3466 | case CMP_TYPE_MAP16: 3467 | case CMP_TYPE_MAP32: 3468 | *size = obj->as.map_size; 3469 | return true; 3470 | default: 3471 | return false; 3472 | } 3473 | } 3474 | 3475 | bool cmp_object_as_ext(const cmp_object_t *obj, int8_t *type, uint32_t *size) { 3476 | switch (obj->type) { 3477 | case CMP_TYPE_FIXEXT1: 3478 | case CMP_TYPE_FIXEXT2: 3479 | case CMP_TYPE_FIXEXT4: 3480 | case CMP_TYPE_FIXEXT8: 3481 | case CMP_TYPE_FIXEXT16: 3482 | case CMP_TYPE_EXT8: 3483 | case CMP_TYPE_EXT16: 3484 | case CMP_TYPE_EXT32: 3485 | *type = obj->as.ext.type; 3486 | *size = obj->as.ext.size; 3487 | return true; 3488 | default: 3489 | return false; 3490 | } 3491 | } 3492 | 3493 | bool cmp_object_to_str(cmp_ctx_t *ctx, const cmp_object_t *obj, char *data, 3494 | uint32_t buf_size) { 3495 | uint32_t str_size = 0; 3496 | 3497 | switch (obj->type) { 3498 | case CMP_TYPE_FIXSTR: 3499 | case CMP_TYPE_STR8: 3500 | case CMP_TYPE_STR16: 3501 | case CMP_TYPE_STR32: 3502 | str_size = obj->as.str_size; 3503 | if (str_size >= buf_size) { 3504 | ctx->error = CMP_ERROR_STR_DATA_LENGTH_TOO_LONG; 3505 | return false; 3506 | } 3507 | 3508 | if (!ctx->read(ctx, data, str_size)) { 3509 | ctx->error = CMP_ERROR_DATA_READING; 3510 | return false; 3511 | } 3512 | 3513 | data[str_size] = 0; 3514 | return true; 3515 | default: 3516 | return false; 3517 | } 3518 | } 3519 | 3520 | bool cmp_object_to_bin(cmp_ctx_t *ctx, const cmp_object_t *obj, void *data, 3521 | uint32_t buf_size) { 3522 | uint32_t bin_size = 0; 3523 | 3524 | switch (obj->type) { 3525 | case CMP_TYPE_BIN8: 3526 | case CMP_TYPE_BIN16: 3527 | case CMP_TYPE_BIN32: 3528 | bin_size = obj->as.bin_size; 3529 | if (bin_size > buf_size) { 3530 | ctx->error = CMP_ERROR_BIN_DATA_LENGTH_TOO_LONG; 3531 | return false; 3532 | } 3533 | 3534 | if (!ctx->read(ctx, data, bin_size)) { 3535 | ctx->error = CMP_ERROR_DATA_READING; 3536 | return false; 3537 | } 3538 | return true; 3539 | default: 3540 | return false; 3541 | } 3542 | } 3543 | 3544 | /* vi: set et ts=2 sw=2: */ 3545 | 3546 | --------------------------------------------------------------------------------