├── .editorconfig ├── .github └── workflows │ └── tinf-ci-workflow.yaml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── examples └── tgunzip │ └── tgunzip.c ├── src ├── adler32.c ├── crc32.c ├── tinf.h ├── tinfgzip.c ├── tinflate.c └── tinfzlib.c ├── test ├── greatest.h └── test_tinf.c └── tools ├── gengztest.py ├── genzlibtest.py └── mkzdata.c /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | 7 | [Makefile*] 8 | indent_style = tab 9 | 10 | [*.{c,h}] 11 | indent_style = tab 12 | indent_size = 8 13 | 14 | [*.yml] 15 | indent_style = space 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.github/workflows/tinf-ci-workflow.yaml: -------------------------------------------------------------------------------- 1 | name: tinf CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | windows: 7 | name: Windows ${{ matrix.config.name }} 8 | runs-on: windows-latest 9 | 10 | strategy: 11 | matrix: 12 | config: 13 | - name: MSVC x64 14 | generator: Visual Studio 16 2019 15 | cmake-flags: -A x64 16 | 17 | steps: 18 | - uses: actions/checkout@v2 19 | 20 | - name: Configure 21 | run: cmake -G "${{ matrix.config.generator }}" ${{ matrix.config.cmake-flags }} -B build 22 | 23 | - name: Build 24 | run: cd build && cmake --build . --config Debug 25 | 26 | - name: Test 27 | run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 -C Debug 28 | 29 | linux: 30 | name: Linux ${{ matrix.config.name }} 31 | runs-on: ubuntu-latest 32 | env: 33 | CC: ${{ matrix.config.cc }} 34 | 35 | strategy: 36 | matrix: 37 | config: 38 | - name: Clang UBSan 39 | cc: clang 40 | cmake-flags: -DCMAKE_C_FLAGS_DEBUG='-g -fsanitize=undefined' 41 | 42 | - name: Clang ASan 43 | cc: clang 44 | cmake-flags: -DCMAKE_C_FLAGS_DEBUG='-O1 -g -fsanitize=address -fno-omit-frame-pointer' 45 | 46 | steps: 47 | - uses: actions/checkout@v2 48 | 49 | - name: Configure 50 | run: cmake ${{ matrix.config.cmake-flags }} -DCMAKE_BUILD_TYPE=Debug -B build 51 | 52 | - name: Build 53 | run: cd build && make VERBOSE=1 54 | 55 | - name: Test 56 | run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 57 | 58 | coverage: 59 | name: Linux Coverage 60 | runs-on: ubuntu-latest 61 | 62 | steps: 63 | - uses: actions/checkout@v2 64 | 65 | - name: Configure 66 | run: cmake -DCMAKE_C_FLAGS_DEBUG='-g -O0 --coverage' -DCMAKE_BUILD_TYPE=Debug -B build 67 | 68 | - name: Build 69 | run: cd build && make VERBOSE=1 70 | 71 | - name: Test 72 | run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 73 | 74 | - name: Generate coverage 75 | run: cd build && gcov -abcfu CMakeFiles/tinf.dir/src/*.c.gcno -o CMakeFiles/tinf.dir/src 76 | 77 | - name: Upload coverage to Codecov 78 | uses: codecov/codecov-action@v2 79 | with: 80 | directory: ./build/ 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.obj 3 | 4 | *.a 5 | *.lib 6 | 7 | *.so 8 | *.so.* 9 | *.dll 10 | 11 | *.exe 12 | 13 | /build/ 14 | /doc/ 15 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | 3 | project(tinf C) 4 | 5 | include(CheckCCompilerFlag) 6 | include(CTest) 7 | 8 | # Check if tinf is the top-level project (standalone), or a subproject 9 | set(_tinf_standalone FALSE) 10 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) 11 | set(_tinf_standalone TRUE) 12 | endif() 13 | 14 | # TINF_BUILD_TESTING controls if tinf adds testing support 15 | # 16 | # When built standalone, it defaults to the value of BUILD_TESTING if set. 17 | # An optional prefix for the test names can be set with TINF_TEST_PREFIX. 18 | set(_tinf_testing_default ON) 19 | if(_tinf_standalone) 20 | if(DEFINED BUILD_TESTING) 21 | set(_tinf_testing_default ${BUILD_TESTING}) 22 | endif() 23 | else() 24 | set(_tinf_testing_default OFF) 25 | endif() 26 | option(TINF_BUILD_TESTING "Add testing support" ${_tinf_testing_default}) 27 | unset(_tinf_testing_default) 28 | 29 | mark_as_advanced(TINF_TEST_PREFIX) 30 | 31 | # Take a list of compiler flags and add those which the compiler accepts to 32 | # the COMPILE_OPTIONS directory property 33 | function(add_valid_c_compile_options) 34 | foreach(flag IN LISTS ARGN) 35 | string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" flag_var "CFLAG_${flag}") 36 | check_c_compiler_flag("${flag}" ${flag_var}) 37 | if(${flag_var}) 38 | add_compile_options("${flag}") 39 | endif() 40 | endforeach() 41 | endfunction() 42 | 43 | if(MSVC) 44 | add_valid_c_compile_options(/W3) 45 | else() 46 | add_valid_c_compile_options(-Wall -Wextra -pedantic) 47 | endif() 48 | 49 | # 50 | # tinf 51 | # 52 | add_library(tinf 53 | src/adler32.c 54 | src/crc32.c 55 | src/tinfgzip.c 56 | src/tinflate.c 57 | src/tinfzlib.c 58 | src/tinf.h 59 | ) 60 | target_include_directories(tinf PUBLIC $) 61 | 62 | # 63 | # tgunzip 64 | # 65 | add_executable(tgunzip examples/tgunzip/tgunzip.c) 66 | target_link_libraries(tgunzip PRIVATE tinf) 67 | if(MSVC) 68 | target_compile_definitions(tgunzip PRIVATE _CRT_SECURE_NO_WARNINGS) 69 | endif() 70 | 71 | # 72 | # Tests 73 | # 74 | if(TINF_BUILD_TESTING) 75 | add_executable(test_tinf test/test_tinf.c) 76 | target_link_libraries(test_tinf PRIVATE tinf) 77 | if(MSVC) 78 | target_compile_definitions(test_tinf PRIVATE _CRT_SECURE_NO_WARNINGS) 79 | endif() 80 | 81 | add_test("${TINF_TEST_PREFIX}tinf" test_tinf) 82 | endif() 83 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The zlib License (Zlib) 2 | 3 | Copyright (c) 2003-2019 Joergen Ibsen 4 | 5 | This software is provided 'as-is', without any express or implied 6 | warranty. In no event will the authors be held liable for any damages 7 | arising from the use of this software. 8 | 9 | Permission is granted to anyone to use this software for any purpose, 10 | including commercial applications, and to alter it and redistribute it 11 | freely, subject to the following restrictions: 12 | 13 | 1. The origin of this software must not be misrepresented; you must 14 | not claim that you wrote the original software. If you use this 15 | software in a product, an acknowledgment in the product 16 | documentation would be appreciated but is not required. 17 | 18 | 2. Altered source versions must be plainly marked as such, and must 19 | not be misrepresented as being the original software. 20 | 21 | 3. This notice may not be removed or altered from any source 22 | distribution. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | tinf - tiny inflate library 3 | =========================== 4 | 5 | Version 1.2.1 6 | 7 | Copyright (c) 2003-2019 Joergen Ibsen 8 | 9 | 10 | 11 | [![tinf CI](https://github.com/jibsen/tinf/actions/workflows/tinf-ci-workflow.yaml/badge.svg)](https://github.com/jibsen/tinf/actions) [![codecov](https://codecov.io/gh/jibsen/tinf/branch/master/graph/badge.svg)](https://codecov.io/gh/jibsen/tinf) 12 | 13 | About 14 | ----- 15 | 16 | tinf is a small library implementing the decompression algorithm for the 17 | [deflate][wpdeflate] compressed data format (called 'inflate'). Deflate 18 | compression is used in e.g. zlib, gzip, zip, and png. 19 | 20 | I wrote it because I needed a small in-memory zlib decompressor for a self- 21 | extracting archive, and the zlib library added 15k to my program. The tinf 22 | code added only 2k. 23 | 24 | Naturally the size difference is insignificant in most cases. Also, the 25 | zlib library has many more features, is well-tested, and mostly faster. 26 | But if you have a project that calls for a small and simple deflate 27 | decompressor, give it a try :-) 28 | 29 | [wpdeflate]: https://en.wikipedia.org/wiki/DEFLATE 30 | 31 | 32 | Usage 33 | ----- 34 | 35 | The include file `src/tinf.h` contains documentation in the form of 36 | [doxygen][] comments. 37 | 38 | Wrappers for decompressing zlib and gzip data in memory are supplied. 39 | 40 | tgunzip, an example command-line gzip decompressor in C, is included. 41 | 42 | tinf uses [CMake][] to generate build systems. To create one for the tools on 43 | your platform, and build tinf, use something along the lines of: 44 | 45 | ~~~sh 46 | mkdir build 47 | cd build 48 | cmake -DCMAKE_BUILD_TYPE=Release .. 49 | cmake --build . --config Release 50 | ~~~ 51 | 52 | You can also compile the source files and link them into your project. CMake 53 | just provides an easy way to build and test across various platforms and 54 | toolsets. 55 | 56 | [doxygen]: http://www.doxygen.org/ 57 | [CMake]: http://www.cmake.org/ 58 | 59 | 60 | Notes 61 | ----- 62 | 63 | tinf requires int to be at least 32-bit. 64 | 65 | The inflate algorithm and data format are from 'DEFLATE Compressed Data 66 | Format Specification version 1.3' ([RFC 1951][deflate]). 67 | 68 | The zlib data format is from 'ZLIB Compressed Data Format Specification 69 | version 3.3' ([RFC 1950][zlib]). 70 | 71 | The gzip data format is from 'GZIP file format specification version 4.3' 72 | ([RFC 1952][gzip]). 73 | 74 | The original version of tinf assumed it was given valid compressed data, and 75 | that there was sufficient space for the decompressed data. If code size is 76 | of the utmost importance, and you are absolutely sure you can trust the 77 | compressed data, you may want to check out [tinf 1.1.0][tinf110] (last 78 | release without security checks). 79 | 80 | Ideas for future versions: 81 | 82 | - Memory for the `tinf_data` object should be passed, to avoid using more 83 | than 1k of stack space 84 | - Wrappers for unpacking zip archives and png images 85 | - Blocking of some sort, so everything does not have to be in memory 86 | - Optional table-based Huffman decoder 87 | - Small compressor using fixed Huffman trees 88 | 89 | [deflate]: http://www.rfc-editor.org/rfc/rfc1951.txt 90 | [zlib]: http://www.rfc-editor.org/rfc/rfc1950.txt 91 | [gzip]: http://www.rfc-editor.org/rfc/rfc1952.txt 92 | [tinf110]: https://github.com/jibsen/tinf/releases/tag/v1.1.0 93 | 94 | 95 | Related Projects 96 | ---------------- 97 | 98 | - [puff](https://github.com/madler/zlib) (in the contrib folder of zlib) 99 | - [tinfl](https://github.com/richgel999/miniz) (part of miniz) 100 | - [uzlib](https://github.com/pfalcon/uzlib) 101 | - [gdunzip](https://github.com/jellehermsen/gdunzip) (GDScript) 102 | - [TinyDeflate](https://github.com/bisqwit/TinyDeflate) (C++) 103 | - [tiny-inflate](https://github.com/foliojs/tiny-inflate) (JavaScript) 104 | - [tinflate](http://achurch.org/tinflate.c) (unrelated to this project) 105 | - The [Wikipedia page for deflate](https://en.wikipedia.org/wiki/DEFLATE) 106 | has a list of implementations 107 | 108 | 109 | License 110 | ------- 111 | 112 | This projected is licensed under the [zlib License](LICENSE) (Zlib). 113 | -------------------------------------------------------------------------------- /examples/tgunzip/tgunzip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tgunzip - gzip decompressor example 3 | * 4 | * Copyright (c) 2003-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | #include "tinf.h" 31 | 32 | static unsigned int read_le32(const unsigned char *p) 33 | { 34 | return ((unsigned int) p[0]) 35 | | ((unsigned int) p[1] << 8) 36 | | ((unsigned int) p[2] << 16) 37 | | ((unsigned int) p[3] << 24); 38 | } 39 | 40 | static void printf_error(const char *fmt, ...) 41 | { 42 | va_list arg; 43 | 44 | fputs("tgunzip: ", stderr); 45 | 46 | va_start(arg, fmt); 47 | vfprintf(stderr, fmt, arg); 48 | va_end(arg); 49 | 50 | fputs("\n", stderr); 51 | } 52 | 53 | int main(int argc, char *argv[]) 54 | { 55 | FILE *fin = NULL; 56 | FILE *fout = NULL; 57 | unsigned char *source = NULL; 58 | unsigned char *dest = NULL; 59 | unsigned int len, dlen, outlen; 60 | int retval = EXIT_FAILURE; 61 | int res; 62 | 63 | printf("tgunzip " TINF_VER_STRING " - example from the tiny inflate library (www.ibsensoftware.com)\n\n"); 64 | 65 | if (argc != 3) { 66 | fputs("usage: tgunzip INFILE OUTFILE\n\n" 67 | "Both input and output are kept in memory, so do not use this on huge files.\n", stderr); 68 | return EXIT_FAILURE; 69 | } 70 | 71 | tinf_init(); 72 | 73 | /* -- Open files -- */ 74 | 75 | if ((fin = fopen(argv[1], "rb")) == NULL) { 76 | printf_error("unable to open input file '%s'", argv[1]); 77 | goto out; 78 | } 79 | 80 | if ((fout = fopen(argv[2], "wb")) == NULL) { 81 | printf_error("unable to create output file '%s'", argv[2]); 82 | goto out; 83 | } 84 | 85 | /* -- Read source -- */ 86 | 87 | fseek(fin, 0, SEEK_END); 88 | 89 | len = ftell(fin); 90 | 91 | fseek(fin, 0, SEEK_SET); 92 | 93 | if (len < 18) { 94 | printf_error("input too small to be gzip"); 95 | goto out; 96 | } 97 | 98 | source = (unsigned char *) malloc(len); 99 | 100 | if (source == NULL) { 101 | printf_error("not enough memory"); 102 | goto out; 103 | } 104 | 105 | if (fread(source, 1, len, fin) != len) { 106 | printf_error("error reading input file"); 107 | goto out; 108 | } 109 | 110 | /* -- Get decompressed length -- */ 111 | 112 | dlen = read_le32(&source[len - 4]); 113 | 114 | dest = (unsigned char *) malloc(dlen ? dlen : 1); 115 | 116 | if (dest == NULL) { 117 | printf_error("not enough memory"); 118 | goto out; 119 | } 120 | 121 | /* -- Decompress data -- */ 122 | 123 | outlen = dlen; 124 | 125 | res = tinf_gzip_uncompress(dest, &outlen, source, len); 126 | 127 | if ((res != TINF_OK) || (outlen != dlen)) { 128 | printf_error("decompression failed"); 129 | goto out; 130 | } 131 | 132 | printf("decompressed %u bytes\n", outlen); 133 | 134 | /* -- Write output -- */ 135 | 136 | fwrite(dest, 1, outlen, fout); 137 | 138 | retval = EXIT_SUCCESS; 139 | 140 | out: 141 | if (fin != NULL) { 142 | fclose(fin); 143 | } 144 | 145 | if (fout != NULL) { 146 | fclose(fout); 147 | } 148 | 149 | if (source != NULL) { 150 | free(source); 151 | } 152 | 153 | if (dest != NULL) { 154 | free(dest); 155 | } 156 | 157 | return retval; 158 | } 159 | -------------------------------------------------------------------------------- /src/adler32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Adler-32 checksum 3 | * 4 | * Copyright (c) 2003-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | /* 27 | * Adler-32 algorithm taken from the zlib source, which is 28 | * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler 29 | */ 30 | 31 | #include "tinf.h" 32 | 33 | #define A32_BASE 65521 34 | #define A32_NMAX 5552 35 | 36 | unsigned int tinf_adler32(const void *data, unsigned int length) 37 | { 38 | const unsigned char *buf = (const unsigned char *) data; 39 | 40 | unsigned int s1 = 1; 41 | unsigned int s2 = 0; 42 | 43 | while (length > 0) { 44 | int k = length < A32_NMAX ? length : A32_NMAX; 45 | int i; 46 | 47 | for (i = k / 16; i; --i, buf += 16) { 48 | s1 += buf[0]; 49 | s2 += s1; 50 | s1 += buf[1]; 51 | s2 += s1; 52 | s1 += buf[2]; 53 | s2 += s1; 54 | s1 += buf[3]; 55 | s2 += s1; 56 | s1 += buf[4]; 57 | s2 += s1; 58 | s1 += buf[5]; 59 | s2 += s1; 60 | s1 += buf[6]; 61 | s2 += s1; 62 | s1 += buf[7]; 63 | s2 += s1; 64 | 65 | s1 += buf[8]; 66 | s2 += s1; 67 | s1 += buf[9]; 68 | s2 += s1; 69 | s1 += buf[10]; 70 | s2 += s1; 71 | s1 += buf[11]; 72 | s2 += s1; 73 | s1 += buf[12]; 74 | s2 += s1; 75 | s1 += buf[13]; 76 | s2 += s1; 77 | s1 += buf[14]; 78 | s2 += s1; 79 | s1 += buf[15]; 80 | s2 += s1; 81 | } 82 | 83 | for (i = k % 16; i; --i) { 84 | s1 += *buf++; 85 | s2 += s1; 86 | } 87 | 88 | s1 %= A32_BASE; 89 | s2 %= A32_BASE; 90 | 91 | length -= k; 92 | } 93 | 94 | return (s2 << 16) | s1; 95 | } 96 | -------------------------------------------------------------------------------- /src/crc32.c: -------------------------------------------------------------------------------- 1 | /* 2 | * CRC32 checksum 3 | * 4 | * Copyright (c) 1998-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | /* 27 | * CRC32 algorithm taken from the zlib source, which is 28 | * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler 29 | */ 30 | 31 | #include "tinf.h" 32 | 33 | static const unsigned int tinf_crc32tab[16] = { 34 | 0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190, 35 | 0x6B6B51F4, 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344, 36 | 0xD6D6A3E8, 0xCB61B38C, 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278, 37 | 0xBDBDF21C 38 | }; 39 | 40 | unsigned int tinf_crc32(const void *data, unsigned int length) 41 | { 42 | const unsigned char *buf = (const unsigned char *) data; 43 | unsigned int crc = 0xFFFFFFFF; 44 | unsigned int i; 45 | 46 | if (length == 0) { 47 | return 0; 48 | } 49 | 50 | for (i = 0; i < length; ++i) { 51 | crc ^= buf[i]; 52 | crc = tinf_crc32tab[crc & 0x0F] ^ (crc >> 4); 53 | crc = tinf_crc32tab[crc & 0x0F] ^ (crc >> 4); 54 | } 55 | 56 | return crc ^ 0xFFFFFFFF; 57 | } 58 | -------------------------------------------------------------------------------- /src/tinf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * tinf - tiny inflate library (inflate, gzip, zlib) 3 | * 4 | * Copyright (c) 2003-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | #ifndef TINF_H_INCLUDED 27 | #define TINF_H_INCLUDED 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | #define TINF_VER_MAJOR 1 /**< Major version number */ 34 | #define TINF_VER_MINOR 2 /**< Minor version number */ 35 | #define TINF_VER_PATCH 1 /**< Patch version number */ 36 | #define TINF_VER_STRING "1.2.1" /**< Version number as a string */ 37 | 38 | #ifndef TINFCC 39 | # ifdef __WATCOMC__ 40 | # define TINFCC __cdecl 41 | # else 42 | # define TINFCC 43 | # endif 44 | #endif 45 | 46 | /** 47 | * Status codes returned. 48 | * 49 | * @see tinf_uncompress, tinf_gzip_uncompress, tinf_zlib_uncompress 50 | */ 51 | typedef enum { 52 | TINF_OK = 0, /**< Success */ 53 | TINF_DATA_ERROR = -3, /**< Input error */ 54 | TINF_BUF_ERROR = -5 /**< Not enough room for output */ 55 | } tinf_error_code; 56 | 57 | /** 58 | * Initialize global data used by tinf. 59 | * 60 | * @deprecated No longer required, may be removed in a future version. 61 | */ 62 | void TINFCC tinf_init(void); 63 | 64 | /** 65 | * Decompress `sourceLen` bytes of deflate data from `source` to `dest`. 66 | * 67 | * The variable `destLen` points to must contain the size of `dest` on entry, 68 | * and will be set to the size of the decompressed data on success. 69 | * 70 | * Reads at most `sourceLen` bytes from `source`. 71 | * Writes at most `*destLen` bytes to `dest`. 72 | * 73 | * @param dest pointer to where to place decompressed data 74 | * @param destLen pointer to variable containing size of `dest` 75 | * @param source pointer to compressed data 76 | * @param sourceLen size of compressed data 77 | * @return `TINF_OK` on success, error code on error 78 | */ 79 | int TINFCC tinf_uncompress(void *dest, unsigned int *destLen, 80 | const void *source, unsigned int sourceLen); 81 | 82 | /** 83 | * Decompress `sourceLen` bytes of gzip data from `source` to `dest`. 84 | * 85 | * The variable `destLen` points to must contain the size of `dest` on entry, 86 | * and will be set to the size of the decompressed data on success. 87 | * 88 | * Reads at most `sourceLen` bytes from `source`. 89 | * Writes at most `*destLen` bytes to `dest`. 90 | * 91 | * @param dest pointer to where to place decompressed data 92 | * @param destLen pointer to variable containing size of `dest` 93 | * @param source pointer to compressed data 94 | * @param sourceLen size of compressed data 95 | * @return `TINF_OK` on success, error code on error 96 | */ 97 | int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen, 98 | const void *source, unsigned int sourceLen); 99 | 100 | /** 101 | * Decompress `sourceLen` bytes of zlib data from `source` to `dest`. 102 | * 103 | * The variable `destLen` points to must contain the size of `dest` on entry, 104 | * and will be set to the size of the decompressed data on success. 105 | * 106 | * Reads at most `sourceLen` bytes from `source`. 107 | * Writes at most `*destLen` bytes to `dest`. 108 | * 109 | * @param dest pointer to where to place decompressed data 110 | * @param destLen pointer to variable containing size of `dest` 111 | * @param source pointer to compressed data 112 | * @param sourceLen size of compressed data 113 | * @return `TINF_OK` on success, error code on error 114 | */ 115 | int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen, 116 | const void *source, unsigned int sourceLen); 117 | 118 | /** 119 | * Compute Adler-32 checksum of `length` bytes starting at `data`. 120 | * 121 | * @param data pointer to data 122 | * @param length size of data 123 | * @return Adler-32 checksum 124 | */ 125 | unsigned int TINFCC tinf_adler32(const void *data, unsigned int length); 126 | 127 | /** 128 | * Compute CRC32 checksum of `length` bytes starting at `data`. 129 | * 130 | * @param data pointer to data 131 | * @param length size of data 132 | * @return CRC32 checksum 133 | */ 134 | unsigned int TINFCC tinf_crc32(const void *data, unsigned int length); 135 | 136 | #ifdef __cplusplus 137 | } /* extern "C" */ 138 | #endif 139 | 140 | #endif /* TINF_H_INCLUDED */ 141 | -------------------------------------------------------------------------------- /src/tinfgzip.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tinfgzip - tiny gzip decompressor 3 | * 4 | * Copyright (c) 2003-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | #include "tinf.h" 27 | 28 | typedef enum { 29 | FTEXT = 1, 30 | FHCRC = 2, 31 | FEXTRA = 4, 32 | FNAME = 8, 33 | FCOMMENT = 16 34 | } tinf_gzip_flag; 35 | 36 | static unsigned int read_le16(const unsigned char *p) 37 | { 38 | return ((unsigned int) p[0]) 39 | | ((unsigned int) p[1] << 8); 40 | } 41 | 42 | static unsigned int read_le32(const unsigned char *p) 43 | { 44 | return ((unsigned int) p[0]) 45 | | ((unsigned int) p[1] << 8) 46 | | ((unsigned int) p[2] << 16) 47 | | ((unsigned int) p[3] << 24); 48 | } 49 | 50 | int tinf_gzip_uncompress(void *dest, unsigned int *destLen, 51 | const void *source, unsigned int sourceLen) 52 | { 53 | const unsigned char *src = (const unsigned char *) source; 54 | unsigned char *dst = (unsigned char *) dest; 55 | const unsigned char *start; 56 | unsigned int dlen, crc32; 57 | int res; 58 | unsigned char flg; 59 | 60 | /* -- Check header -- */ 61 | 62 | /* Check room for at least 10 byte header and 8 byte trailer */ 63 | if (sourceLen < 18) { 64 | return TINF_DATA_ERROR; 65 | } 66 | 67 | /* Check id bytes */ 68 | if (src[0] != 0x1F || src[1] != 0x8B) { 69 | return TINF_DATA_ERROR; 70 | } 71 | 72 | /* Check method is deflate */ 73 | if (src[2] != 8) { 74 | return TINF_DATA_ERROR; 75 | } 76 | 77 | /* Get flag byte */ 78 | flg = src[3]; 79 | 80 | /* Check that reserved bits are zero */ 81 | if (flg & 0xE0) { 82 | return TINF_DATA_ERROR; 83 | } 84 | 85 | /* -- Find start of compressed data -- */ 86 | 87 | /* Skip base header of 10 bytes */ 88 | start = src + 10; 89 | 90 | /* Skip extra data if present */ 91 | if (flg & FEXTRA) { 92 | unsigned int xlen = read_le16(start); 93 | 94 | if (xlen > sourceLen - 12) { 95 | return TINF_DATA_ERROR; 96 | } 97 | 98 | start += xlen + 2; 99 | } 100 | 101 | /* Skip file name if present */ 102 | if (flg & FNAME) { 103 | do { 104 | if (start - src >= sourceLen) { 105 | return TINF_DATA_ERROR; 106 | } 107 | } while (*start++); 108 | } 109 | 110 | /* Skip file comment if present */ 111 | if (flg & FCOMMENT) { 112 | do { 113 | if (start - src >= sourceLen) { 114 | return TINF_DATA_ERROR; 115 | } 116 | } while (*start++); 117 | } 118 | 119 | /* Check header crc if present */ 120 | if (flg & FHCRC) { 121 | unsigned int hcrc; 122 | 123 | if (start - src > sourceLen - 2) { 124 | return TINF_DATA_ERROR; 125 | } 126 | 127 | hcrc = read_le16(start); 128 | 129 | if (hcrc != (tinf_crc32(src, start - src) & 0x0000FFFF)) { 130 | return TINF_DATA_ERROR; 131 | } 132 | 133 | start += 2; 134 | } 135 | 136 | /* -- Get decompressed length -- */ 137 | 138 | dlen = read_le32(&src[sourceLen - 4]); 139 | 140 | if (dlen > *destLen) { 141 | return TINF_BUF_ERROR; 142 | } 143 | 144 | /* -- Get CRC32 checksum of original data -- */ 145 | 146 | crc32 = read_le32(&src[sourceLen - 8]); 147 | 148 | /* -- Decompress data -- */ 149 | 150 | if ((src + sourceLen) - start < 8) { 151 | return TINF_DATA_ERROR; 152 | } 153 | 154 | res = tinf_uncompress(dst, destLen, start, 155 | (src + sourceLen) - start - 8); 156 | 157 | if (res != TINF_OK) { 158 | return TINF_DATA_ERROR; 159 | } 160 | 161 | if (*destLen != dlen) { 162 | return TINF_DATA_ERROR; 163 | } 164 | 165 | /* -- Check CRC32 checksum -- */ 166 | 167 | if (crc32 != tinf_crc32(dst, dlen)) { 168 | return TINF_DATA_ERROR; 169 | } 170 | 171 | return TINF_OK; 172 | } 173 | -------------------------------------------------------------------------------- /src/tinflate.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tinflate - tiny inflate 3 | * 4 | * Copyright (c) 2003-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | #include "tinf.h" 27 | 28 | #include 29 | #include 30 | 31 | #if defined(UINT_MAX) && (UINT_MAX) < 0xFFFFFFFFUL 32 | # error "tinf requires unsigned int to be at least 32-bit" 33 | #endif 34 | 35 | /* -- Internal data structures -- */ 36 | 37 | struct tinf_tree { 38 | unsigned short counts[16]; /* Number of codes with a given length */ 39 | unsigned short symbols[288]; /* Symbols sorted by code */ 40 | int max_sym; 41 | }; 42 | 43 | struct tinf_data { 44 | const unsigned char *source; 45 | const unsigned char *source_end; 46 | unsigned int tag; 47 | int bitcount; 48 | int overflow; 49 | 50 | unsigned char *dest_start; 51 | unsigned char *dest; 52 | unsigned char *dest_end; 53 | 54 | struct tinf_tree ltree; /* Literal/length tree */ 55 | struct tinf_tree dtree; /* Distance tree */ 56 | }; 57 | 58 | /* -- Utility functions -- */ 59 | 60 | static unsigned int read_le16(const unsigned char *p) 61 | { 62 | return ((unsigned int) p[0]) 63 | | ((unsigned int) p[1] << 8); 64 | } 65 | 66 | /* Build fixed Huffman trees */ 67 | static void tinf_build_fixed_trees(struct tinf_tree *lt, struct tinf_tree *dt) 68 | { 69 | int i; 70 | 71 | /* Build fixed literal/length tree */ 72 | for (i = 0; i < 16; ++i) { 73 | lt->counts[i] = 0; 74 | } 75 | 76 | lt->counts[7] = 24; 77 | lt->counts[8] = 152; 78 | lt->counts[9] = 112; 79 | 80 | for (i = 0; i < 24; ++i) { 81 | lt->symbols[i] = 256 + i; 82 | } 83 | for (i = 0; i < 144; ++i) { 84 | lt->symbols[24 + i] = i; 85 | } 86 | for (i = 0; i < 8; ++i) { 87 | lt->symbols[24 + 144 + i] = 280 + i; 88 | } 89 | for (i = 0; i < 112; ++i) { 90 | lt->symbols[24 + 144 + 8 + i] = 144 + i; 91 | } 92 | 93 | lt->max_sym = 285; 94 | 95 | /* Build fixed distance tree */ 96 | for (i = 0; i < 16; ++i) { 97 | dt->counts[i] = 0; 98 | } 99 | 100 | dt->counts[5] = 32; 101 | 102 | for (i = 0; i < 32; ++i) { 103 | dt->symbols[i] = i; 104 | } 105 | 106 | dt->max_sym = 29; 107 | } 108 | 109 | /* Given an array of code lengths, build a tree */ 110 | static int tinf_build_tree(struct tinf_tree *t, const unsigned char *lengths, 111 | unsigned int num) 112 | { 113 | unsigned short offs[16]; 114 | unsigned int i, num_codes, available; 115 | 116 | assert(num <= 288); 117 | 118 | for (i = 0; i < 16; ++i) { 119 | t->counts[i] = 0; 120 | } 121 | 122 | t->max_sym = -1; 123 | 124 | /* Count number of codes for each non-zero length */ 125 | for (i = 0; i < num; ++i) { 126 | assert(lengths[i] <= 15); 127 | 128 | if (lengths[i]) { 129 | t->max_sym = i; 130 | t->counts[lengths[i]]++; 131 | } 132 | } 133 | 134 | /* Compute offset table for distribution sort */ 135 | for (available = 1, num_codes = 0, i = 0; i < 16; ++i) { 136 | unsigned int used = t->counts[i]; 137 | 138 | /* Check length contains no more codes than available */ 139 | if (used > available) { 140 | return TINF_DATA_ERROR; 141 | } 142 | available = 2 * (available - used); 143 | 144 | offs[i] = num_codes; 145 | num_codes += used; 146 | } 147 | 148 | /* 149 | * Check all codes were used, or for the special case of only one 150 | * code that it has length 1 151 | */ 152 | if ((num_codes > 1 && available > 0) 153 | || (num_codes == 1 && t->counts[1] != 1)) { 154 | return TINF_DATA_ERROR; 155 | } 156 | 157 | /* Fill in symbols sorted by code */ 158 | for (i = 0; i < num; ++i) { 159 | if (lengths[i]) { 160 | t->symbols[offs[lengths[i]]++] = i; 161 | } 162 | } 163 | 164 | /* 165 | * For the special case of only one code (which will be 0) add a 166 | * code 1 which results in a symbol that is too large 167 | */ 168 | if (num_codes == 1) { 169 | t->counts[1] = 2; 170 | t->symbols[1] = t->max_sym + 1; 171 | } 172 | 173 | return TINF_OK; 174 | } 175 | 176 | /* -- Decode functions -- */ 177 | 178 | static void tinf_refill(struct tinf_data *d, int num) 179 | { 180 | assert(num >= 0 && num <= 32); 181 | 182 | /* Read bytes until at least num bits available */ 183 | while (d->bitcount < num) { 184 | if (d->source != d->source_end) { 185 | d->tag |= (unsigned int) *d->source++ << d->bitcount; 186 | } 187 | else { 188 | d->overflow = 1; 189 | } 190 | d->bitcount += 8; 191 | } 192 | 193 | assert(d->bitcount <= 32); 194 | } 195 | 196 | static unsigned int tinf_getbits_no_refill(struct tinf_data *d, int num) 197 | { 198 | unsigned int bits; 199 | 200 | assert(num >= 0 && num <= d->bitcount); 201 | 202 | /* Get bits from tag */ 203 | bits = d->tag & ((1UL << num) - 1); 204 | 205 | /* Remove bits from tag */ 206 | d->tag >>= num; 207 | d->bitcount -= num; 208 | 209 | return bits; 210 | } 211 | 212 | /* Get num bits from source stream */ 213 | static unsigned int tinf_getbits(struct tinf_data *d, int num) 214 | { 215 | tinf_refill(d, num); 216 | return tinf_getbits_no_refill(d, num); 217 | } 218 | 219 | /* Read a num bit value from stream and add base */ 220 | static unsigned int tinf_getbits_base(struct tinf_data *d, int num, int base) 221 | { 222 | return base + (num ? tinf_getbits(d, num) : 0); 223 | } 224 | 225 | /* Given a data stream and a tree, decode a symbol */ 226 | static int tinf_decode_symbol(struct tinf_data *d, const struct tinf_tree *t) 227 | { 228 | int base = 0, offs = 0; 229 | int len; 230 | 231 | /* 232 | * Get more bits while code index is above number of codes 233 | * 234 | * Rather than the actual code, we are computing the position of the 235 | * code in the sorted order of codes, which is the index of the 236 | * corresponding symbol. 237 | * 238 | * Conceptually, for each code length (level in the tree), there are 239 | * counts[len] leaves on the left and internal nodes on the right. 240 | * The index we have decoded so far is base + offs, and if that 241 | * falls within the leaves we are done. Otherwise we adjust the range 242 | * of offs and add one more bit to it. 243 | */ 244 | for (len = 1; ; ++len) { 245 | offs = 2 * offs + tinf_getbits(d, 1); 246 | 247 | assert(len <= 15); 248 | 249 | if (offs < t->counts[len]) { 250 | break; 251 | } 252 | 253 | base += t->counts[len]; 254 | offs -= t->counts[len]; 255 | } 256 | 257 | assert(base + offs >= 0 && base + offs < 288); 258 | 259 | return t->symbols[base + offs]; 260 | } 261 | 262 | /* Given a data stream, decode dynamic trees from it */ 263 | static int tinf_decode_trees(struct tinf_data *d, struct tinf_tree *lt, 264 | struct tinf_tree *dt) 265 | { 266 | unsigned char lengths[288 + 32]; 267 | 268 | /* Special ordering of code length codes */ 269 | static const unsigned char clcidx[19] = { 270 | 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 271 | 11, 4, 12, 3, 13, 2, 14, 1, 15 272 | }; 273 | 274 | unsigned int hlit, hdist, hclen; 275 | unsigned int i, num, length; 276 | int res; 277 | 278 | /* Get 5 bits HLIT (257-286) */ 279 | hlit = tinf_getbits_base(d, 5, 257); 280 | 281 | /* Get 5 bits HDIST (1-32) */ 282 | hdist = tinf_getbits_base(d, 5, 1); 283 | 284 | /* Get 4 bits HCLEN (4-19) */ 285 | hclen = tinf_getbits_base(d, 4, 4); 286 | 287 | /* 288 | * The RFC limits the range of HLIT to 286, but lists HDIST as range 289 | * 1-32, even though distance codes 30 and 31 have no meaning. While 290 | * we could allow the full range of HLIT and HDIST to make it possible 291 | * to decode the fixed trees with this function, we consider it an 292 | * error here. 293 | * 294 | * See also: https://github.com/madler/zlib/issues/82 295 | */ 296 | if (hlit > 286 || hdist > 30) { 297 | return TINF_DATA_ERROR; 298 | } 299 | 300 | for (i = 0; i < 19; ++i) { 301 | lengths[i] = 0; 302 | } 303 | 304 | /* Read code lengths for code length alphabet */ 305 | for (i = 0; i < hclen; ++i) { 306 | /* Get 3 bits code length (0-7) */ 307 | unsigned int clen = tinf_getbits(d, 3); 308 | 309 | lengths[clcidx[i]] = clen; 310 | } 311 | 312 | /* Build code length tree (in literal/length tree to save space) */ 313 | res = tinf_build_tree(lt, lengths, 19); 314 | 315 | if (res != TINF_OK) { 316 | return res; 317 | } 318 | 319 | /* Check code length tree is not empty */ 320 | if (lt->max_sym == -1) { 321 | return TINF_DATA_ERROR; 322 | } 323 | 324 | /* Decode code lengths for the dynamic trees */ 325 | for (num = 0; num < hlit + hdist; ) { 326 | int sym = tinf_decode_symbol(d, lt); 327 | 328 | if (sym > lt->max_sym) { 329 | return TINF_DATA_ERROR; 330 | } 331 | 332 | switch (sym) { 333 | case 16: 334 | /* Copy previous code length 3-6 times (read 2 bits) */ 335 | if (num == 0) { 336 | return TINF_DATA_ERROR; 337 | } 338 | sym = lengths[num - 1]; 339 | length = tinf_getbits_base(d, 2, 3); 340 | break; 341 | case 17: 342 | /* Repeat code length 0 for 3-10 times (read 3 bits) */ 343 | sym = 0; 344 | length = tinf_getbits_base(d, 3, 3); 345 | break; 346 | case 18: 347 | /* Repeat code length 0 for 11-138 times (read 7 bits) */ 348 | sym = 0; 349 | length = tinf_getbits_base(d, 7, 11); 350 | break; 351 | default: 352 | /* Values 0-15 represent the actual code lengths */ 353 | length = 1; 354 | break; 355 | } 356 | 357 | if (length > hlit + hdist - num) { 358 | return TINF_DATA_ERROR; 359 | } 360 | 361 | while (length--) { 362 | lengths[num++] = sym; 363 | } 364 | } 365 | 366 | /* Check EOB symbol is present */ 367 | if (lengths[256] == 0) { 368 | return TINF_DATA_ERROR; 369 | } 370 | 371 | /* Build dynamic trees */ 372 | res = tinf_build_tree(lt, lengths, hlit); 373 | 374 | if (res != TINF_OK) { 375 | return res; 376 | } 377 | 378 | res = tinf_build_tree(dt, lengths + hlit, hdist); 379 | 380 | if (res != TINF_OK) { 381 | return res; 382 | } 383 | 384 | return TINF_OK; 385 | } 386 | 387 | /* -- Block inflate functions -- */ 388 | 389 | /* Given a stream and two trees, inflate a block of data */ 390 | static int tinf_inflate_block_data(struct tinf_data *d, struct tinf_tree *lt, 391 | struct tinf_tree *dt) 392 | { 393 | /* Extra bits and base tables for length codes */ 394 | static const unsigned char length_bits[30] = { 395 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 396 | 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 397 | 4, 4, 4, 4, 5, 5, 5, 5, 0, 127 398 | }; 399 | 400 | static const unsigned short length_base[30] = { 401 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 402 | 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 403 | 67, 83, 99, 115, 131, 163, 195, 227, 258, 0 404 | }; 405 | 406 | /* Extra bits and base tables for distance codes */ 407 | static const unsigned char dist_bits[30] = { 408 | 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 409 | 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 410 | 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 411 | }; 412 | 413 | static const unsigned short dist_base[30] = { 414 | 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 415 | 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 416 | 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 417 | }; 418 | 419 | for (;;) { 420 | int sym = tinf_decode_symbol(d, lt); 421 | 422 | /* Check for overflow in bit reader */ 423 | if (d->overflow) { 424 | return TINF_DATA_ERROR; 425 | } 426 | 427 | if (sym < 256) { 428 | if (d->dest == d->dest_end) { 429 | return TINF_BUF_ERROR; 430 | } 431 | *d->dest++ = sym; 432 | } 433 | else { 434 | int length, dist, offs; 435 | int i; 436 | 437 | /* Check for end of block */ 438 | if (sym == 256) { 439 | return TINF_OK; 440 | } 441 | 442 | /* Check sym is within range and distance tree is not empty */ 443 | if (sym > lt->max_sym || sym - 257 > 28 || dt->max_sym == -1) { 444 | return TINF_DATA_ERROR; 445 | } 446 | 447 | sym -= 257; 448 | 449 | /* Possibly get more bits from length code */ 450 | length = tinf_getbits_base(d, length_bits[sym], 451 | length_base[sym]); 452 | 453 | dist = tinf_decode_symbol(d, dt); 454 | 455 | /* Check dist is within range */ 456 | if (dist > dt->max_sym || dist > 29) { 457 | return TINF_DATA_ERROR; 458 | } 459 | 460 | /* Possibly get more bits from distance code */ 461 | offs = tinf_getbits_base(d, dist_bits[dist], 462 | dist_base[dist]); 463 | 464 | if (offs > d->dest - d->dest_start) { 465 | return TINF_DATA_ERROR; 466 | } 467 | 468 | if (d->dest_end - d->dest < length) { 469 | return TINF_BUF_ERROR; 470 | } 471 | 472 | /* Copy match */ 473 | for (i = 0; i < length; ++i) { 474 | d->dest[i] = d->dest[i - offs]; 475 | } 476 | 477 | d->dest += length; 478 | } 479 | } 480 | } 481 | 482 | /* Inflate an uncompressed block of data */ 483 | static int tinf_inflate_uncompressed_block(struct tinf_data *d) 484 | { 485 | unsigned int length, invlength; 486 | 487 | if (d->source_end - d->source < 4) { 488 | return TINF_DATA_ERROR; 489 | } 490 | 491 | /* Get length */ 492 | length = read_le16(d->source); 493 | 494 | /* Get one's complement of length */ 495 | invlength = read_le16(d->source + 2); 496 | 497 | /* Check length */ 498 | if (length != (~invlength & 0x0000FFFF)) { 499 | return TINF_DATA_ERROR; 500 | } 501 | 502 | d->source += 4; 503 | 504 | if (d->source_end - d->source < length) { 505 | return TINF_DATA_ERROR; 506 | } 507 | 508 | if (d->dest_end - d->dest < length) { 509 | return TINF_BUF_ERROR; 510 | } 511 | 512 | /* Copy block */ 513 | while (length--) { 514 | *d->dest++ = *d->source++; 515 | } 516 | 517 | /* Make sure we start next block on a byte boundary */ 518 | d->tag = 0; 519 | d->bitcount = 0; 520 | 521 | return TINF_OK; 522 | } 523 | 524 | /* Inflate a block of data compressed with fixed Huffman trees */ 525 | static int tinf_inflate_fixed_block(struct tinf_data *d) 526 | { 527 | /* Build fixed Huffman trees */ 528 | tinf_build_fixed_trees(&d->ltree, &d->dtree); 529 | 530 | /* Decode block using fixed trees */ 531 | return tinf_inflate_block_data(d, &d->ltree, &d->dtree); 532 | } 533 | 534 | /* Inflate a block of data compressed with dynamic Huffman trees */ 535 | static int tinf_inflate_dynamic_block(struct tinf_data *d) 536 | { 537 | /* Decode trees from stream */ 538 | int res = tinf_decode_trees(d, &d->ltree, &d->dtree); 539 | 540 | if (res != TINF_OK) { 541 | return res; 542 | } 543 | 544 | /* Decode block using decoded trees */ 545 | return tinf_inflate_block_data(d, &d->ltree, &d->dtree); 546 | } 547 | 548 | /* -- Public functions -- */ 549 | 550 | /* Initialize global (static) data */ 551 | void tinf_init(void) 552 | { 553 | return; 554 | } 555 | 556 | /* Inflate stream from source to dest */ 557 | int tinf_uncompress(void *dest, unsigned int *destLen, 558 | const void *source, unsigned int sourceLen) 559 | { 560 | struct tinf_data d; 561 | int bfinal; 562 | 563 | /* Initialise data */ 564 | d.source = (const unsigned char *) source; 565 | d.source_end = d.source + sourceLen; 566 | d.tag = 0; 567 | d.bitcount = 0; 568 | d.overflow = 0; 569 | 570 | d.dest = (unsigned char *) dest; 571 | d.dest_start = d.dest; 572 | d.dest_end = d.dest + *destLen; 573 | 574 | do { 575 | unsigned int btype; 576 | int res; 577 | 578 | /* Read final block flag */ 579 | bfinal = tinf_getbits(&d, 1); 580 | 581 | /* Read block type (2 bits) */ 582 | btype = tinf_getbits(&d, 2); 583 | 584 | /* Decompress block */ 585 | switch (btype) { 586 | case 0: 587 | /* Decompress uncompressed block */ 588 | res = tinf_inflate_uncompressed_block(&d); 589 | break; 590 | case 1: 591 | /* Decompress block with fixed Huffman trees */ 592 | res = tinf_inflate_fixed_block(&d); 593 | break; 594 | case 2: 595 | /* Decompress block with dynamic Huffman trees */ 596 | res = tinf_inflate_dynamic_block(&d); 597 | break; 598 | default: 599 | res = TINF_DATA_ERROR; 600 | break; 601 | } 602 | 603 | if (res != TINF_OK) { 604 | return res; 605 | } 606 | } while (!bfinal); 607 | 608 | /* Check for overflow in bit reader */ 609 | if (d.overflow) { 610 | return TINF_DATA_ERROR; 611 | } 612 | 613 | *destLen = d.dest - d.dest_start; 614 | 615 | return TINF_OK; 616 | } 617 | 618 | /* clang -g -O1 -fsanitize=fuzzer,address -DTINF_FUZZING tinflate.c */ 619 | #if defined(TINF_FUZZING) 620 | #include 621 | #include 622 | #include 623 | #include 624 | #include 625 | 626 | unsigned char depacked[64 * 1024]; 627 | 628 | extern int 629 | LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) 630 | { 631 | if (size > UINT_MAX / 2) { return 0; } 632 | unsigned int destLen = sizeof(depacked); 633 | tinf_uncompress(depacked, &destLen, data, size); 634 | return 0; 635 | } 636 | #endif 637 | -------------------------------------------------------------------------------- /src/tinfzlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tinfzlib - tiny zlib decompressor 3 | * 4 | * Copyright (c) 2003-2019 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | #include "tinf.h" 27 | 28 | static unsigned int read_be32(const unsigned char *p) 29 | { 30 | return ((unsigned int) p[0] << 24) 31 | | ((unsigned int) p[1] << 16) 32 | | ((unsigned int) p[2] << 8) 33 | | ((unsigned int) p[3]); 34 | } 35 | 36 | int tinf_zlib_uncompress(void *dest, unsigned int *destLen, 37 | const void *source, unsigned int sourceLen) 38 | { 39 | const unsigned char *src = (const unsigned char *) source; 40 | unsigned char *dst = (unsigned char *) dest; 41 | unsigned int a32; 42 | int res; 43 | unsigned char cmf, flg; 44 | 45 | /* -- Check header -- */ 46 | 47 | /* Check room for at least 2 byte header and 4 byte trailer */ 48 | if (sourceLen < 6) { 49 | return TINF_DATA_ERROR; 50 | } 51 | 52 | /* Get header bytes */ 53 | cmf = src[0]; 54 | flg = src[1]; 55 | 56 | /* Check checksum */ 57 | if ((256 * cmf + flg) % 31) { 58 | return TINF_DATA_ERROR; 59 | } 60 | 61 | /* Check method is deflate */ 62 | if ((cmf & 0x0F) != 8) { 63 | return TINF_DATA_ERROR; 64 | } 65 | 66 | /* Check window size is valid */ 67 | if ((cmf >> 4) > 7) { 68 | return TINF_DATA_ERROR; 69 | } 70 | 71 | /* Check there is no preset dictionary */ 72 | if (flg & 0x20) { 73 | return TINF_DATA_ERROR; 74 | } 75 | 76 | /* -- Get Adler-32 checksum of original data -- */ 77 | 78 | a32 = read_be32(&src[sourceLen - 4]); 79 | 80 | /* -- Decompress data -- */ 81 | 82 | res = tinf_uncompress(dst, destLen, src + 2, sourceLen - 6); 83 | 84 | if (res != TINF_OK) { 85 | return TINF_DATA_ERROR; 86 | } 87 | 88 | /* -- Check Adler-32 checksum -- */ 89 | 90 | if (a32 != tinf_adler32(dst, *destLen)) { 91 | return TINF_DATA_ERROR; 92 | } 93 | 94 | return TINF_OK; 95 | } 96 | -------------------------------------------------------------------------------- /test/greatest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011-2021 Scott Vokes 3 | * 4 | * Permission to use, copy, modify, and/or distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | #ifndef GREATEST_H 18 | #define GREATEST_H 19 | 20 | #if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) 21 | extern "C" { 22 | #endif 23 | 24 | /* 1.5.0 */ 25 | #define GREATEST_VERSION_MAJOR 1 26 | #define GREATEST_VERSION_MINOR 5 27 | #define GREATEST_VERSION_PATCH 0 28 | 29 | /* A unit testing system for C, contained in 1 file. 30 | * It doesn't use dynamic allocation or depend on anything 31 | * beyond ANSI C89. 32 | * 33 | * An up-to-date version can be found at: 34 | * https://github.com/silentbicycle/greatest/ 35 | */ 36 | 37 | 38 | /********************************************************************* 39 | * Minimal test runner template 40 | *********************************************************************/ 41 | #if 0 42 | 43 | #include "greatest.h" 44 | 45 | TEST foo_should_foo(void) { 46 | PASS(); 47 | } 48 | 49 | static void setup_cb(void *data) { 50 | printf("setup callback for each test case\n"); 51 | } 52 | 53 | static void teardown_cb(void *data) { 54 | printf("teardown callback for each test case\n"); 55 | } 56 | 57 | SUITE(suite) { 58 | /* Optional setup/teardown callbacks which will be run before/after 59 | * every test case. If using a test suite, they will be cleared when 60 | * the suite finishes. */ 61 | SET_SETUP(setup_cb, voidp_to_callback_data); 62 | SET_TEARDOWN(teardown_cb, voidp_to_callback_data); 63 | 64 | RUN_TEST(foo_should_foo); 65 | } 66 | 67 | /* Add definitions that need to be in the test runner's main file. */ 68 | GREATEST_MAIN_DEFS(); 69 | 70 | /* Set up, run suite(s) of tests, report pass/fail/skip stats. */ 71 | int run_tests(void) { 72 | GREATEST_INIT(); /* init. greatest internals */ 73 | /* List of suites to run (if any). */ 74 | RUN_SUITE(suite); 75 | 76 | /* Tests can also be run directly, without using test suites. */ 77 | RUN_TEST(foo_should_foo); 78 | 79 | GREATEST_PRINT_REPORT(); /* display results */ 80 | return greatest_all_passed(); 81 | } 82 | 83 | /* main(), for a standalone command-line test runner. 84 | * This replaces run_tests above, and adds command line option 85 | * handling and exiting with a pass/fail status. */ 86 | int main(int argc, char **argv) { 87 | GREATEST_MAIN_BEGIN(); /* init & parse command-line args */ 88 | RUN_SUITE(suite); 89 | GREATEST_MAIN_END(); /* display results */ 90 | } 91 | 92 | #endif 93 | /*********************************************************************/ 94 | 95 | 96 | #include 97 | #include 98 | #include 99 | #include 100 | 101 | /*********** 102 | * Options * 103 | ***********/ 104 | 105 | /* Default column width for non-verbose output. */ 106 | #ifndef GREATEST_DEFAULT_WIDTH 107 | #define GREATEST_DEFAULT_WIDTH 72 108 | #endif 109 | 110 | /* FILE *, for test logging. */ 111 | #ifndef GREATEST_STDOUT 112 | #define GREATEST_STDOUT stdout 113 | #endif 114 | 115 | /* Remove GREATEST_ prefix from most commonly used symbols? */ 116 | #ifndef GREATEST_USE_ABBREVS 117 | #define GREATEST_USE_ABBREVS 1 118 | #endif 119 | 120 | /* Set to 0 to disable all use of setjmp/longjmp. */ 121 | #ifndef GREATEST_USE_LONGJMP 122 | #define GREATEST_USE_LONGJMP 0 123 | #endif 124 | 125 | /* Make it possible to replace fprintf with another 126 | * function with the same interface. */ 127 | #ifndef GREATEST_FPRINTF 128 | #define GREATEST_FPRINTF fprintf 129 | #endif 130 | 131 | #if GREATEST_USE_LONGJMP 132 | #include 133 | #endif 134 | 135 | /* Set to 0 to disable all use of time.h / clock(). */ 136 | #ifndef GREATEST_USE_TIME 137 | #define GREATEST_USE_TIME 1 138 | #endif 139 | 140 | #if GREATEST_USE_TIME 141 | #include 142 | #endif 143 | 144 | /* Floating point type, for ASSERT_IN_RANGE. */ 145 | #ifndef GREATEST_FLOAT 146 | #define GREATEST_FLOAT double 147 | #define GREATEST_FLOAT_FMT "%g" 148 | #endif 149 | 150 | /* Size of buffer for test name + optional '_' separator and suffix */ 151 | #ifndef GREATEST_TESTNAME_BUF_SIZE 152 | #define GREATEST_TESTNAME_BUF_SIZE 128 153 | #endif 154 | 155 | 156 | /********* 157 | * Types * 158 | *********/ 159 | 160 | /* Info for the current running suite. */ 161 | typedef struct greatest_suite_info { 162 | unsigned int tests_run; 163 | unsigned int passed; 164 | unsigned int failed; 165 | unsigned int skipped; 166 | 167 | #if GREATEST_USE_TIME 168 | /* timers, pre/post running suite and individual tests */ 169 | clock_t pre_suite; 170 | clock_t post_suite; 171 | clock_t pre_test; 172 | clock_t post_test; 173 | #endif 174 | } greatest_suite_info; 175 | 176 | /* Type for a suite function. */ 177 | typedef void greatest_suite_cb(void); 178 | 179 | /* Types for setup/teardown callbacks. If non-NULL, these will be run 180 | * and passed the pointer to their additional data. */ 181 | typedef void greatest_setup_cb(void *udata); 182 | typedef void greatest_teardown_cb(void *udata); 183 | 184 | /* Type for an equality comparison between two pointers of the same type. 185 | * Should return non-0 if equal, otherwise 0. 186 | * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ 187 | typedef int greatest_equal_cb(const void *expd, const void *got, void *udata); 188 | 189 | /* Type for a callback that prints a value pointed to by T. 190 | * Return value has the same meaning as printf's. 191 | * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */ 192 | typedef int greatest_printf_cb(const void *t, void *udata); 193 | 194 | /* Callbacks for an arbitrary type; needed for type-specific 195 | * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/ 196 | typedef struct greatest_type_info { 197 | greatest_equal_cb *equal; 198 | greatest_printf_cb *print; 199 | } greatest_type_info; 200 | 201 | typedef struct greatest_memory_cmp_env { 202 | const unsigned char *exp; 203 | const unsigned char *got; 204 | size_t size; 205 | } greatest_memory_cmp_env; 206 | 207 | /* Callbacks for string and raw memory types. */ 208 | extern greatest_type_info greatest_type_info_string; 209 | extern greatest_type_info greatest_type_info_memory; 210 | 211 | typedef enum { 212 | GREATEST_FLAG_FIRST_FAIL = 0x01, 213 | GREATEST_FLAG_LIST_ONLY = 0x02, 214 | GREATEST_FLAG_ABORT_ON_FAIL = 0x04 215 | } greatest_flag_t; 216 | 217 | /* Internal state for a PRNG, used to shuffle test order. */ 218 | struct greatest_prng { 219 | unsigned char random_order; /* use random ordering? */ 220 | unsigned char initialized; /* is random ordering initialized? */ 221 | unsigned char pad_0[6]; 222 | unsigned long state; /* PRNG state */ 223 | unsigned long count; /* how many tests, this pass */ 224 | unsigned long count_ceil; /* total number of tests */ 225 | unsigned long count_run; /* total tests run */ 226 | unsigned long a; /* LCG multiplier */ 227 | unsigned long c; /* LCG increment */ 228 | unsigned long m; /* LCG modulus, based on count_ceil */ 229 | }; 230 | 231 | /* Struct containing all test runner state. */ 232 | typedef struct greatest_run_info { 233 | unsigned char flags; 234 | unsigned char verbosity; 235 | unsigned char running_test; /* guard for nested RUN_TEST calls */ 236 | unsigned char exact_name_match; 237 | 238 | unsigned int tests_run; /* total test count */ 239 | 240 | /* currently running test suite */ 241 | greatest_suite_info suite; 242 | 243 | /* overall pass/fail/skip counts */ 244 | unsigned int passed; 245 | unsigned int failed; 246 | unsigned int skipped; 247 | unsigned int assertions; 248 | 249 | /* info to print about the most recent failure */ 250 | unsigned int fail_line; 251 | unsigned int pad_1; 252 | const char *fail_file; 253 | const char *msg; 254 | 255 | /* current setup/teardown hooks and userdata */ 256 | greatest_setup_cb *setup; 257 | void *setup_udata; 258 | greatest_teardown_cb *teardown; 259 | void *teardown_udata; 260 | 261 | /* formatting info for ".....s...F"-style output */ 262 | unsigned int col; 263 | unsigned int width; 264 | 265 | /* only run a specific suite or test */ 266 | const char *suite_filter; 267 | const char *test_filter; 268 | const char *test_exclude; 269 | const char *name_suffix; /* print suffix with test name */ 270 | char name_buf[GREATEST_TESTNAME_BUF_SIZE]; 271 | 272 | struct greatest_prng prng[2]; /* 0: suites, 1: tests */ 273 | 274 | #if GREATEST_USE_TIME 275 | /* overall timers */ 276 | clock_t begin; 277 | clock_t end; 278 | #endif 279 | 280 | #if GREATEST_USE_LONGJMP 281 | int pad_jmp_buf; 282 | unsigned char pad_2[4]; 283 | jmp_buf jump_dest; 284 | #endif 285 | } greatest_run_info; 286 | 287 | struct greatest_report_t { 288 | /* overall pass/fail/skip counts */ 289 | unsigned int passed; 290 | unsigned int failed; 291 | unsigned int skipped; 292 | unsigned int assertions; 293 | }; 294 | 295 | /* Global var for the current testing context. 296 | * Initialized by GREATEST_MAIN_DEFS(). */ 297 | extern greatest_run_info greatest_info; 298 | 299 | /* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */ 300 | typedef const char *greatest_enum_str_fun(int value); 301 | 302 | 303 | /********************** 304 | * Exported functions * 305 | **********************/ 306 | 307 | /* These are used internally by greatest macros. */ 308 | int greatest_test_pre(const char *name); 309 | void greatest_test_post(int res); 310 | int greatest_do_assert_equal_t(const void *expd, const void *got, 311 | greatest_type_info *type_info, void *udata); 312 | void greatest_prng_init_first_pass(int id); 313 | int greatest_prng_init_second_pass(int id, unsigned long seed); 314 | void greatest_prng_step(int id); 315 | 316 | /* These are part of the public greatest API. */ 317 | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata); 318 | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata); 319 | void GREATEST_INIT(void); 320 | void GREATEST_PRINT_REPORT(void); 321 | int greatest_all_passed(void); 322 | void greatest_set_suite_filter(const char *filter); 323 | void greatest_set_test_filter(const char *filter); 324 | void greatest_set_test_exclude(const char *filter); 325 | void greatest_set_exact_name_match(void); 326 | void greatest_stop_at_first_fail(void); 327 | void greatest_abort_on_fail(void); 328 | void greatest_list_only(void); 329 | void greatest_get_report(struct greatest_report_t *report); 330 | unsigned int greatest_get_verbosity(void); 331 | void greatest_set_verbosity(unsigned int verbosity); 332 | void greatest_set_flag(greatest_flag_t flag); 333 | void greatest_set_test_suffix(const char *suffix); 334 | 335 | 336 | /******************** 337 | * Language Support * 338 | ********************/ 339 | 340 | /* If __VA_ARGS__ (C99) is supported, allow parametric testing 341 | * without needing to manually manage the argument struct. */ 342 | #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L) || \ 343 | (defined(_MSC_VER) && _MSC_VER >= 1800) 344 | #define GREATEST_VA_ARGS 345 | #endif 346 | 347 | 348 | /********** 349 | * Macros * 350 | **********/ 351 | 352 | /* Define a suite. (The duplication is intentional -- it eliminates 353 | * a warning from -Wmissing-declarations.) */ 354 | #define GREATEST_SUITE(NAME) void NAME(void); void NAME(void) 355 | 356 | /* Declare a suite, provided by another compilation unit. */ 357 | #define GREATEST_SUITE_EXTERN(NAME) void NAME(void) 358 | 359 | /* Start defining a test function. 360 | * The arguments are not included, to allow parametric testing. */ 361 | #define GREATEST_TEST static enum greatest_test_res 362 | 363 | /* PASS/FAIL/SKIP result from a test. Used internally. */ 364 | typedef enum greatest_test_res { 365 | GREATEST_TEST_RES_PASS = 0, 366 | GREATEST_TEST_RES_FAIL = -1, 367 | GREATEST_TEST_RES_SKIP = 1 368 | } greatest_test_res; 369 | 370 | /* Run a suite. */ 371 | #define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME) 372 | 373 | /* Run a test in the current suite. */ 374 | #define GREATEST_RUN_TEST(TEST) \ 375 | do { \ 376 | if (greatest_test_pre(#TEST) == 1) { \ 377 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 378 | if (res == GREATEST_TEST_RES_PASS) { \ 379 | res = TEST(); \ 380 | } \ 381 | greatest_test_post(res); \ 382 | } \ 383 | } while (0) 384 | 385 | /* Ignore a test, don't warn about it being unused. */ 386 | #define GREATEST_IGNORE_TEST(TEST) (void)TEST 387 | 388 | /* Run a test in the current suite with one void * argument, 389 | * which can be a pointer to a struct with multiple arguments. */ 390 | #define GREATEST_RUN_TEST1(TEST, ENV) \ 391 | do { \ 392 | if (greatest_test_pre(#TEST) == 1) { \ 393 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 394 | if (res == GREATEST_TEST_RES_PASS) { \ 395 | res = TEST(ENV); \ 396 | } \ 397 | greatest_test_post(res); \ 398 | } \ 399 | } while (0) 400 | 401 | #ifdef GREATEST_VA_ARGS 402 | #define GREATEST_RUN_TESTp(TEST, ...) \ 403 | do { \ 404 | if (greatest_test_pre(#TEST) == 1) { \ 405 | enum greatest_test_res res = GREATEST_SAVE_CONTEXT(); \ 406 | if (res == GREATEST_TEST_RES_PASS) { \ 407 | res = TEST(__VA_ARGS__); \ 408 | } \ 409 | greatest_test_post(res); \ 410 | } \ 411 | } while (0) 412 | #endif 413 | 414 | 415 | /* Check if the test runner is in verbose mode. */ 416 | #define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0) 417 | #define GREATEST_LIST_ONLY() \ 418 | (greatest_info.flags & GREATEST_FLAG_LIST_ONLY) 419 | #define GREATEST_FIRST_FAIL() \ 420 | (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL) 421 | #define GREATEST_ABORT_ON_FAIL() \ 422 | (greatest_info.flags & GREATEST_FLAG_ABORT_ON_FAIL) 423 | #define GREATEST_FAILURE_ABORT() \ 424 | (GREATEST_FIRST_FAIL() && \ 425 | (greatest_info.suite.failed > 0 || greatest_info.failed > 0)) 426 | 427 | /* Message-less forms of tests defined below. */ 428 | #define GREATEST_PASS() GREATEST_PASSm(NULL) 429 | #define GREATEST_FAIL() GREATEST_FAILm(NULL) 430 | #define GREATEST_SKIP() GREATEST_SKIPm(NULL) 431 | #define GREATEST_ASSERT(COND) \ 432 | GREATEST_ASSERTm(#COND, COND) 433 | #define GREATEST_ASSERT_OR_LONGJMP(COND) \ 434 | GREATEST_ASSERT_OR_LONGJMPm(#COND, COND) 435 | #define GREATEST_ASSERT_FALSE(COND) \ 436 | GREATEST_ASSERT_FALSEm(#COND, COND) 437 | #define GREATEST_ASSERT_EQ(EXP, GOT) \ 438 | GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT) 439 | #define GREATEST_ASSERT_NEQ(EXP, GOT) \ 440 | GREATEST_ASSERT_NEQm(#EXP " == " #GOT, EXP, GOT) 441 | #define GREATEST_ASSERT_GT(EXP, GOT) \ 442 | GREATEST_ASSERT_GTm(#EXP " <= " #GOT, EXP, GOT) 443 | #define GREATEST_ASSERT_GTE(EXP, GOT) \ 444 | GREATEST_ASSERT_GTEm(#EXP " < " #GOT, EXP, GOT) 445 | #define GREATEST_ASSERT_LT(EXP, GOT) \ 446 | GREATEST_ASSERT_LTm(#EXP " >= " #GOT, EXP, GOT) 447 | #define GREATEST_ASSERT_LTE(EXP, GOT) \ 448 | GREATEST_ASSERT_LTEm(#EXP " > " #GOT, EXP, GOT) 449 | #define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT) \ 450 | GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT) 451 | #define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL) \ 452 | GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL) 453 | #define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA) \ 454 | GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA) 455 | #define GREATEST_ASSERT_STR_EQ(EXP, GOT) \ 456 | GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT) 457 | #define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE) \ 458 | GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) 459 | #define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE) \ 460 | GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE) 461 | #define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR) \ 462 | GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR) 463 | 464 | /* The following forms take an additional message argument first, 465 | * to be displayed by the test runner. */ 466 | 467 | /* Fail if a condition is not true, with message. */ 468 | #define GREATEST_ASSERTm(MSG, COND) \ 469 | do { \ 470 | greatest_info.assertions++; \ 471 | if (!(COND)) { GREATEST_FAILm(MSG); } \ 472 | } while (0) 473 | 474 | /* Fail if a condition is not true, longjmping out of test. */ 475 | #define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND) \ 476 | do { \ 477 | greatest_info.assertions++; \ 478 | if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); } \ 479 | } while (0) 480 | 481 | /* Fail if a condition is not false, with message. */ 482 | #define GREATEST_ASSERT_FALSEm(MSG, COND) \ 483 | do { \ 484 | greatest_info.assertions++; \ 485 | if ((COND)) { GREATEST_FAILm(MSG); } \ 486 | } while (0) 487 | 488 | /* Internal macro for relational assertions */ 489 | #define GREATEST__REL(REL, MSG, EXP, GOT) \ 490 | do { \ 491 | greatest_info.assertions++; \ 492 | if (!((EXP) REL (GOT))) { GREATEST_FAILm(MSG); } \ 493 | } while (0) 494 | 495 | /* Fail if EXP is not ==, !=, >, <, >=, or <= to GOT. */ 496 | #define GREATEST_ASSERT_EQm(MSG,E,G) GREATEST__REL(==, MSG,E,G) 497 | #define GREATEST_ASSERT_NEQm(MSG,E,G) GREATEST__REL(!=, MSG,E,G) 498 | #define GREATEST_ASSERT_GTm(MSG,E,G) GREATEST__REL(>, MSG,E,G) 499 | #define GREATEST_ASSERT_GTEm(MSG,E,G) GREATEST__REL(>=, MSG,E,G) 500 | #define GREATEST_ASSERT_LTm(MSG,E,G) GREATEST__REL(<, MSG,E,G) 501 | #define GREATEST_ASSERT_LTEm(MSG,E,G) GREATEST__REL(<=, MSG,E,G) 502 | 503 | /* Fail if EXP != GOT (equality comparison by ==). 504 | * Warning: FMT, EXP, and GOT will be evaluated more 505 | * than once on failure. */ 506 | #define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT) \ 507 | do { \ 508 | greatest_info.assertions++; \ 509 | if ((EXP) != (GOT)) { \ 510 | GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ 511 | GREATEST_FPRINTF(GREATEST_STDOUT, FMT, EXP); \ 512 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ 513 | GREATEST_FPRINTF(GREATEST_STDOUT, FMT, GOT); \ 514 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 515 | GREATEST_FAILm(MSG); \ 516 | } \ 517 | } while (0) 518 | 519 | /* Fail if EXP is not equal to GOT, printing enum IDs. */ 520 | #define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR) \ 521 | do { \ 522 | int greatest_EXP = (int)(EXP); \ 523 | int greatest_GOT = (int)(GOT); \ 524 | greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR; \ 525 | if (greatest_EXP != greatest_GOT) { \ 526 | GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: %s", \ 527 | greatest_ENUM_STR(greatest_EXP)); \ 528 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: %s\n", \ 529 | greatest_ENUM_STR(greatest_GOT)); \ 530 | GREATEST_FAILm(MSG); \ 531 | } \ 532 | } while (0) \ 533 | 534 | /* Fail if GOT not in range of EXP +|- TOL. */ 535 | #define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL) \ 536 | do { \ 537 | GREATEST_FLOAT greatest_EXP = (EXP); \ 538 | GREATEST_FLOAT greatest_GOT = (GOT); \ 539 | GREATEST_FLOAT greatest_TOL = (TOL); \ 540 | greatest_info.assertions++; \ 541 | if ((greatest_EXP > greatest_GOT && \ 542 | greatest_EXP - greatest_GOT > greatest_TOL) || \ 543 | (greatest_EXP < greatest_GOT && \ 544 | greatest_GOT - greatest_EXP > greatest_TOL)) { \ 545 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 546 | "\nExpected: " GREATEST_FLOAT_FMT \ 547 | " +/- " GREATEST_FLOAT_FMT \ 548 | "\n Got: " GREATEST_FLOAT_FMT \ 549 | "\n", \ 550 | greatest_EXP, greatest_TOL, greatest_GOT); \ 551 | GREATEST_FAILm(MSG); \ 552 | } \ 553 | } while (0) 554 | 555 | /* Fail if EXP is not equal to GOT, according to strcmp. */ 556 | #define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT) \ 557 | do { \ 558 | GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ 559 | &greatest_type_info_string, NULL); \ 560 | } while (0) \ 561 | 562 | /* Fail if EXP is not equal to GOT, according to strncmp. */ 563 | #define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE) \ 564 | do { \ 565 | size_t size = SIZE; \ 566 | GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, \ 567 | &greatest_type_info_string, &size); \ 568 | } while (0) \ 569 | 570 | /* Fail if EXP is not equal to GOT, according to memcmp. */ 571 | #define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE) \ 572 | do { \ 573 | greatest_memory_cmp_env env; \ 574 | env.exp = (const unsigned char *)EXP; \ 575 | env.got = (const unsigned char *)GOT; \ 576 | env.size = SIZE; \ 577 | GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got, \ 578 | &greatest_type_info_memory, &env); \ 579 | } while (0) \ 580 | 581 | /* Fail if EXP is not equal to GOT, according to a comparison 582 | * callback in TYPE_INFO. If they are not equal, optionally use a 583 | * print callback in TYPE_INFO to print them. */ 584 | #define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA) \ 585 | do { \ 586 | greatest_type_info *type_info = (TYPE_INFO); \ 587 | greatest_info.assertions++; \ 588 | if (!greatest_do_assert_equal_t(EXP, GOT, \ 589 | type_info, UDATA)) { \ 590 | if (type_info == NULL || type_info->equal == NULL) { \ 591 | GREATEST_FAILm("type_info->equal callback missing!"); \ 592 | } else { \ 593 | GREATEST_FAILm(MSG); \ 594 | } \ 595 | } \ 596 | } while (0) \ 597 | 598 | /* Pass. */ 599 | #define GREATEST_PASSm(MSG) \ 600 | do { \ 601 | greatest_info.msg = MSG; \ 602 | return GREATEST_TEST_RES_PASS; \ 603 | } while (0) 604 | 605 | /* Fail. */ 606 | #define GREATEST_FAILm(MSG) \ 607 | do { \ 608 | greatest_info.fail_file = __FILE__; \ 609 | greatest_info.fail_line = __LINE__; \ 610 | greatest_info.msg = MSG; \ 611 | if (GREATEST_ABORT_ON_FAIL()) { abort(); } \ 612 | return GREATEST_TEST_RES_FAIL; \ 613 | } while (0) 614 | 615 | /* Optional GREATEST_FAILm variant that longjmps. */ 616 | #if GREATEST_USE_LONGJMP 617 | #define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL) 618 | #define GREATEST_FAIL_WITH_LONGJMPm(MSG) \ 619 | do { \ 620 | greatest_info.fail_file = __FILE__; \ 621 | greatest_info.fail_line = __LINE__; \ 622 | greatest_info.msg = MSG; \ 623 | longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL); \ 624 | } while (0) 625 | #endif 626 | 627 | /* Skip the current test. */ 628 | #define GREATEST_SKIPm(MSG) \ 629 | do { \ 630 | greatest_info.msg = MSG; \ 631 | return GREATEST_TEST_RES_SKIP; \ 632 | } while (0) 633 | 634 | /* Check the result of a subfunction using ASSERT, etc. */ 635 | #define GREATEST_CHECK_CALL(RES) \ 636 | do { \ 637 | enum greatest_test_res greatest_RES = RES; \ 638 | if (greatest_RES != GREATEST_TEST_RES_PASS) { \ 639 | return greatest_RES; \ 640 | } \ 641 | } while (0) \ 642 | 643 | #if GREATEST_USE_TIME 644 | #define GREATEST_SET_TIME(NAME) \ 645 | NAME = clock(); \ 646 | if (NAME == (clock_t) -1) { \ 647 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 648 | "clock error: %s\n", #NAME); \ 649 | exit(EXIT_FAILURE); \ 650 | } 651 | 652 | #define GREATEST_CLOCK_DIFF(C1, C2) \ 653 | GREATEST_FPRINTF(GREATEST_STDOUT, " (%lu ticks, %.3f sec)", \ 654 | (long unsigned int) (C2) - (long unsigned int)(C1), \ 655 | (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC)) 656 | #else 657 | #define GREATEST_SET_TIME(UNUSED) 658 | #define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2) 659 | #endif 660 | 661 | #if GREATEST_USE_LONGJMP 662 | #define GREATEST_SAVE_CONTEXT() \ 663 | /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call * \ 664 | * so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */ \ 665 | ((enum greatest_test_res)(setjmp(greatest_info.jump_dest))) 666 | #else 667 | #define GREATEST_SAVE_CONTEXT() \ 668 | /*a no-op, since setjmp/longjmp aren't being used */ \ 669 | GREATEST_TEST_RES_PASS 670 | #endif 671 | 672 | /* Run every suite / test function run within BODY in pseudo-random 673 | * order, seeded by SEED. (The top 3 bits of the seed are ignored.) 674 | * 675 | * This should be called like: 676 | * GREATEST_SHUFFLE_TESTS(seed, { 677 | * GREATEST_RUN_TEST(some_test); 678 | * GREATEST_RUN_TEST(some_other_test); 679 | * GREATEST_RUN_TEST(yet_another_test); 680 | * }); 681 | * 682 | * Note that the body of the second argument will be evaluated 683 | * multiple times. */ 684 | #define GREATEST_SHUFFLE_SUITES(SD, BODY) GREATEST_SHUFFLE(0, SD, BODY) 685 | #define GREATEST_SHUFFLE_TESTS(SD, BODY) GREATEST_SHUFFLE(1, SD, BODY) 686 | #define GREATEST_SHUFFLE(ID, SD, BODY) \ 687 | do { \ 688 | struct greatest_prng *prng = &greatest_info.prng[ID]; \ 689 | greatest_prng_init_first_pass(ID); \ 690 | do { \ 691 | prng->count = 0; \ 692 | if (prng->initialized) { greatest_prng_step(ID); } \ 693 | BODY; \ 694 | if (!prng->initialized) { \ 695 | if (!greatest_prng_init_second_pass(ID, SD)) { break; } \ 696 | } else if (prng->count_run == prng->count_ceil) { \ 697 | break; \ 698 | } \ 699 | } while (!GREATEST_FAILURE_ABORT()); \ 700 | prng->count_run = prng->random_order = prng->initialized = 0; \ 701 | } while(0) 702 | 703 | /* Include several function definitions in the main test file. */ 704 | #define GREATEST_MAIN_DEFS() \ 705 | \ 706 | /* Is FILTER a subset of NAME? */ \ 707 | static int greatest_name_match(const char *name, const char *filter, \ 708 | int res_if_none) { \ 709 | size_t offset = 0; \ 710 | size_t filter_len = filter ? strlen(filter) : 0; \ 711 | if (filter_len == 0) { return res_if_none; } /* no filter */ \ 712 | if (greatest_info.exact_name_match && strlen(name) != filter_len) { \ 713 | return 0; /* ignore substring matches */ \ 714 | } \ 715 | while (name[offset] != '\0') { \ 716 | if (name[offset] == filter[0]) { \ 717 | if (0 == strncmp(&name[offset], filter, filter_len)) { \ 718 | return 1; \ 719 | } \ 720 | } \ 721 | offset++; \ 722 | } \ 723 | \ 724 | return 0; \ 725 | } \ 726 | \ 727 | static void greatest_buffer_test_name(const char *name) { \ 728 | struct greatest_run_info *g = &greatest_info; \ 729 | size_t len = strlen(name), size = sizeof(g->name_buf); \ 730 | memset(g->name_buf, 0x00, size); \ 731 | (void)strncat(g->name_buf, name, size - 1); \ 732 | if (g->name_suffix && (len + 1 < size)) { \ 733 | g->name_buf[len] = '_'; \ 734 | strncat(&g->name_buf[len+1], g->name_suffix, size-(len+2)); \ 735 | } \ 736 | } \ 737 | \ 738 | /* Before running a test, check the name filtering and \ 739 | * test shuffling state, if applicable, and then call setup hooks. */ \ 740 | int greatest_test_pre(const char *name) { \ 741 | struct greatest_run_info *g = &greatest_info; \ 742 | int match; \ 743 | greatest_buffer_test_name(name); \ 744 | match = greatest_name_match(g->name_buf, g->test_filter, 1) && \ 745 | !greatest_name_match(g->name_buf, g->test_exclude, 0); \ 746 | if (GREATEST_LIST_ONLY()) { /* just listing test names */ \ 747 | if (match) { \ 748 | GREATEST_FPRINTF(GREATEST_STDOUT, " %s\n", g->name_buf); \ 749 | } \ 750 | goto clear; \ 751 | } \ 752 | if (match && (!GREATEST_FIRST_FAIL() || g->suite.failed == 0)) { \ 753 | struct greatest_prng *p = &g->prng[1]; \ 754 | if (p->random_order) { \ 755 | p->count++; \ 756 | if (!p->initialized || ((p->count - 1) != p->state)) { \ 757 | goto clear; /* don't run this test yet */ \ 758 | } \ 759 | } \ 760 | if (g->running_test) { \ 761 | fprintf(stderr, "Error: Test run inside another test.\n"); \ 762 | return 0; \ 763 | } \ 764 | GREATEST_SET_TIME(g->suite.pre_test); \ 765 | if (g->setup) { g->setup(g->setup_udata); } \ 766 | p->count_run++; \ 767 | g->running_test = 1; \ 768 | return 1; /* test should be run */ \ 769 | } else { \ 770 | goto clear; /* skipped */ \ 771 | } \ 772 | clear: \ 773 | g->name_suffix = NULL; \ 774 | return 0; \ 775 | } \ 776 | \ 777 | static void greatest_do_pass(void) { \ 778 | struct greatest_run_info *g = &greatest_info; \ 779 | if (GREATEST_IS_VERBOSE()) { \ 780 | GREATEST_FPRINTF(GREATEST_STDOUT, "PASS %s: %s", \ 781 | g->name_buf, g->msg ? g->msg : ""); \ 782 | } else { \ 783 | GREATEST_FPRINTF(GREATEST_STDOUT, "."); \ 784 | } \ 785 | g->suite.passed++; \ 786 | } \ 787 | \ 788 | static void greatest_do_fail(void) { \ 789 | struct greatest_run_info *g = &greatest_info; \ 790 | if (GREATEST_IS_VERBOSE()) { \ 791 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 792 | "FAIL %s: %s (%s:%u)", g->name_buf, \ 793 | g->msg ? g->msg : "", g->fail_file, g->fail_line); \ 794 | } else { \ 795 | GREATEST_FPRINTF(GREATEST_STDOUT, "F"); \ 796 | g->col++; /* add linebreak if in line of '.'s */ \ 797 | if (g->col != 0) { \ 798 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 799 | g->col = 0; \ 800 | } \ 801 | GREATEST_FPRINTF(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n", \ 802 | g->name_buf, g->msg ? g->msg : "", \ 803 | g->fail_file, g->fail_line); \ 804 | } \ 805 | g->suite.failed++; \ 806 | } \ 807 | \ 808 | static void greatest_do_skip(void) { \ 809 | struct greatest_run_info *g = &greatest_info; \ 810 | if (GREATEST_IS_VERBOSE()) { \ 811 | GREATEST_FPRINTF(GREATEST_STDOUT, "SKIP %s: %s", \ 812 | g->name_buf, g->msg ? g->msg : ""); \ 813 | } else { \ 814 | GREATEST_FPRINTF(GREATEST_STDOUT, "s"); \ 815 | } \ 816 | g->suite.skipped++; \ 817 | } \ 818 | \ 819 | void greatest_test_post(int res) { \ 820 | GREATEST_SET_TIME(greatest_info.suite.post_test); \ 821 | if (greatest_info.teardown) { \ 822 | void *udata = greatest_info.teardown_udata; \ 823 | greatest_info.teardown(udata); \ 824 | } \ 825 | \ 826 | greatest_info.running_test = 0; \ 827 | if (res <= GREATEST_TEST_RES_FAIL) { \ 828 | greatest_do_fail(); \ 829 | } else if (res >= GREATEST_TEST_RES_SKIP) { \ 830 | greatest_do_skip(); \ 831 | } else if (res == GREATEST_TEST_RES_PASS) { \ 832 | greatest_do_pass(); \ 833 | } \ 834 | greatest_info.name_suffix = NULL; \ 835 | greatest_info.suite.tests_run++; \ 836 | greatest_info.col++; \ 837 | if (GREATEST_IS_VERBOSE()) { \ 838 | GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test, \ 839 | greatest_info.suite.post_test); \ 840 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 841 | } else if (greatest_info.col % greatest_info.width == 0) { \ 842 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 843 | greatest_info.col = 0; \ 844 | } \ 845 | fflush(GREATEST_STDOUT); \ 846 | } \ 847 | \ 848 | static void report_suite(void) { \ 849 | if (greatest_info.suite.tests_run > 0) { \ 850 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 851 | "\n%u test%s - %u passed, %u failed, %u skipped", \ 852 | greatest_info.suite.tests_run, \ 853 | greatest_info.suite.tests_run == 1 ? "" : "s", \ 854 | greatest_info.suite.passed, \ 855 | greatest_info.suite.failed, \ 856 | greatest_info.suite.skipped); \ 857 | GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite, \ 858 | greatest_info.suite.post_suite); \ 859 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 860 | } \ 861 | } \ 862 | \ 863 | static void update_counts_and_reset_suite(void) { \ 864 | greatest_info.setup = NULL; \ 865 | greatest_info.setup_udata = NULL; \ 866 | greatest_info.teardown = NULL; \ 867 | greatest_info.teardown_udata = NULL; \ 868 | greatest_info.passed += greatest_info.suite.passed; \ 869 | greatest_info.failed += greatest_info.suite.failed; \ 870 | greatest_info.skipped += greatest_info.suite.skipped; \ 871 | greatest_info.tests_run += greatest_info.suite.tests_run; \ 872 | memset(&greatest_info.suite, 0, sizeof(greatest_info.suite)); \ 873 | greatest_info.col = 0; \ 874 | } \ 875 | \ 876 | static int greatest_suite_pre(const char *suite_name) { \ 877 | struct greatest_prng *p = &greatest_info.prng[0]; \ 878 | if (!greatest_name_match(suite_name, greatest_info.suite_filter, 1) \ 879 | || (GREATEST_FAILURE_ABORT())) { return 0; } \ 880 | if (p->random_order) { \ 881 | p->count++; \ 882 | if (!p->initialized || ((p->count - 1) != p->state)) { \ 883 | return 0; /* don't run this suite yet */ \ 884 | } \ 885 | } \ 886 | p->count_run++; \ 887 | update_counts_and_reset_suite(); \ 888 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name); \ 889 | GREATEST_SET_TIME(greatest_info.suite.pre_suite); \ 890 | return 1; \ 891 | } \ 892 | \ 893 | static void greatest_suite_post(void) { \ 894 | GREATEST_SET_TIME(greatest_info.suite.post_suite); \ 895 | report_suite(); \ 896 | } \ 897 | \ 898 | static void greatest_run_suite(greatest_suite_cb *suite_cb, \ 899 | const char *suite_name) { \ 900 | if (greatest_suite_pre(suite_name)) { \ 901 | suite_cb(); \ 902 | greatest_suite_post(); \ 903 | } \ 904 | } \ 905 | \ 906 | int greatest_do_assert_equal_t(const void *expd, const void *got, \ 907 | greatest_type_info *type_info, void *udata) { \ 908 | int eq = 0; \ 909 | if (type_info == NULL || type_info->equal == NULL) { return 0; } \ 910 | eq = type_info->equal(expd, got, udata); \ 911 | if (!eq) { \ 912 | if (type_info->print != NULL) { \ 913 | GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: "); \ 914 | (void)type_info->print(expd, udata); \ 915 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n Got: "); \ 916 | (void)type_info->print(got, udata); \ 917 | GREATEST_FPRINTF(GREATEST_STDOUT, "\n"); \ 918 | } \ 919 | } \ 920 | return eq; \ 921 | } \ 922 | \ 923 | static void greatest_usage(const char *name) { \ 924 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 925 | "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n" \ 926 | " -h, --help print this Help\n" \ 927 | " -l List suites and tests, then exit (dry run)\n" \ 928 | " -f Stop runner after first failure\n" \ 929 | " -a Abort on first failure (implies -f)\n" \ 930 | " -v Verbose output\n" \ 931 | " -s SUITE only run suites containing substring SUITE\n" \ 932 | " -t TEST only run tests containing substring TEST\n" \ 933 | " -e only run exact name match for -s or -t\n" \ 934 | " -x EXCLUDE exclude tests containing substring EXCLUDE\n", \ 935 | name); \ 936 | } \ 937 | \ 938 | static void greatest_parse_options(int argc, char **argv) { \ 939 | int i = 0; \ 940 | for (i = 1; i < argc; i++) { \ 941 | if (argv[i][0] == '-') { \ 942 | char f = argv[i][1]; \ 943 | if ((f == 's' || f == 't' || f == 'x') && argc <= i + 1) { \ 944 | greatest_usage(argv[0]); exit(EXIT_FAILURE); \ 945 | } \ 946 | switch (f) { \ 947 | case 's': /* suite name filter */ \ 948 | greatest_set_suite_filter(argv[i + 1]); i++; break; \ 949 | case 't': /* test name filter */ \ 950 | greatest_set_test_filter(argv[i + 1]); i++; break; \ 951 | case 'x': /* test name exclusion */ \ 952 | greatest_set_test_exclude(argv[i + 1]); i++; break; \ 953 | case 'e': /* exact name match */ \ 954 | greatest_set_exact_name_match(); break; \ 955 | case 'f': /* first fail flag */ \ 956 | greatest_stop_at_first_fail(); break; \ 957 | case 'a': /* abort() on fail flag */ \ 958 | greatest_abort_on_fail(); break; \ 959 | case 'l': /* list only (dry run) */ \ 960 | greatest_list_only(); break; \ 961 | case 'v': /* first fail flag */ \ 962 | greatest_info.verbosity++; break; \ 963 | case 'h': /* help */ \ 964 | greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ 965 | default: \ 966 | case '-': \ 967 | if (0 == strncmp("--help", argv[i], 6)) { \ 968 | greatest_usage(argv[0]); exit(EXIT_SUCCESS); \ 969 | } else if (0 == strcmp("--", argv[i])) { \ 970 | return; /* ignore following arguments */ \ 971 | } \ 972 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 973 | "Unknown argument '%s'\n", argv[i]); \ 974 | greatest_usage(argv[0]); \ 975 | exit(EXIT_FAILURE); \ 976 | } \ 977 | } \ 978 | } \ 979 | } \ 980 | \ 981 | int greatest_all_passed(void) { return (greatest_info.failed == 0); } \ 982 | \ 983 | void greatest_set_test_filter(const char *filter) { \ 984 | greatest_info.test_filter = filter; \ 985 | } \ 986 | \ 987 | void greatest_set_test_exclude(const char *filter) { \ 988 | greatest_info.test_exclude = filter; \ 989 | } \ 990 | \ 991 | void greatest_set_suite_filter(const char *filter) { \ 992 | greatest_info.suite_filter = filter; \ 993 | } \ 994 | \ 995 | void greatest_set_exact_name_match(void) { \ 996 | greatest_info.exact_name_match = 1; \ 997 | } \ 998 | \ 999 | void greatest_stop_at_first_fail(void) { \ 1000 | greatest_set_flag(GREATEST_FLAG_FIRST_FAIL); \ 1001 | } \ 1002 | \ 1003 | void greatest_abort_on_fail(void) { \ 1004 | greatest_set_flag(GREATEST_FLAG_ABORT_ON_FAIL); \ 1005 | } \ 1006 | \ 1007 | void greatest_list_only(void) { \ 1008 | greatest_set_flag(GREATEST_FLAG_LIST_ONLY); \ 1009 | } \ 1010 | \ 1011 | void greatest_get_report(struct greatest_report_t *report) { \ 1012 | if (report) { \ 1013 | report->passed = greatest_info.passed; \ 1014 | report->failed = greatest_info.failed; \ 1015 | report->skipped = greatest_info.skipped; \ 1016 | report->assertions = greatest_info.assertions; \ 1017 | } \ 1018 | } \ 1019 | \ 1020 | unsigned int greatest_get_verbosity(void) { \ 1021 | return greatest_info.verbosity; \ 1022 | } \ 1023 | \ 1024 | void greatest_set_verbosity(unsigned int verbosity) { \ 1025 | greatest_info.verbosity = (unsigned char)verbosity; \ 1026 | } \ 1027 | \ 1028 | void greatest_set_flag(greatest_flag_t flag) { \ 1029 | greatest_info.flags = (unsigned char)(greatest_info.flags | flag); \ 1030 | } \ 1031 | \ 1032 | void greatest_set_test_suffix(const char *suffix) { \ 1033 | greatest_info.name_suffix = suffix; \ 1034 | } \ 1035 | \ 1036 | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) { \ 1037 | greatest_info.setup = cb; \ 1038 | greatest_info.setup_udata = udata; \ 1039 | } \ 1040 | \ 1041 | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) { \ 1042 | greatest_info.teardown = cb; \ 1043 | greatest_info.teardown_udata = udata; \ 1044 | } \ 1045 | \ 1046 | static int greatest_string_equal_cb(const void *expd, const void *got, \ 1047 | void *udata) { \ 1048 | size_t *size = (size_t *)udata; \ 1049 | return (size != NULL \ 1050 | ? (0 == strncmp((const char *)expd, (const char *)got, *size)) \ 1051 | : (0 == strcmp((const char *)expd, (const char *)got))); \ 1052 | } \ 1053 | \ 1054 | static int greatest_string_printf_cb(const void *t, void *udata) { \ 1055 | (void)udata; /* note: does not check \0 termination. */ \ 1056 | return GREATEST_FPRINTF(GREATEST_STDOUT, "%s", (const char *)t); \ 1057 | } \ 1058 | \ 1059 | greatest_type_info greatest_type_info_string = { \ 1060 | greatest_string_equal_cb, greatest_string_printf_cb, \ 1061 | }; \ 1062 | \ 1063 | static int greatest_memory_equal_cb(const void *expd, const void *got, \ 1064 | void *udata) { \ 1065 | greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ 1066 | return (0 == memcmp(expd, got, env->size)); \ 1067 | } \ 1068 | \ 1069 | /* Hexdump raw memory, with differences highlighted */ \ 1070 | static int greatest_memory_printf_cb(const void *t, void *udata) { \ 1071 | greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata; \ 1072 | const unsigned char *buf = (const unsigned char *)t; \ 1073 | unsigned char diff_mark = ' '; \ 1074 | FILE *out = GREATEST_STDOUT; \ 1075 | size_t i, line_i, line_len = 0; \ 1076 | int len = 0; /* format hexdump with differences highlighted */ \ 1077 | for (i = 0; i < env->size; i+= line_len) { \ 1078 | diff_mark = ' '; \ 1079 | line_len = env->size - i; \ 1080 | if (line_len > 16) { line_len = 16; } \ 1081 | for (line_i = i; line_i < i + line_len; line_i++) { \ 1082 | if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X'; \ 1083 | } \ 1084 | len += GREATEST_FPRINTF(out, "\n%04x %c ", \ 1085 | (unsigned int)i, diff_mark); \ 1086 | for (line_i = i; line_i < i + line_len; line_i++) { \ 1087 | int m = env->exp[line_i] == env->got[line_i]; /* match? */ \ 1088 | len += GREATEST_FPRINTF(out, "%02x%c", \ 1089 | buf[line_i], m ? ' ' : '<'); \ 1090 | } \ 1091 | for (line_i = 0; line_i < 16 - line_len; line_i++) { \ 1092 | len += GREATEST_FPRINTF(out, " "); \ 1093 | } \ 1094 | GREATEST_FPRINTF(out, " "); \ 1095 | for (line_i = i; line_i < i + line_len; line_i++) { \ 1096 | unsigned char c = buf[line_i]; \ 1097 | len += GREATEST_FPRINTF(out, "%c", isprint(c) ? c : '.'); \ 1098 | } \ 1099 | } \ 1100 | len += GREATEST_FPRINTF(out, "\n"); \ 1101 | return len; \ 1102 | } \ 1103 | \ 1104 | void greatest_prng_init_first_pass(int id) { \ 1105 | greatest_info.prng[id].random_order = 1; \ 1106 | greatest_info.prng[id].count_run = 0; \ 1107 | } \ 1108 | \ 1109 | int greatest_prng_init_second_pass(int id, unsigned long seed) { \ 1110 | struct greatest_prng *p = &greatest_info.prng[id]; \ 1111 | if (p->count == 0) { return 0; } \ 1112 | p->count_ceil = p->count; \ 1113 | for (p->m = 1; p->m < p->count; p->m <<= 1) {} \ 1114 | p->state = seed & 0x1fffffff; /* only use lower 29 bits */ \ 1115 | p->a = 4LU * p->state; /* to avoid overflow when */ \ 1116 | p->a = (p->a ? p->a : 4) | 1; /* multiplied by 4 */ \ 1117 | p->c = 2147483647; /* and so p->c ((2 ** 31) - 1) is */ \ 1118 | p->initialized = 1; /* always relatively prime to p->a. */ \ 1119 | fprintf(stderr, "init_second_pass: a %lu, c %lu, state %lu\n", \ 1120 | p->a, p->c, p->state); \ 1121 | return 1; \ 1122 | } \ 1123 | \ 1124 | /* Step the pseudorandom number generator until its state reaches \ 1125 | * another test ID between 0 and the test count. \ 1126 | * This use a linear congruential pseudorandom number generator, \ 1127 | * with the power-of-two ceiling of the test count as the modulus, the \ 1128 | * masked seed as the multiplier, and a prime as the increment. For \ 1129 | * each generated value < the test count, run the corresponding test. \ 1130 | * This will visit all IDs 0 <= X < mod once before repeating, \ 1131 | * with a starting position chosen based on the initial seed. \ 1132 | * For details, see: Knuth, The Art of Computer Programming \ 1133 | * Volume. 2, section 3.2.1. */ \ 1134 | void greatest_prng_step(int id) { \ 1135 | struct greatest_prng *p = &greatest_info.prng[id]; \ 1136 | do { \ 1137 | p->state = ((p->a * p->state) + p->c) & (p->m - 1); \ 1138 | } while (p->state >= p->count_ceil); \ 1139 | } \ 1140 | \ 1141 | void GREATEST_INIT(void) { \ 1142 | /* Suppress unused function warning if features aren't used */ \ 1143 | (void)greatest_run_suite; \ 1144 | (void)greatest_parse_options; \ 1145 | (void)greatest_prng_step; \ 1146 | (void)greatest_prng_init_first_pass; \ 1147 | (void)greatest_prng_init_second_pass; \ 1148 | (void)greatest_set_test_suffix; \ 1149 | \ 1150 | memset(&greatest_info, 0, sizeof(greatest_info)); \ 1151 | greatest_info.width = GREATEST_DEFAULT_WIDTH; \ 1152 | GREATEST_SET_TIME(greatest_info.begin); \ 1153 | } \ 1154 | \ 1155 | /* Report passes, failures, skipped tests, the number of \ 1156 | * assertions, and the overall run time. */ \ 1157 | void GREATEST_PRINT_REPORT(void) { \ 1158 | if (!GREATEST_LIST_ONLY()) { \ 1159 | update_counts_and_reset_suite(); \ 1160 | GREATEST_SET_TIME(greatest_info.end); \ 1161 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 1162 | "\nTotal: %u test%s", \ 1163 | greatest_info.tests_run, \ 1164 | greatest_info.tests_run == 1 ? "" : "s"); \ 1165 | GREATEST_CLOCK_DIFF(greatest_info.begin, \ 1166 | greatest_info.end); \ 1167 | GREATEST_FPRINTF(GREATEST_STDOUT, ", %u assertion%s\n", \ 1168 | greatest_info.assertions, \ 1169 | greatest_info.assertions == 1 ? "" : "s"); \ 1170 | GREATEST_FPRINTF(GREATEST_STDOUT, \ 1171 | "Pass: %u, fail: %u, skip: %u.\n", \ 1172 | greatest_info.passed, \ 1173 | greatest_info.failed, greatest_info.skipped); \ 1174 | } \ 1175 | } \ 1176 | \ 1177 | greatest_type_info greatest_type_info_memory = { \ 1178 | greatest_memory_equal_cb, greatest_memory_printf_cb, \ 1179 | }; \ 1180 | \ 1181 | greatest_run_info greatest_info 1182 | 1183 | /* Handle command-line arguments, etc. */ 1184 | #define GREATEST_MAIN_BEGIN() \ 1185 | do { \ 1186 | GREATEST_INIT(); \ 1187 | greatest_parse_options(argc, argv); \ 1188 | } while (0) 1189 | 1190 | /* Report results, exit with exit status based on results. */ 1191 | #define GREATEST_MAIN_END() \ 1192 | do { \ 1193 | GREATEST_PRINT_REPORT(); \ 1194 | return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE); \ 1195 | } while (0) 1196 | 1197 | /* Make abbreviations without the GREATEST_ prefix for the 1198 | * most commonly used symbols. */ 1199 | #if GREATEST_USE_ABBREVS 1200 | #define TEST GREATEST_TEST 1201 | #define SUITE GREATEST_SUITE 1202 | #define SUITE_EXTERN GREATEST_SUITE_EXTERN 1203 | #define RUN_TEST GREATEST_RUN_TEST 1204 | #define RUN_TEST1 GREATEST_RUN_TEST1 1205 | #define RUN_SUITE GREATEST_RUN_SUITE 1206 | #define IGNORE_TEST GREATEST_IGNORE_TEST 1207 | #define ASSERT GREATEST_ASSERT 1208 | #define ASSERTm GREATEST_ASSERTm 1209 | #define ASSERT_FALSE GREATEST_ASSERT_FALSE 1210 | #define ASSERT_EQ GREATEST_ASSERT_EQ 1211 | #define ASSERT_NEQ GREATEST_ASSERT_NEQ 1212 | #define ASSERT_GT GREATEST_ASSERT_GT 1213 | #define ASSERT_GTE GREATEST_ASSERT_GTE 1214 | #define ASSERT_LT GREATEST_ASSERT_LT 1215 | #define ASSERT_LTE GREATEST_ASSERT_LTE 1216 | #define ASSERT_EQ_FMT GREATEST_ASSERT_EQ_FMT 1217 | #define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE 1218 | #define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T 1219 | #define ASSERT_STR_EQ GREATEST_ASSERT_STR_EQ 1220 | #define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ 1221 | #define ASSERT_MEM_EQ GREATEST_ASSERT_MEM_EQ 1222 | #define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ 1223 | #define ASSERT_FALSEm GREATEST_ASSERT_FALSEm 1224 | #define ASSERT_EQm GREATEST_ASSERT_EQm 1225 | #define ASSERT_NEQm GREATEST_ASSERT_NEQm 1226 | #define ASSERT_GTm GREATEST_ASSERT_GTm 1227 | #define ASSERT_GTEm GREATEST_ASSERT_GTEm 1228 | #define ASSERT_LTm GREATEST_ASSERT_LTm 1229 | #define ASSERT_LTEm GREATEST_ASSERT_LTEm 1230 | #define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm 1231 | #define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm 1232 | #define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm 1233 | #define ASSERT_STR_EQm GREATEST_ASSERT_STR_EQm 1234 | #define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm 1235 | #define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm 1236 | #define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm 1237 | #define PASS GREATEST_PASS 1238 | #define FAIL GREATEST_FAIL 1239 | #define SKIP GREATEST_SKIP 1240 | #define PASSm GREATEST_PASSm 1241 | #define FAILm GREATEST_FAILm 1242 | #define SKIPm GREATEST_SKIPm 1243 | #define SET_SETUP GREATEST_SET_SETUP_CB 1244 | #define SET_TEARDOWN GREATEST_SET_TEARDOWN_CB 1245 | #define CHECK_CALL GREATEST_CHECK_CALL 1246 | #define SHUFFLE_TESTS GREATEST_SHUFFLE_TESTS 1247 | #define SHUFFLE_SUITES GREATEST_SHUFFLE_SUITES 1248 | 1249 | #ifdef GREATEST_VA_ARGS 1250 | #define RUN_TESTp GREATEST_RUN_TESTp 1251 | #endif 1252 | 1253 | #if GREATEST_USE_LONGJMP 1254 | #define ASSERT_OR_LONGJMP GREATEST_ASSERT_OR_LONGJMP 1255 | #define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm 1256 | #define FAIL_WITH_LONGJMP GREATEST_FAIL_WITH_LONGJMP 1257 | #define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm 1258 | #endif 1259 | 1260 | #endif /* USE_ABBREVS */ 1261 | 1262 | #if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS) 1263 | } 1264 | #endif 1265 | 1266 | #endif 1267 | -------------------------------------------------------------------------------- /test/test_tinf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * tinf unit test 3 | * 4 | * Copyright (c) 2014-2022 Joergen Ibsen 5 | * 6 | * This software is provided 'as-is', without any express or implied 7 | * warranty. In no event will the authors be held liable for any damages 8 | * arising from the use of this software. 9 | * 10 | * Permission is granted to anyone to use this software for any purpose, 11 | * including commercial applications, and to alter it and redistribute it 12 | * freely, subject to the following restrictions: 13 | * 14 | * 1. The origin of this software must not be misrepresented; you must 15 | * not claim that you wrote the original software. If you use this 16 | * software in a product, an acknowledgment in the product 17 | * documentation would be appreciated but is not required. 18 | * 19 | * 2. Altered source versions must be plainly marked as such, and must 20 | * not be misrepresented as being the original software. 21 | * 22 | * 3. This notice may not be removed or altered from any source 23 | * distribution. 24 | */ 25 | 26 | #include "tinf.h" 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include "greatest.h" 33 | 34 | #ifndef ARRAY_SIZE 35 | # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 36 | #endif 37 | 38 | static const unsigned char robuffer[] = { 0 }; 39 | 40 | static unsigned char buffer[4096]; 41 | 42 | struct packed_data { 43 | unsigned int src_size; 44 | unsigned int depacked_size; 45 | const unsigned char data[32]; 46 | }; 47 | 48 | static const struct packed_data inflate_errors[] = { 49 | /* Unable to read first byte */ 50 | { 0, 1, { 0x42 } }, 51 | /* No next block after non-final block */ 52 | { 5, 1, { 0x00, 0x00, 0x00, 0xFF, 0xFF } }, 53 | /* Invalid block type 11 */ 54 | { 13, 1, { 0x07, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xFF, 0x6B, 0x01, 0x00 } }, 55 | 56 | /* Uncompressed block incomplete */ 57 | { 4, 1, { 0x01, 0x00, 0x00, 0xFF } }, 58 | /* Uncompressed block inv length wrong */ 59 | { 5, 1, { 0x01, 0x00, 0x00, 0x00, 0x00 } }, 60 | /* Uncompressed block missing data */ 61 | { 5, 1, { 0x01, 0x01, 0x00, 0xFE, 0xFF } }, 62 | /* Uncompressed block writing one past end */ 63 | { 7, 1, { 0x01, 0x02, 0x00, 0xFD, 0xFF, 0x42, 0x42 } }, 64 | 65 | /* Fixed incomplete */ 66 | { 2, 1, { 0x63, 0x00 } }, 67 | /* Fixed reading one byte before start */ 68 | { 4, 4, { 0x63, 0x00, 0x42, 0x00 } }, 69 | /* Fixed literal writing one byte past end */ 70 | { 4, 1, { 0x63, 0x60, 0x00, 0x00 } }, 71 | /* Fixed match writing one byte past end */ 72 | { 4, 3, { 0x63, 0x00, 0x02, 0x00 } }, 73 | /* Fixed len > 285 */ 74 | { 4, 1024, { 0x63, 0x18, 0x03, 0x00 } }, 75 | /* Fixed dist > 29 */ 76 | { 4, 4, { 0x63, 0x00, 0x3E, 0x00 } }, 77 | 78 | /* Dynamic incomplete no HDIST */ 79 | { 1, 1, { 0x05 } }, 80 | /* Dynamic incomplete HCLEN */ 81 | { 2, 1, { 0x05, 0x00 } }, 82 | /* Dynamic incomplete code length code lengths */ 83 | { 4, 1, { 0x05, 0x40, 0x00, 0x04 } }, 84 | /* Dynamic code length code lengths all zero*/ 85 | { 6, 1, { 0x05, 0x0B, 0x00, 0x00, 0x00, 0x00 } }, 86 | /* Dynamic incomplete literal code lengths */ 87 | { 4, 1, { 0x05, 0x20, 0x00, 0x04 } }, 88 | /* Dynamic 256 has code length 0 */ 89 | { 13, 1, { 0x05, 0xCB, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xD7, 0x02, 0x00 } }, 90 | /* Dynamic only 256 available, but data contains 1 bit */ 91 | { 13, 1, { 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x7F, 0xEB, 0x00, 0x02 } }, 92 | /* Dynamic only one distance code, but compressed data contains 1 bit */ 93 | { 13, 4, { 0x0D, 0xC0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x3F, 0x0F } }, 94 | /* Dynamic all distance codes zero, but compressed data contains match */ 95 | { 14, 4, { 0x0D, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x1F, 0xC0, 0x02 } }, 96 | /* Dynamic only one code length code length, but compressed data contains 1 bit */ 97 | { 8, 4, { 0x05, 0x00, 0x80, 0xC0, 0xBF, 0x37, 0x00, 0x00 } }, 98 | /* Dynamic first code length code is copy prev length */ 99 | { 13, 1, { 0x05, 0xCA, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xF1, 0x87, 0x0E, 0x00 } }, 100 | /* Dynamic underfull code length in code length code (missing len 2 code) */ 101 | { 13, 1, { 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7F, 0xEB, 0x00, 0x00 } }, 102 | /* Dynamic overfull code length in code length code (extra len 2 code) */ 103 | { 13, 1, { 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x82, 0x20, 0x7F, 0xEB, 0x00, 0x00 } }, 104 | /* Dynamic overfull code length in literal/length code (extra len 1 codes) */ 105 | { 15, 4, { 0x0D, 0xC3, 0x37, 0x01, 0x00, 0x00, 0x00, 0x80, 0x20, 0x46, 0xFF, 0xCE, 0xCA, 0x61, 0x01 } }, 106 | /* Dynamic underfull code length in distance code (missing len 2 code) */ 107 | { 14, 4, { 0x0D, 0xCE, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFD, 0xA9, 0xBB, 0x09, 0x1A } }, 108 | /* Dynamic overfull code length in distance code (extra len 2 code) */ 109 | { 15, 4, { 0x0D, 0xCE, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFD, 0xA9, 0xBB, 0x1F, 0xA0, 0x01 } }, 110 | /* Dynamic HLIT too large (30 = 287) */ 111 | { 15, 4, { 0xF5, 0xCB, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x9F, 0x24, 0x00, 0x01 } }, 112 | /* Dynamic HDIST too large (30 = 31) */ 113 | { 15, 4, { 0xED, 0xDE, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x5F, 0x24, 0x13, 0x01 } }, 114 | /* Dynamic number of literal/length codes too large (last repeat exceeds limit) */ 115 | { 15, 4, { 0x0D, 0xCB, 0x37, 0x01, 0x00, 0x00, 0x00, 0x80, 0x20, 0xFA, 0xA7, 0x56, 0x08, 0x60, 0x01 } } 116 | }; 117 | 118 | static const struct packed_data zlib_errors[] = { 119 | /* Too short (not enough room for 2 byte header and 4 byte trailer) */ 120 | { 5, 1, { 0x78, 0x9C, 0x63, 0x00, 0x00 } }, 121 | /* Too short, but last 4 bytes are valid Adler-32 */ 122 | { 8, 1, { 0x78, 0x9C, 0x63, 0x04, 0x00, 0x02, 0x00, 0x02 } }, 123 | /* Header checksum error */ 124 | { 9, 1, { 0x78, 0x9D, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } }, 125 | /* Method not deflate */ 126 | { 9, 1, { 0x74, 0x9D, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } }, 127 | /* Window size invalid */ 128 | { 9, 1, { 0x88, 0x98, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } }, 129 | /* Preset dictionary (not supported by tinf) */ 130 | { 13, 1, { 0x78, 0xBB, 0x00, 0x00, 0x00, 0x01, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } }, 131 | 132 | /* Adler-32 checksum does not match value in trailer */ 133 | { 9, 1, { 0x78, 0x9C, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } }, 134 | 135 | /* Decompression error (bad block type) */ 136 | { 9, 1, { 0x78, 0x9C, 0x67, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } } 137 | }; 138 | 139 | static const struct packed_data gzip_errors[] = { 140 | /* Too short (not enough room for 10 byte header and 8 byte trailer) */ 141 | { 17, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2 } }, 142 | /* Too short, but last 8 bytes are valid CRC32 and size */ 143 | { 19, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, 144 | /* Error in first id byte */ 145 | { 21, 1, { 0x1E, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } }, 146 | /* Error in second id byte */ 147 | { 21, 1, { 0x1F, 0x8A, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } }, 148 | /* Method not deflate */ 149 | { 21, 1, { 0x1F, 0x8B, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } }, 150 | /* Reserved flag bit set */ 151 | { 21, 1, { 0x1F, 0x8B, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } }, 152 | /* Header CRC16 error */ 153 | { 23, 1, { 0x1F, 0x8B, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x17, 0x9C, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } }, 154 | /* Header CRC16 exceeds input size */ 155 | { 19, 1, { 0x1F, 0x8B, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x2E } }, 156 | /* Filename exceeds input size */ 157 | { 19, 1, { 0x1F, 0x8B, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 } }, 158 | /* Comment exceeds input size */ 159 | { 19, 1, { 0x1F, 0x8B, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 } }, 160 | /* Extra data exceeds input size */ 161 | { 19, 1, { 0x1F, 0x8B, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x08, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 } }, 162 | /* Not enough room for trailer after comment */ 163 | { 19, 1, { 0x1F, 0x8B, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00 } }, 164 | 165 | /* Decompressed size does not match size in trailer */ 166 | { 21, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x02, 0x00, 0x00, 0x00 } }, 167 | /* CRC32 checksum does not match value in trailer */ 168 | { 21, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x01, 0xD2, 0x01, 0x00, 0x00, 0x00 } }, 169 | 170 | /* Decompression error (bad block type) */ 171 | { 21, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x67, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } } 172 | }; 173 | 174 | /* tinflate */ 175 | 176 | TEST inflate_padding(void) 177 | { 178 | /* Empty buffer, fixed, 6 bits of padding in the second byte set to 1 */ 179 | static const unsigned char data[] = { 180 | 0x03, 0xFC 181 | }; 182 | unsigned int dlen = 0; 183 | int res; 184 | 185 | res = tinf_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 186 | 187 | ASSERT(res == TINF_OK && dlen == 0); 188 | 189 | PASS(); 190 | } 191 | 192 | TEST inflate_empty_no_literals(void) 193 | { 194 | /* Empty buffer, dynamic with 256 as only literal/length code 195 | * 196 | * You could argue that since the RFC only has an exception allowing 197 | * one symbol for the distance tree, the literal/length tree should 198 | * be complete. However gzip allows this. 199 | * 200 | * See also: https://github.com/madler/zlib/issues/75 201 | */ 202 | static const unsigned char data[] = { 203 | 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xFF, 204 | 0x6B, 0x01, 0x00 205 | }; 206 | unsigned int dlen = 0; 207 | int res; 208 | 209 | res = tinf_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 210 | 211 | ASSERT(res == TINF_OK && dlen == 0); 212 | 213 | PASS(); 214 | } 215 | 216 | TEST inflate_huffman_only(void) 217 | { 218 | /* 256 zero bytes compressed using Huffman only (no match or distance codes) */ 219 | static const unsigned char data[] = { 220 | 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 221 | 0xD5, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 222 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 223 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 224 | 0x00, 0x00, 0x00, 0x00, 0x02 225 | }; 226 | unsigned char out[256]; 227 | unsigned int dlen = ARRAY_SIZE(out); 228 | int res; 229 | size_t i; 230 | 231 | memset(out, 0xFF, ARRAY_SIZE(out)); 232 | 233 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 234 | 235 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 236 | 237 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 238 | if (out[i]) { 239 | FAIL(); 240 | } 241 | } 242 | 243 | PASS(); 244 | } 245 | 246 | TEST inflate_rle(void) 247 | { 248 | /* 256 zero bytes compressed using RLE (only one distance code) */ 249 | static const unsigned char data[] = { 250 | 0xE5, 0xC0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 251 | 0xA9, 0x07, 0x39, 0x73, 0x01 252 | }; 253 | unsigned char out[256]; 254 | unsigned int dlen = ARRAY_SIZE(out); 255 | int res; 256 | size_t i; 257 | 258 | memset(out, 0xFF, ARRAY_SIZE(out)); 259 | 260 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 261 | 262 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 263 | 264 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 265 | if (out[i]) { 266 | FAIL(); 267 | } 268 | } 269 | 270 | PASS(); 271 | } 272 | 273 | TEST inflate_max_matchlen(void) 274 | { 275 | /* 259 zero bytes compressed using literal/length code 285 (len 258) */ 276 | static const unsigned char data[] = { 277 | 0xED, 0xCC, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 278 | 0xA9, 0x17, 0xB9, 0x00, 0x2C 279 | }; 280 | unsigned char out[259]; 281 | unsigned int dlen = ARRAY_SIZE(out); 282 | int res; 283 | size_t i; 284 | 285 | memset(out, 0xFF, ARRAY_SIZE(out)); 286 | 287 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 288 | 289 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 290 | 291 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 292 | if (out[i]) { 293 | FAIL(); 294 | } 295 | } 296 | 297 | PASS(); 298 | } 299 | 300 | TEST inflate_max_matchlen_alt(void) 301 | { 302 | /* 259 zero bytes compressed using literal/length code 284 + 31 (len 258) 303 | * 304 | * Technically, this is outside the range specified in the RFC, but 305 | * gzip allows it. 306 | * 307 | * See also: https://github.com/madler/zlib/issues/75 308 | */ 309 | static const unsigned char data[] = { 310 | 0xE5, 0xCC, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 311 | 0xA9, 0x07, 0xB9, 0x00, 0xFC, 0x05 312 | }; 313 | unsigned char out[259]; 314 | unsigned int dlen = ARRAY_SIZE(out); 315 | int res; 316 | size_t i; 317 | 318 | memset(out, 0xFF, ARRAY_SIZE(out)); 319 | 320 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 321 | 322 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 323 | 324 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 325 | if (out[i]) { 326 | FAIL(); 327 | } 328 | } 329 | 330 | PASS(); 331 | } 332 | 333 | TEST inflate_max_matchdist(void) 334 | { 335 | /* A match of length 3 with a distance of 32768 */ 336 | static const unsigned char data[] = { 337 | 0xED, 0xDD, 0x01, 0x01, 0x00, 0x00, 0x08, 0x02, 0x20, 0xED, 338 | 0xFF, 0xE8, 0xFA, 0x11, 0x1C, 0x61, 0x9A, 0xF7, 0x00, 0x00, 339 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 340 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 341 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 342 | 0xFE, 0xFF, 0x05 343 | }; 344 | unsigned char out[32771]; 345 | unsigned int dlen = ARRAY_SIZE(out); 346 | int res; 347 | size_t i; 348 | 349 | memset(out, 0xFF, ARRAY_SIZE(out)); 350 | 351 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 352 | 353 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 354 | 355 | ASSERT(out[0] == 2 && out[1] == 1 && out[2] == 0); 356 | 357 | for (i = 3; i < ARRAY_SIZE(out) - 3; ++i) { 358 | if (out[i]) { 359 | FAIL(); 360 | } 361 | } 362 | 363 | ASSERT(out[ARRAY_SIZE(out) - 3] == 2); 364 | ASSERT(out[ARRAY_SIZE(out) - 2] == 1); 365 | ASSERT(out[ARRAY_SIZE(out) - 1] == 0); 366 | 367 | PASS(); 368 | } 369 | 370 | TEST inflate_code_length_codes(void) 371 | { 372 | /* 4 zero bytes compressed, code length codes include codes 16, 17, and 18 */ 373 | static const unsigned char data[] = { 374 | 0x0D, 0xC3, 0x37, 0x01, 0x00, 0x00, 0x00, 0x80, 0x20, 0xFA, 375 | 0x77, 0x1E, 0xCA, 0x61, 0x01 376 | }; 377 | unsigned char out[4]; 378 | unsigned int dlen = ARRAY_SIZE(out); 379 | int res; 380 | size_t i; 381 | 382 | memset(out, 0xFF, ARRAY_SIZE(out)); 383 | 384 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 385 | 386 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 387 | 388 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 389 | if (out[i]) { 390 | FAIL(); 391 | } 392 | } 393 | 394 | PASS(); 395 | } 396 | 397 | TEST inflate_max_codelen(void) 398 | { 399 | /* Use all codeword lengths including 15 */ 400 | static const unsigned char data[] = { 401 | 0x05, 0xEA, 0x01, 0x82, 0x24, 0x49, 0x92, 0x24, 0x49, 0x02, 402 | 0x12, 0x8B, 0x9A, 0x47, 0x56, 0xCF, 0xDE, 0xFF, 0x9F, 0x7B, 403 | 0x0F, 0xD0, 0xEE, 0x7D, 0xBF, 0xBF, 0x7F, 0xFF, 0xFD, 0xEF, 404 | 0xFF, 0xFE, 0xDF, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0x03 405 | }; 406 | unsigned char out[15]; 407 | unsigned int dlen = ARRAY_SIZE(out); 408 | int res; 409 | size_t i; 410 | 411 | memset(out, 0xFF, ARRAY_SIZE(out)); 412 | 413 | res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 414 | 415 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 416 | 417 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 418 | if (out[i] != i) { 419 | FAIL(); 420 | } 421 | } 422 | 423 | PASS(); 424 | } 425 | 426 | /* Test tinf_uncompress on random data */ 427 | TEST inflate_random(void) 428 | { 429 | unsigned char data[256]; 430 | unsigned int len; 431 | 432 | for (len = 1; len < ARRAY_SIZE(data); ++len) { 433 | unsigned int dlen = ARRAY_SIZE(buffer); 434 | size_t i; 435 | 436 | for (i = 0; i < len; ++i) { 437 | data[i] = (unsigned char) rand(); 438 | } 439 | 440 | /* Make sure btype is valid */ 441 | if ((data[0] & 0x06) == 0x06) { 442 | data[0] &= (rand() > RAND_MAX / 2) ? ~0x02 : ~0x04; 443 | } 444 | 445 | tinf_uncompress(buffer, &dlen, data, len); 446 | } 447 | 448 | PASS(); 449 | } 450 | 451 | /* Test tinf_uncompress on compressed data with errors */ 452 | TEST inflate_error_case(const void *closure) 453 | { 454 | const struct packed_data *pd = (const struct packed_data *) closure; 455 | int res; 456 | 457 | unsigned int size = pd->depacked_size; 458 | res = tinf_uncompress(buffer, &size, pd->data, pd->src_size); 459 | 460 | ASSERT(res != TINF_OK); 461 | 462 | PASS(); 463 | } 464 | 465 | SUITE(tinflate) 466 | { 467 | char suffix[32]; 468 | size_t i; 469 | 470 | RUN_TEST(inflate_padding); 471 | RUN_TEST(inflate_empty_no_literals); 472 | RUN_TEST(inflate_huffman_only); 473 | RUN_TEST(inflate_rle); 474 | RUN_TEST(inflate_max_matchlen); 475 | RUN_TEST(inflate_max_matchlen_alt); 476 | RUN_TEST(inflate_max_matchdist); 477 | RUN_TEST(inflate_code_length_codes); 478 | RUN_TEST(inflate_max_codelen); 479 | 480 | RUN_TEST(inflate_random); 481 | 482 | for (i = 0; i < ARRAY_SIZE(inflate_errors); ++i) { 483 | sprintf(suffix, "%d", (int) i); 484 | greatest_set_test_suffix(suffix); 485 | RUN_TEST1(inflate_error_case, &inflate_errors[i]); 486 | } 487 | } 488 | 489 | /* tinfzlib */ 490 | 491 | TEST zlib_empty_raw(void) 492 | { 493 | /* Empty buffer, uncompressed */ 494 | static const unsigned char data[] = { 495 | 0x78, 0x9C, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 496 | 0x01 497 | }; 498 | unsigned int dlen = 0; 499 | int res; 500 | 501 | res = tinf_zlib_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 502 | 503 | ASSERT(res == TINF_OK && dlen == 0); 504 | 505 | PASS(); 506 | } 507 | 508 | TEST zlib_empty_fixed(void) 509 | { 510 | /* Empty buffer, fixed Huffman */ 511 | static const unsigned char data[] = { 512 | 0x78, 0x9C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01 513 | }; 514 | unsigned int dlen = 0; 515 | int res; 516 | 517 | res = tinf_zlib_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 518 | 519 | ASSERT(res == TINF_OK && dlen == 0); 520 | 521 | PASS(); 522 | } 523 | 524 | TEST zlib_empty_dynamic(void) 525 | { 526 | /* Empty buffer, dynamic Huffman */ 527 | static const unsigned char data[] = { 528 | 0x78, 0x9C, 0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 529 | 0x10, 0xFF, 0xD5, 0x08, 0x00, 0x00, 0x00, 0x01 530 | }; 531 | unsigned int dlen = 0; 532 | int res; 533 | 534 | res = tinf_zlib_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 535 | 536 | ASSERT(res == TINF_OK && dlen == 0); 537 | 538 | PASS(); 539 | } 540 | 541 | TEST zlib_onebyte_raw(void) 542 | { 543 | /* One byte 00, uncompressed */ 544 | static const unsigned char data[] = { 545 | 0x78, 0x9C, 0x01, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01, 546 | 0x00, 0x01 547 | }; 548 | unsigned char out[] = { 0xFF }; 549 | unsigned int dlen = 1; 550 | int res; 551 | 552 | res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 553 | 554 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 555 | 556 | PASS(); 557 | } 558 | 559 | TEST zlib_onebyte_fixed(void) 560 | { 561 | /* One byte 00, fixed Huffman */ 562 | static const unsigned char data[] = { 563 | 0x78, 0x9C, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 564 | }; 565 | unsigned char out[] = { 0xFF }; 566 | unsigned int dlen = 1; 567 | int res; 568 | 569 | res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 570 | 571 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 572 | 573 | PASS(); 574 | } 575 | 576 | TEST zlib_onebyte_dynamic(void) 577 | { 578 | /* One byte 00, dynamic Huffman */ 579 | static const unsigned char data[] = { 580 | 0x78, 0x9C, 0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 581 | 0x10, 0xFF, 0xD5, 0x10, 0x00, 0x01, 0x00, 0x01 582 | }; 583 | unsigned char out[] = { 0xFF }; 584 | unsigned int dlen = 1; 585 | int res; 586 | 587 | res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 588 | 589 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 590 | 591 | PASS(); 592 | } 593 | 594 | TEST zlib_zeroes(void) 595 | { 596 | /* 256 zero bytes, to test unrolling in Adler-32 */ 597 | static const unsigned char data[] = { 598 | 0x78, 0x9C, 0x63, 0x60, 0x18, 0xD9, 0x00, 0x00, 0x01, 0x00, 599 | 0x00, 0x01 600 | }; 601 | unsigned char out[256]; 602 | unsigned int dlen = ARRAY_SIZE(out); 603 | int res; 604 | size_t i; 605 | 606 | memset(out, 0xFF, ARRAY_SIZE(out)); 607 | 608 | res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 609 | 610 | ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out)); 611 | 612 | for (i = 0; i < ARRAY_SIZE(out); ++i) { 613 | if (out[i]) { 614 | FAIL(); 615 | } 616 | } 617 | 618 | PASS(); 619 | } 620 | 621 | /* Test tinf_zlib_uncompress on compressed data with errors */ 622 | TEST zlib_error_case(const void *closure) 623 | { 624 | const struct packed_data *pd = (const struct packed_data *) closure; 625 | int res; 626 | 627 | unsigned int size = pd->depacked_size; 628 | res = tinf_zlib_uncompress(buffer, &size, pd->data, pd->src_size); 629 | 630 | ASSERT(res != TINF_OK); 631 | 632 | PASS(); 633 | } 634 | 635 | SUITE(tinfzlib) 636 | { 637 | char suffix[32]; 638 | size_t i; 639 | 640 | RUN_TEST(zlib_empty_raw); 641 | RUN_TEST(zlib_empty_fixed); 642 | RUN_TEST(zlib_empty_dynamic); 643 | 644 | RUN_TEST(zlib_onebyte_raw); 645 | RUN_TEST(zlib_onebyte_fixed); 646 | RUN_TEST(zlib_onebyte_dynamic); 647 | RUN_TEST(zlib_zeroes); 648 | 649 | for (i = 0; i < ARRAY_SIZE(zlib_errors); ++i) { 650 | sprintf(suffix, "%d", (int) i); 651 | greatest_set_test_suffix(suffix); 652 | RUN_TEST1(zlib_error_case, &zlib_errors[i]); 653 | } 654 | } 655 | 656 | /* tinfgzip */ 657 | 658 | TEST gzip_empty_raw(void) 659 | { 660 | /* Empty buffer, uncompressed */ 661 | static const unsigned char data[] = { 662 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 663 | 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 664 | 0x00, 0x00, 0x00 665 | }; 666 | unsigned int dlen = 0; 667 | int res; 668 | 669 | res = tinf_gzip_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 670 | 671 | ASSERT(res == TINF_OK && dlen == 0); 672 | 673 | PASS(); 674 | } 675 | 676 | TEST gzip_empty_fixed(void) 677 | { 678 | /* Empty buffer, fixed Huffman */ 679 | static const unsigned char data[] = { 680 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 681 | 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 682 | }; 683 | unsigned int dlen = 0; 684 | int res; 685 | 686 | res = tinf_gzip_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 687 | 688 | ASSERT(res == TINF_OK && dlen == 0); 689 | 690 | PASS(); 691 | } 692 | 693 | TEST gzip_empty_dynamic(void) 694 | { 695 | /* Empty buffer, dynamic Huffman */ 696 | static const unsigned char data[] = { 697 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 698 | 0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 699 | 0xD5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 700 | }; 701 | unsigned int dlen = 0; 702 | int res; 703 | 704 | res = tinf_gzip_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data)); 705 | 706 | ASSERT(res == TINF_OK && dlen == 0); 707 | 708 | PASS(); 709 | } 710 | 711 | TEST gzip_onebyte_raw(void) 712 | { 713 | /* One byte 00, uncompressed */ 714 | static const unsigned char data[] = { 715 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 716 | 0x01, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 717 | 0x01, 0x00, 0x00, 0x00 718 | }; 719 | unsigned char out[] = { 0xFF }; 720 | unsigned int dlen = 1; 721 | int res; 722 | 723 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 724 | 725 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 726 | 727 | PASS(); 728 | } 729 | 730 | TEST gzip_onebyte_fixed(void) 731 | { 732 | /* One byte 00, fixed Huffman */ 733 | static const unsigned char data[] = { 734 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 735 | 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 736 | 0x00 737 | }; 738 | unsigned char out[] = { 0xFF }; 739 | unsigned int dlen = 1; 740 | int res; 741 | 742 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 743 | 744 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 745 | 746 | PASS(); 747 | } 748 | 749 | TEST gzip_onebyte_dynamic(void) 750 | { 751 | /* One byte 00, dynamic Huffman */ 752 | static const unsigned char data[] = { 753 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 754 | 0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 755 | 0xD5, 0x10, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 756 | }; 757 | unsigned char out[] = { 0xFF }; 758 | unsigned int dlen = 1; 759 | int res; 760 | 761 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 762 | 763 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 764 | 765 | PASS(); 766 | } 767 | 768 | TEST gzip_fhcrc(void) 769 | { 770 | /* One byte 00, uncompressed, fhcrc */ 771 | static const unsigned char data[] = { 772 | 0x1F, 0x8B, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 773 | 0x17, 0x9D, 0x01, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x8D, 0xEF, 774 | 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 775 | }; 776 | unsigned char out[] = { 0xFF }; 777 | unsigned int dlen = 1; 778 | int res; 779 | 780 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 781 | 782 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 783 | 784 | PASS(); 785 | } 786 | 787 | TEST gzip_fextra(void) 788 | { 789 | /* One byte 00, uncompressed, fextra */ 790 | static const unsigned char data[] = { 791 | 0x1F, 0x8B, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 792 | 0x04, 0x00, 0x64, 0x61, 0x74, 0x61, 0x01, 0x01, 0x00, 0xFE, 793 | 0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 794 | }; 795 | unsigned char out[] = { 0xFF }; 796 | unsigned int dlen = 1; 797 | int res; 798 | 799 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 800 | 801 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 802 | 803 | PASS(); 804 | } 805 | 806 | TEST gzip_fname(void) 807 | { 808 | /* One byte 00, uncompressed, fname */ 809 | static const unsigned char data[] = { 810 | 0x1F, 0x8B, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 811 | 0x66, 0x6F, 0x6F, 0x2E, 0x63, 0x00, 0x01, 0x01, 0x00, 0xFE, 812 | 0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 813 | }; 814 | unsigned char out[] = { 0xFF }; 815 | unsigned int dlen = 1; 816 | int res; 817 | 818 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 819 | 820 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 821 | 822 | PASS(); 823 | } 824 | 825 | TEST gzip_fcomment(void) 826 | { 827 | /* One byte 00, uncompressed, fcomment */ 828 | static const unsigned char data[] = { 829 | 0x1F, 0x8B, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 830 | 0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x01, 0x01, 0x00, 0xFE, 831 | 0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 832 | }; 833 | unsigned char out[] = { 0xFF }; 834 | unsigned int dlen = 1; 835 | int res; 836 | 837 | res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data)); 838 | 839 | ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0); 840 | 841 | PASS(); 842 | } 843 | 844 | /* Test tinf_gzip_uncompress on compressed data with errors */ 845 | TEST gzip_error_case(const void *closure) 846 | { 847 | const struct packed_data *pd = (const struct packed_data *) closure; 848 | int res; 849 | 850 | unsigned int size = pd->depacked_size; 851 | res = tinf_gzip_uncompress(buffer, &size, pd->data, pd->src_size); 852 | 853 | ASSERT(res != TINF_OK); 854 | 855 | PASS(); 856 | } 857 | 858 | SUITE(tinfgzip) 859 | { 860 | char suffix[32]; 861 | size_t i; 862 | 863 | RUN_TEST(gzip_empty_raw); 864 | RUN_TEST(gzip_empty_fixed); 865 | RUN_TEST(gzip_empty_dynamic); 866 | 867 | RUN_TEST(gzip_onebyte_raw); 868 | RUN_TEST(gzip_onebyte_fixed); 869 | RUN_TEST(gzip_onebyte_dynamic); 870 | 871 | RUN_TEST(gzip_fhcrc); 872 | RUN_TEST(gzip_fextra); 873 | RUN_TEST(gzip_fname); 874 | RUN_TEST(gzip_fcomment); 875 | 876 | for (i = 0; i < ARRAY_SIZE(gzip_errors); ++i) { 877 | sprintf(suffix, "%d", (int) i); 878 | greatest_set_test_suffix(suffix); 879 | RUN_TEST1(gzip_error_case, &gzip_errors[i]); 880 | } 881 | } 882 | 883 | GREATEST_MAIN_DEFS(); 884 | 885 | int main(int argc, char *argv[]) 886 | { 887 | GREATEST_MAIN_BEGIN(); 888 | 889 | srand(time(NULL)); 890 | 891 | tinf_init(); 892 | 893 | RUN_SUITE(tinflate); 894 | RUN_SUITE(tinfzlib); 895 | RUN_SUITE(tinfgzip); 896 | 897 | GREATEST_MAIN_END(); 898 | } 899 | -------------------------------------------------------------------------------- /tools/gengztest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (c) 2014-2019 Joergen Ibsen 4 | # 5 | # Permission is hereby granted, free of charge, to any person obtaining a 6 | # copy of this software and associated documentation files (the "Software"), 7 | # to deal in the Software without restriction, including without limitation 8 | # the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 | # and/or sell copies of the Software, and to permit persons to whom the 10 | # Software is 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 18 | # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 | # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 | # DEALINGS IN THE SOFTWARE. 22 | 23 | """ 24 | Gzip test file generator. 25 | 26 | Generates gzip test files with specified fields in the header. 27 | """ 28 | 29 | import argparse 30 | import struct 31 | import zlib 32 | import textwrap 33 | 34 | def write_gzip(f, args): 35 | """Write gzip data to file f.""" 36 | 37 | # gzip header 38 | data = bytearray.fromhex('1f 8b 08 00 00 00 00 00 02 0b') 39 | 40 | flags = 0 41 | 42 | if args.s: 43 | flags |= 2 44 | 45 | if args.extra: 46 | flags |= 4 47 | edata = args.extra.encode('ascii') 48 | data.extend(struct.pack('I', args.preset_dict)) 53 | 54 | flg |= 31 - ((256 * cmf + flg) % 31) 55 | 56 | data[0] = cmf 57 | data[1] = flg 58 | 59 | if args.data == 'empty': 60 | if args.method == 'raw': 61 | # empty buffer, uncompressed 62 | data.extend(bytes.fromhex('01 00 00 ff ff')) 63 | elif args.method == 'fixed': 64 | # empty buffer, fixed Huffman 65 | data.extend(bytes.fromhex('03 00')) 66 | elif args.method == 'dynamic': 67 | # empty buffer, dynamic Huffman 68 | data.extend(bytes.fromhex('05 c1 81 00 00 00 00 00 10 ff d5 08')) 69 | # Adler-32 of empty buffer 70 | data.extend(struct.pack('>I', 1)) 71 | elif args.data == 'byte00': 72 | if args.method == 'raw': 73 | # one byte 00, uncompressed 74 | data.extend(bytes.fromhex('01 01 00 fe ff 00')) 75 | elif args.method == 'fixed': 76 | # one byte 00, fixed Huffman 77 | data.extend(bytes.fromhex('63 00 00')) 78 | elif args.method == 'dynamic': 79 | # one byte 00, dynamic Huffman 80 | data.extend(bytes.fromhex('05 c1 81 00 00 00 00 00 10 ff d5 10')) 81 | # Adler-32 of one byte 00 82 | data.extend(struct.pack('>I', zlib.adler32(b'\x00'))) 83 | 84 | if args.i: 85 | s = textwrap.fill(', '.join('0x{:02X}'.format(b) for b in data)) 86 | f.write(s.encode('utf-8')) 87 | else: 88 | f.write(data) 89 | 90 | if __name__ == '__main__': 91 | parser = argparse.ArgumentParser(description='zlib test file generator.') 92 | parser.add_argument('-d', '--data', type=str, 93 | choices=['empty', 'byte00'], default='empty', 94 | help='compressed data') 95 | parser.add_argument('-m', '--method', type=str, 96 | choices=['raw', 'fixed', 'dynamic'], default='fixed', 97 | help='compression method') 98 | parser.add_argument('-l', '--level', type=int, 99 | choices=range(0, 4), default=2, 100 | help='compression level') 101 | parser.add_argument('-w', '--window_size', type=int, 102 | choices=range(0, 8), default=7, 103 | help='window size') 104 | parser.add_argument('-p', '--preset_dict', type=int, 105 | help='preset dictionary Adler-32') 106 | parser.add_argument('-i', action='store_true', help='generate include file') 107 | parser.add_argument('outfile', type=argparse.FileType('wb'), help='output file') 108 | args = parser.parse_args() 109 | 110 | write_zlib(args.outfile, args) 111 | -------------------------------------------------------------------------------- /tools/mkzdata.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mkzdata - generate deflate compressed data testcases 3 | * 4 | * Copyright (c) 2014-2019 Joergen Ibsen 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, including without limitation 9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 | * and/or sell copies of the Software, and to permit persons to whom the 11 | * Software is 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 19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 22 | * DEALINGS IN THE SOFTWARE. 23 | */ 24 | 25 | #include "tinf.h" 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | struct lsb_bitwriter { 33 | unsigned char *next_out; 34 | uint32_t tag; 35 | int bitcount; 36 | }; 37 | 38 | static void 39 | lbw_init(struct lsb_bitwriter *lbw, unsigned char *dst) 40 | { 41 | lbw->next_out = dst; 42 | lbw->tag = 0; 43 | lbw->bitcount = 0; 44 | } 45 | 46 | static unsigned char* 47 | lbw_finalize(struct lsb_bitwriter *lbw) 48 | { 49 | /* Write bytes until no bits left in tag */ 50 | while (lbw->bitcount > 0) { 51 | *lbw->next_out++ = lbw->tag; 52 | lbw->tag >>= 8; 53 | lbw->bitcount -= 8; 54 | } 55 | 56 | return lbw->next_out; 57 | } 58 | 59 | static void 60 | lbw_flush(struct lsb_bitwriter *lbw, int num) { 61 | assert(num >= 0 && num <= 32); 62 | 63 | /* Write bytes until at least num bits free */ 64 | while (lbw->bitcount > 32 - num) { 65 | *lbw->next_out++ = lbw->tag; 66 | lbw->tag >>= 8; 67 | lbw->bitcount -= 8; 68 | } 69 | 70 | assert(lbw->bitcount >= 0); 71 | } 72 | 73 | static void 74 | lbw_putbits_no_flush(struct lsb_bitwriter *lbw, uint32_t bits, int num) { 75 | assert(num >= 0 && num <= 32 - lbw->bitcount); 76 | assert((bits & (~0ULL << num)) == 0); 77 | 78 | /* Add bits to tag */ 79 | lbw->tag |= bits << lbw->bitcount; 80 | lbw->bitcount += num; 81 | } 82 | 83 | static void 84 | lbw_putbits(struct lsb_bitwriter *lbw, uint32_t bits, int num) { 85 | lbw_flush(lbw, num); 86 | lbw_putbits_no_flush(lbw, bits, num); 87 | } 88 | 89 | static void 90 | lbw_putbits_rev(struct lsb_bitwriter *lbw, uint32_t bits, int num) { 91 | lbw_flush(lbw, num); 92 | while (num-- > 0) { 93 | lbw_putbits_no_flush(lbw, (bits >> num) & 1, 1); 94 | } 95 | } 96 | 97 | // 256 00 bytes compressed with Z_RLE (one distance code) 98 | void 99 | write_256_rle(struct lsb_bitwriter *lbw) 100 | { 101 | // bfinal 102 | lbw_putbits(lbw, 1, 1); 103 | 104 | // btype 105 | lbw_putbits(lbw, 2, 2); 106 | 107 | // hlit 108 | lbw_putbits(lbw, 28, 5); 109 | 110 | // hdist 111 | lbw_putbits(lbw, 0, 5); 112 | 113 | // hclen 114 | lbw_putbits(lbw, 14, 4); 115 | 116 | lbw_putbits(lbw, 0, 3); // 16 117 | lbw_putbits(lbw, 0, 3); // 17 118 | lbw_putbits(lbw, 1, 3); // 18 119 | lbw_putbits(lbw, 0, 3); // 0 120 | lbw_putbits(lbw, 0, 3); // 8 121 | lbw_putbits(lbw, 0, 3); // 7 122 | lbw_putbits(lbw, 0, 3); // 9 123 | lbw_putbits(lbw, 0, 3); // 6 124 | lbw_putbits(lbw, 0, 3); // 10 125 | lbw_putbits(lbw, 0, 3); // 5 126 | lbw_putbits(lbw, 0, 3); // 11 127 | lbw_putbits(lbw, 0, 3); // 4 128 | lbw_putbits(lbw, 0, 3); // 12 129 | lbw_putbits(lbw, 0, 3); // 3 130 | lbw_putbits(lbw, 0, 3); // 13 131 | lbw_putbits(lbw, 2, 3); // 2 132 | lbw_putbits(lbw, 0, 3); // 14 133 | lbw_putbits(lbw, 2, 3); // 1 134 | 135 | // code lengths for literal/length 136 | lbw_putbits_rev(lbw, 2, 2); // 0 has len 1 137 | 138 | lbw_putbits_rev(lbw, 0, 1); // repeat len 0 for 138 times 139 | lbw_putbits(lbw, 127, 7); 140 | 141 | lbw_putbits_rev(lbw, 0, 1); // repeat len 0 for 117 times 142 | lbw_putbits(lbw, 106, 7); 143 | 144 | lbw_putbits_rev(lbw, 3, 2); // 256 has len 2 145 | 146 | lbw_putbits_rev(lbw, 0, 1); // repeat len 0 for 27 times 147 | lbw_putbits(lbw, 16, 7); 148 | 149 | lbw_putbits_rev(lbw, 3, 2); // 284 has len 2 150 | 151 | // code lengths for distance 152 | lbw_putbits_rev(lbw, 2, 2); // 1 has len 1 153 | 154 | // compressed data 155 | lbw_putbits_rev(lbw, 0, 1); // 00 byte 156 | 157 | lbw_putbits_rev(lbw, 3, 2); // match len 255 158 | lbw_putbits(lbw, 28, 5); 159 | 160 | lbw_putbits_rev(lbw, 0, 1); // distance 1 161 | 162 | // end of block 163 | lbw_putbits_rev(lbw, 2, 2); // 256 = EOB 164 | } 165 | 166 | // 256 00 bytes compressed with Z_HUFFMAN_ONLY (no distance codes) 167 | void 168 | write_256_huffman(struct lsb_bitwriter *lbw) 169 | { 170 | // bfinal 171 | lbw_putbits(lbw, 1, 1); 172 | 173 | // btype 174 | lbw_putbits(lbw, 2, 2); 175 | 176 | // hlit 177 | lbw_putbits(lbw, 0, 5); 178 | 179 | // hdist 180 | lbw_putbits(lbw, 10, 5); 181 | 182 | // hclen 183 | lbw_putbits(lbw, 14, 4); 184 | 185 | lbw_putbits(lbw, 0, 3); // 16 186 | lbw_putbits(lbw, 0, 3); // 17 187 | lbw_putbits(lbw, 1, 3); // 18 188 | lbw_putbits(lbw, 0, 3); // 0 189 | lbw_putbits(lbw, 0, 3); // 8 190 | lbw_putbits(lbw, 0, 3); // 7 191 | lbw_putbits(lbw, 0, 3); // 9 192 | lbw_putbits(lbw, 0, 3); // 6 193 | lbw_putbits(lbw, 0, 3); // 10 194 | lbw_putbits(lbw, 0, 3); // 5 195 | lbw_putbits(lbw, 0, 3); // 11 196 | lbw_putbits(lbw, 0, 3); // 4 197 | lbw_putbits(lbw, 0, 3); // 12 198 | lbw_putbits(lbw, 0, 3); // 3 199 | lbw_putbits(lbw, 0, 3); // 13 200 | lbw_putbits(lbw, 0, 3); // 2 201 | lbw_putbits(lbw, 0, 3); // 14 202 | lbw_putbits(lbw, 1, 3); // 1 203 | 204 | // code lengths for literal/length 205 | lbw_putbits_rev(lbw, 0, 1); // 0 has len 1 206 | 207 | lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 138 times 208 | lbw_putbits(lbw, 127, 7); 209 | 210 | lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 117 times 211 | lbw_putbits(lbw, 106, 7); 212 | 213 | lbw_putbits_rev(lbw, 0, 1); // 256 has len 1 214 | 215 | // code lengths for distance 216 | lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 11 times 217 | lbw_putbits(lbw, 0, 7); 218 | 219 | // compressed data 220 | for (int i = 0; i < 256; ++i) { 221 | lbw_putbits_rev(lbw, 0, 1); // 00 byte 222 | } 223 | 224 | // end of block 225 | lbw_putbits_rev(lbw, 1, 1); // 256 = EOB 226 | } 227 | 228 | // empty with no literal symbols and no distance codes (only 256 has len 1) 229 | void 230 | write_no_lit(struct lsb_bitwriter *lbw) 231 | { 232 | // bfinal 233 | lbw_putbits(lbw, 1, 1); 234 | 235 | // btype 236 | lbw_putbits(lbw, 2, 2); 237 | 238 | // hlit 239 | lbw_putbits(lbw, 0, 5); 240 | 241 | // hdist 242 | lbw_putbits(lbw, 10, 5); 243 | 244 | // hclen 245 | lbw_putbits(lbw, 14, 4); 246 | 247 | lbw_putbits(lbw, 0, 3); // 16 248 | lbw_putbits(lbw, 0, 3); // 17 249 | lbw_putbits(lbw, 1, 3); // 18 250 | lbw_putbits(lbw, 0, 3); // 0 251 | lbw_putbits(lbw, 0, 3); // 8 252 | lbw_putbits(lbw, 0, 3); // 7 253 | lbw_putbits(lbw, 0, 3); // 9 254 | lbw_putbits(lbw, 0, 3); // 6 255 | lbw_putbits(lbw, 0, 3); // 10 256 | lbw_putbits(lbw, 0, 3); // 5 257 | lbw_putbits(lbw, 0, 3); // 11 258 | lbw_putbits(lbw, 0, 3); // 4 259 | lbw_putbits(lbw, 0, 3); // 12 260 | lbw_putbits(lbw, 0, 3); // 3 261 | lbw_putbits(lbw, 0, 3); // 13 262 | lbw_putbits(lbw, 0, 3); // 2 263 | lbw_putbits(lbw, 0, 3); // 14 264 | lbw_putbits(lbw, 1, 3); // 1 265 | 266 | // code lengths for literal/length 267 | lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 138 times 268 | lbw_putbits(lbw, 127, 7); 269 | 270 | lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 118 times 271 | lbw_putbits(lbw, 107, 7); 272 | 273 | lbw_putbits_rev(lbw, 0, 1); // 256 has len 1 274 | 275 | // code lengths for distance 276 | lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 11 times 277 | lbw_putbits(lbw, 0, 7); 278 | 279 | // no compressed data 280 | 281 | // end of block 282 | lbw_putbits_rev(lbw, 0, 1); // 256 = EOB 283 | } 284 | 285 | // copy with max distance 32768 286 | void 287 | write_max_dist(struct lsb_bitwriter *lbw) 288 | { 289 | // bfinal 290 | lbw_putbits(lbw, 1, 1); 291 | 292 | // btype 293 | lbw_putbits(lbw, 2, 2); 294 | 295 | // hlit 296 | lbw_putbits(lbw, 286 - 257, 5); 297 | 298 | // hdist 299 | lbw_putbits(lbw, 30 - 1, 5); 300 | 301 | // hclen 302 | lbw_putbits(lbw, 14, 4); 303 | 304 | lbw_putbits(lbw, 0, 3); // 16 305 | lbw_putbits(lbw, 0, 3); // 17 306 | lbw_putbits(lbw, 2, 3); // 18 307 | lbw_putbits(lbw, 0, 3); // 0 308 | lbw_putbits(lbw, 0, 3); // 8 309 | lbw_putbits(lbw, 0, 3); // 7 310 | lbw_putbits(lbw, 0, 3); // 9 311 | lbw_putbits(lbw, 0, 3); // 6 312 | lbw_putbits(lbw, 0, 3); // 10 313 | lbw_putbits(lbw, 0, 3); // 5 314 | lbw_putbits(lbw, 0, 3); // 11 315 | lbw_putbits(lbw, 2, 3); // 4 316 | lbw_putbits(lbw, 0, 3); // 12 317 | lbw_putbits(lbw, 2, 3); // 3 318 | lbw_putbits(lbw, 0, 3); // 13 319 | lbw_putbits(lbw, 0, 3); // 2 320 | lbw_putbits(lbw, 0, 3); // 14 321 | lbw_putbits(lbw, 2, 3); // 1 322 | 323 | // code lengths for literal/length 324 | lbw_putbits_rev(lbw, 1, 2); // 0 has len 3 325 | lbw_putbits_rev(lbw, 1, 2); // 1 has len 3 326 | lbw_putbits_rev(lbw, 2, 2); // 2 has len 4 327 | 328 | lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 138 times 329 | lbw_putbits(lbw, 127, 7); 330 | 331 | lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 115 times 332 | lbw_putbits(lbw, 104, 7); 333 | 334 | lbw_putbits_rev(lbw, 2, 2); // 256 has len 4 335 | lbw_putbits_rev(lbw, 2, 2); // 257 has len 4 336 | 337 | lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 26 times 338 | lbw_putbits(lbw, 15, 7); 339 | 340 | lbw_putbits_rev(lbw, 2, 2); // 284 has len 4 341 | 342 | lbw_putbits_rev(lbw, 0, 2); // 285 has len 1 343 | 344 | // code lengths for distance 345 | lbw_putbits_rev(lbw, 0, 2); // 0 has len 1 346 | 347 | lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 28 times 348 | lbw_putbits(lbw, 17, 7); 349 | 350 | lbw_putbits_rev(lbw, 0, 2); // 29 has len 1 351 | 352 | // no compressed data 353 | lbw_putbits_rev(lbw, 12, 4); // literal 02 354 | lbw_putbits_rev(lbw, 5, 3); // literal 01 355 | lbw_putbits_rev(lbw, 4, 3); // literal 00 356 | 357 | lbw_putbits_rev(lbw, 15, 4); // 284 = copy len 257 358 | lbw_putbits(lbw, 30, 5); 359 | 360 | lbw_putbits_rev(lbw, 0, 1); // distance 1 361 | 362 | for (int i = 0; i < 126; ++i) { 363 | lbw_putbits_rev(lbw, 0, 1); // 285 = copy len 258 364 | 365 | lbw_putbits_rev(lbw, 0, 1); // distance 1 366 | } 367 | 368 | lbw_putbits_rev(lbw, 14, 4); // 257 = copy len 3 369 | 370 | lbw_putbits_rev(lbw, 1, 1); // distance 32768 371 | lbw_putbits(lbw, 8191, 13); 372 | 373 | // end of block 374 | lbw_putbits_rev(lbw, 13, 4); // 256 = EOB 375 | } 376 | 377 | // Use length 15 codeword 378 | void 379 | write_max_codelen(struct lsb_bitwriter *lbw) 380 | { 381 | // bfinal 382 | lbw_putbits(lbw, 1, 1); 383 | 384 | // btype 385 | lbw_putbits(lbw, 2, 2); 386 | 387 | // hlit 388 | lbw_putbits(lbw, 0, 5); 389 | 390 | // hdist 391 | lbw_putbits(lbw, 10, 5); 392 | 393 | // hclen 394 | lbw_putbits(lbw, 15, 4); 395 | 396 | lbw_putbits(lbw, 0, 3); // 16 397 | lbw_putbits(lbw, 0, 3); // 17 398 | lbw_putbits(lbw, 4, 3); // 18 399 | lbw_putbits(lbw, 0, 3); // 0 400 | lbw_putbits(lbw, 4, 3); // 8 401 | lbw_putbits(lbw, 4, 3); // 7 402 | lbw_putbits(lbw, 4, 3); // 9 403 | lbw_putbits(lbw, 4, 3); // 6 404 | lbw_putbits(lbw, 4, 3); // 10 405 | lbw_putbits(lbw, 4, 3); // 5 406 | lbw_putbits(lbw, 4, 3); // 11 407 | lbw_putbits(lbw, 4, 3); // 4 408 | lbw_putbits(lbw, 4, 3); // 12 409 | lbw_putbits(lbw, 4, 3); // 3 410 | lbw_putbits(lbw, 4, 3); // 13 411 | lbw_putbits(lbw, 4, 3); // 2 412 | lbw_putbits(lbw, 4, 3); // 14 413 | lbw_putbits(lbw, 4, 3); // 1 414 | lbw_putbits(lbw, 4, 3); // 15 415 | 416 | // code lengths for literal/length 417 | lbw_putbits_rev(lbw, 0, 4); // 0 has len 1 418 | lbw_putbits_rev(lbw, 1, 4); // 1 has len 2 419 | lbw_putbits_rev(lbw, 2, 4); // 2 has len 3 420 | lbw_putbits_rev(lbw, 3, 4); // 3 has len 4 421 | lbw_putbits_rev(lbw, 4, 4); // 4 has len 5 422 | lbw_putbits_rev(lbw, 5, 4); // 5 has len 6 423 | lbw_putbits_rev(lbw, 6, 4); // 6 has len 7 424 | lbw_putbits_rev(lbw, 7, 4); // 7 has len 8 425 | lbw_putbits_rev(lbw, 8, 4); // 8 has len 9 426 | lbw_putbits_rev(lbw, 9, 4); // 9 has len 10 427 | lbw_putbits_rev(lbw, 10, 4); // 10 has len 11 428 | lbw_putbits_rev(lbw, 11, 4); // 11 has len 12 429 | lbw_putbits_rev(lbw, 12, 4); // 12 has len 13 430 | lbw_putbits_rev(lbw, 13, 4); // 13 has len 14 431 | lbw_putbits_rev(lbw, 14, 4); // 14 has len 15 432 | 433 | lbw_putbits_rev(lbw, 15, 4); // repeat len 0 for 138 times 434 | lbw_putbits(lbw, 127, 7); 435 | 436 | lbw_putbits_rev(lbw, 15, 4); // repeat len 0 for 103 times 437 | lbw_putbits(lbw, 92, 7); 438 | 439 | lbw_putbits_rev(lbw, 14, 4); // 256 has len 15 440 | 441 | // code lengths for distance 442 | lbw_putbits_rev(lbw, 15, 4); // repeat len 0 for 11 times 443 | lbw_putbits(lbw, 0, 7); 444 | 445 | // compressed data 446 | lbw_putbits_rev(lbw, 0, 1); // literal 0 447 | lbw_putbits_rev(lbw, 2, 2); // literal 1 448 | lbw_putbits_rev(lbw, 6, 3); // literal 2 449 | lbw_putbits_rev(lbw, 14, 4); // literal 3 450 | lbw_putbits_rev(lbw, 30, 5); // literal 4 451 | lbw_putbits_rev(lbw, 62, 6); // literal 5 452 | lbw_putbits_rev(lbw, 126, 7); // literal 6 453 | lbw_putbits_rev(lbw, 254, 8); // literal 7 454 | lbw_putbits_rev(lbw, 510, 9); // literal 8 455 | lbw_putbits_rev(lbw, 1022, 10); // literal 9 456 | lbw_putbits_rev(lbw, 2046, 11); // literal 10 457 | lbw_putbits_rev(lbw, 4094, 12); // literal 11 458 | lbw_putbits_rev(lbw, 8190, 13); // literal 12 459 | lbw_putbits_rev(lbw, 16382, 14); // literal 13 460 | lbw_putbits_rev(lbw, 32766, 15); // literal 14 461 | 462 | // end of block 463 | lbw_putbits_rev(lbw, 32767, 15); // 256 = EOB 464 | } 465 | 466 | unsigned char buffer[64 * 1024]; 467 | 468 | int 469 | main(int argc, char *argv[]) 470 | { 471 | if (argc > 2) { 472 | fputs("syntax: mkzdata FILE\n", stderr); 473 | return EXIT_FAILURE; 474 | } 475 | 476 | const unsigned char org_data[1024] = {0}; 477 | 478 | unsigned char data[4096]; 479 | 480 | struct lsb_bitwriter lbw; 481 | 482 | lbw_init(&lbw, &data[0]); 483 | 484 | write_max_codelen(&lbw); 485 | 486 | uint32_t size = lbw_finalize(&lbw) - &data[0]; 487 | 488 | for (int i = 0; i < size; ++i) { 489 | if (i > 0) { 490 | fputs(", ", stdout); 491 | } 492 | printf("0x%02X", data[i]); 493 | } 494 | printf("\n"); 495 | 496 | if (argc > 1) { 497 | FILE *fout = fopen(argv[1], "wb"); 498 | 499 | const unsigned char gzip_header[10] = { 500 | 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B 501 | }; 502 | 503 | fwrite(gzip_header, 1, sizeof(gzip_header), fout); 504 | 505 | fwrite(data, 1, size, fout); 506 | 507 | unsigned int dsize = sizeof(buffer); 508 | int res = tinf_uncompress(buffer, &dsize, data, size); 509 | 510 | if (res != TINF_OK) { 511 | fputs("mkzdata: decompression error\n", stderr); 512 | return EXIT_FAILURE; 513 | } 514 | 515 | // Note: only works on little-endian 516 | uint32_t crc = tinf_crc32(&buffer[0], dsize); 517 | fwrite(&crc, sizeof(crc), 1, fout); 518 | uint32_t org_size = dsize; 519 | fwrite(&org_size, sizeof(org_size), 1, fout); 520 | 521 | fclose(fout); 522 | } 523 | 524 | return 0; 525 | } 526 | --------------------------------------------------------------------------------