Full Code of jibsen/tinf for AI

master 57ffa1f1d5e3 cached
18 files
153.3 KB
44.6k tokens
136 symbols
1 requests
Download .txt
Repository: jibsen/tinf
Branch: master
Commit: 57ffa1f1d5e3
Files: 18
Total size: 153.3 KB

Directory structure:
gitextract_cflkwvkt/

├── .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

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
insert_final_newline = true
trim_trailing_whitespace = true

[Makefile*]
indent_style = tab

[*.{c,h}]
indent_style = tab
indent_size = 8

[*.yml]
indent_style = space
indent_size = 2


================================================
FILE: .github/workflows/tinf-ci-workflow.yaml
================================================
name: tinf CI

on: [push, pull_request]

jobs:
  windows:
    name: Windows ${{ matrix.config.name }}
    runs-on: windows-latest

    strategy:
      matrix:
        config:
          - name: MSVC x64
            generator: Visual Studio 16 2019
            cmake-flags: -A x64

    steps:
      - uses: actions/checkout@v2

      - name: Configure
        run: cmake -G "${{ matrix.config.generator }}" ${{ matrix.config.cmake-flags }} -B build

      - name: Build
        run: cd build && cmake --build . --config Debug

      - name: Test
        run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0 -C Debug

  linux:
    name: Linux ${{ matrix.config.name }}
    runs-on: ubuntu-latest
    env:
      CC: ${{ matrix.config.cc }}

    strategy:
      matrix:
        config:
          - name: Clang UBSan
            cc: clang
            cmake-flags: -DCMAKE_C_FLAGS_DEBUG='-g -fsanitize=undefined'

          - name: Clang ASan
            cc: clang
            cmake-flags: -DCMAKE_C_FLAGS_DEBUG='-O1 -g -fsanitize=address -fno-omit-frame-pointer'

    steps:
      - uses: actions/checkout@v2

      - name: Configure
        run: cmake ${{ matrix.config.cmake-flags }} -DCMAKE_BUILD_TYPE=Debug -B build

      - name: Build
        run: cd build && make VERBOSE=1

      - name: Test
        run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0

  coverage:
    name: Linux Coverage
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Configure
        run: cmake -DCMAKE_C_FLAGS_DEBUG='-g -O0 --coverage' -DCMAKE_BUILD_TYPE=Debug -B build

      - name: Build
        run: cd build && make VERBOSE=1

      - name: Test
        run: cd build && ctest -V --output-on-failure --interactive-debug-mode 0

      - name: Generate coverage
        run: cd build && gcov -abcfu CMakeFiles/tinf.dir/src/*.c.gcno -o CMakeFiles/tinf.dir/src

      - name: Upload coverage to Codecov
        uses: codecov/codecov-action@v2
        with:
          directory: ./build/


================================================
FILE: .gitignore
================================================
*.o
*.obj

*.a
*.lib

*.so
*.so.*
*.dll

*.exe

/build/
/doc/


================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.16)

project(tinf C)

include(CheckCCompilerFlag)
include(CTest)

# Check if tinf is the top-level project (standalone), or a subproject
set(_tinf_standalone FALSE)
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
  set(_tinf_standalone TRUE)
endif()

# TINF_BUILD_TESTING controls if tinf adds testing support
#
# When built standalone, it defaults to the value of BUILD_TESTING if set.
# An optional prefix for the test names can be set with TINF_TEST_PREFIX.
set(_tinf_testing_default ON)
if(_tinf_standalone)
  if(DEFINED BUILD_TESTING)
    set(_tinf_testing_default ${BUILD_TESTING})
  endif()
else()
  set(_tinf_testing_default OFF)
endif()
option(TINF_BUILD_TESTING "Add testing support" ${_tinf_testing_default})
unset(_tinf_testing_default)

mark_as_advanced(TINF_TEST_PREFIX)

# Take a list of compiler flags and add those which the compiler accepts to
# the COMPILE_OPTIONS directory property
function(add_valid_c_compile_options)
  foreach(flag IN LISTS ARGN)
    string(REGEX REPLACE "[^a-zA-Z0-9]+" "_" flag_var "CFLAG_${flag}")
    check_c_compiler_flag("${flag}" ${flag_var})
    if(${flag_var})
      add_compile_options("${flag}")
    endif()
  endforeach()
endfunction()

if(MSVC)
  add_valid_c_compile_options(/W3)
else()
  add_valid_c_compile_options(-Wall -Wextra -pedantic)
endif()

#
# tinf
#
add_library(tinf
  src/adler32.c
  src/crc32.c
  src/tinfgzip.c
  src/tinflate.c
  src/tinfzlib.c
  src/tinf.h
)
target_include_directories(tinf PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/src>)

#
# tgunzip
#
add_executable(tgunzip examples/tgunzip/tgunzip.c)
target_link_libraries(tgunzip PRIVATE tinf)
if(MSVC)
  target_compile_definitions(tgunzip PRIVATE _CRT_SECURE_NO_WARNINGS)
endif()

#
# Tests
#
if(TINF_BUILD_TESTING)
  add_executable(test_tinf test/test_tinf.c)
  target_link_libraries(test_tinf PRIVATE tinf)
  if(MSVC)
    target_compile_definitions(test_tinf PRIVATE _CRT_SECURE_NO_WARNINGS)
  endif()

  add_test("${TINF_TEST_PREFIX}tinf" test_tinf)
endif()


================================================
FILE: LICENSE
================================================
The zlib License (Zlib)

Copyright (c) 2003-2019 Joergen Ibsen

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:

  1. The origin of this software must not be misrepresented; you must
     not claim that you wrote the original software. If you use this
     software in a product, an acknowledgment in the product
     documentation would be appreciated but is not required.

  2. Altered source versions must be plainly marked as such, and must
     not be misrepresented as being the original software.

  3. This notice may not be removed or altered from any source
     distribution.


================================================
FILE: README.md
================================================

tinf - tiny inflate library
===========================

Version 1.2.1

Copyright (c) 2003-2019 Joergen Ibsen

<http://www.ibsensoftware.com/>

[![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)

About
-----

tinf is a small library implementing the decompression algorithm for the
[deflate][wpdeflate] compressed data format (called 'inflate'). Deflate
compression is used in e.g. zlib, gzip, zip, and png.

I wrote it because I needed a small in-memory zlib decompressor for a self-
extracting archive, and the zlib library added 15k to my program. The tinf
code added only 2k.

Naturally the size difference is insignificant in most cases. Also, the
zlib library has many more features, is well-tested, and mostly faster.
But if you have a project that calls for a small and simple deflate
decompressor, give it a try :-)

[wpdeflate]: https://en.wikipedia.org/wiki/DEFLATE


Usage
-----

The include file `src/tinf.h` contains documentation in the form of
[doxygen][] comments.

Wrappers for decompressing zlib and gzip data in memory are supplied.

tgunzip, an example command-line gzip decompressor in C, is included.

tinf uses [CMake][] to generate build systems. To create one for the tools on
your platform, and build tinf, use something along the lines of:

~~~sh
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release
~~~

You can also compile the source files and link them into your project. CMake
just provides an easy way to build and test across various platforms and
toolsets.

[doxygen]: http://www.doxygen.org/
[CMake]: http://www.cmake.org/


Notes
-----

tinf requires int to be at least 32-bit.

The inflate algorithm and data format are from 'DEFLATE Compressed Data
Format Specification version 1.3' ([RFC 1951][deflate]).

The zlib data format is from 'ZLIB Compressed Data Format Specification
version 3.3' ([RFC 1950][zlib]).

The gzip data format is from 'GZIP file format specification version 4.3'
([RFC 1952][gzip]).

The original version of tinf assumed it was given valid compressed data, and
that there was sufficient space for the decompressed data. If code size is
of the utmost importance, and you are absolutely sure you can trust the
compressed data, you may want to check out [tinf 1.1.0][tinf110] (last
release without security checks).

Ideas for future versions:

  - Memory for the `tinf_data` object should be passed, to avoid using more
    than 1k of stack space
  - Wrappers for unpacking zip archives and png images
  - Blocking of some sort, so everything does not have to be in memory
  - Optional table-based Huffman decoder
  - Small compressor using fixed Huffman trees

[deflate]: http://www.rfc-editor.org/rfc/rfc1951.txt
[zlib]: http://www.rfc-editor.org/rfc/rfc1950.txt
[gzip]: http://www.rfc-editor.org/rfc/rfc1952.txt
[tinf110]: https://github.com/jibsen/tinf/releases/tag/v1.1.0


Related Projects
----------------

  - [puff](https://github.com/madler/zlib) (in the contrib folder of zlib)
  - [tinfl](https://github.com/richgel999/miniz) (part of miniz)
  - [uzlib](https://github.com/pfalcon/uzlib)
  - [gdunzip](https://github.com/jellehermsen/gdunzip) (GDScript)
  - [TinyDeflate](https://github.com/bisqwit/TinyDeflate) (C++)
  - [tiny-inflate](https://github.com/foliojs/tiny-inflate) (JavaScript)
  - [tinflate](http://achurch.org/tinflate.c) (unrelated to this project)
  - The [Wikipedia page for deflate](https://en.wikipedia.org/wiki/DEFLATE)
    has a list of implementations


License
-------

This projected is licensed under the [zlib License](LICENSE) (Zlib).


================================================
FILE: examples/tgunzip/tgunzip.c
================================================
/*
 * tgunzip - gzip decompressor example
 *
 * Copyright (c) 2003-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>

#include "tinf.h"

static unsigned int read_le32(const unsigned char *p)
{
	return ((unsigned int) p[0])
	     | ((unsigned int) p[1] << 8)
	     | ((unsigned int) p[2] << 16)
	     | ((unsigned int) p[3] << 24);
}

static void printf_error(const char *fmt, ...)
{
	va_list arg;

	fputs("tgunzip: ", stderr);

	va_start(arg, fmt);
	vfprintf(stderr, fmt, arg);
	va_end(arg);

	fputs("\n", stderr);
}

int main(int argc, char *argv[])
{
	FILE *fin = NULL;
	FILE *fout = NULL;
	unsigned char *source = NULL;
	unsigned char *dest = NULL;
	unsigned int len, dlen, outlen;
	int retval = EXIT_FAILURE;
	int res;

	printf("tgunzip " TINF_VER_STRING " - example from the tiny inflate library (www.ibsensoftware.com)\n\n");

	if (argc != 3) {
		fputs("usage: tgunzip INFILE OUTFILE\n\n"
		      "Both input and output are kept in memory, so do not use this on huge files.\n", stderr);
		return EXIT_FAILURE;
	}

	tinf_init();

	/* -- Open files -- */

	if ((fin = fopen(argv[1], "rb")) == NULL) {
		printf_error("unable to open input file '%s'", argv[1]);
		goto out;
	}

	if ((fout = fopen(argv[2], "wb")) == NULL) {
		printf_error("unable to create output file '%s'", argv[2]);
		goto out;
	}

	/* -- Read source -- */

	fseek(fin, 0, SEEK_END);

	len = ftell(fin);

	fseek(fin, 0, SEEK_SET);

	if (len < 18) {
		printf_error("input too small to be gzip");
		goto out;
	}

	source = (unsigned char *) malloc(len);

	if (source == NULL) {
		printf_error("not enough memory");
		goto out;
	}

	if (fread(source, 1, len, fin) != len) {
		printf_error("error reading input file");
		goto out;
	}

	/* -- Get decompressed length -- */

	dlen = read_le32(&source[len - 4]);

	dest = (unsigned char *) malloc(dlen ? dlen : 1);

	if (dest == NULL) {
		printf_error("not enough memory");
		goto out;
	}

	/* -- Decompress data -- */

	outlen = dlen;

	res = tinf_gzip_uncompress(dest, &outlen, source, len);

	if ((res != TINF_OK) || (outlen != dlen)) {
		printf_error("decompression failed");
		goto out;
	}

	printf("decompressed %u bytes\n", outlen);

	/* -- Write output -- */

	fwrite(dest, 1, outlen, fout);

	retval = EXIT_SUCCESS;

out:
	if (fin != NULL) {
		fclose(fin);
	}

	if (fout != NULL) {
		fclose(fout);
	}

	if (source != NULL) {
		free(source);
	}

	if (dest != NULL) {
		free(dest);
	}

	return retval;
}


================================================
FILE: src/adler32.c
================================================
/*
 * Adler-32 checksum
 *
 * Copyright (c) 2003-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

/*
 * Adler-32 algorithm taken from the zlib source, which is
 * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
 */

#include "tinf.h"

#define A32_BASE 65521
#define A32_NMAX 5552

unsigned int tinf_adler32(const void *data, unsigned int length)
{
	const unsigned char *buf = (const unsigned char *) data;

	unsigned int s1 = 1;
	unsigned int s2 = 0;

	while (length > 0) {
		int k = length < A32_NMAX ? length : A32_NMAX;
		int i;

		for (i = k / 16; i; --i, buf += 16) {
			s1 += buf[0];
			s2 += s1;
			s1 += buf[1];
			s2 += s1;
			s1 += buf[2];
			s2 += s1;
			s1 += buf[3];
			s2 += s1;
			s1 += buf[4];
			s2 += s1;
			s1 += buf[5];
			s2 += s1;
			s1 += buf[6];
			s2 += s1;
			s1 += buf[7];
			s2 += s1;

			s1 += buf[8];
			s2 += s1;
			s1 += buf[9];
			s2 += s1;
			s1 += buf[10];
			s2 += s1;
			s1 += buf[11];
			s2 += s1;
			s1 += buf[12];
			s2 += s1;
			s1 += buf[13];
			s2 += s1;
			s1 += buf[14];
			s2 += s1;
			s1 += buf[15];
			s2 += s1;
		}

		for (i = k % 16; i; --i) {
			s1 += *buf++;
			s2 += s1;
		}

		s1 %= A32_BASE;
		s2 %= A32_BASE;

		length -= k;
	}

	return (s2 << 16) | s1;
}


================================================
FILE: src/crc32.c
================================================
/*
 * CRC32 checksum
 *
 * Copyright (c) 1998-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

/*
 * CRC32 algorithm taken from the zlib source, which is
 * Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler
 */

#include "tinf.h"

static const unsigned int tinf_crc32tab[16] = {
	0x00000000, 0x1DB71064, 0x3B6E20C8, 0x26D930AC, 0x76DC4190,
	0x6B6B51F4, 0x4DB26158, 0x5005713C, 0xEDB88320, 0xF00F9344,
	0xD6D6A3E8, 0xCB61B38C, 0x9B64C2B0, 0x86D3D2D4, 0xA00AE278,
	0xBDBDF21C
};

unsigned int tinf_crc32(const void *data, unsigned int length)
{
	const unsigned char *buf = (const unsigned char *) data;
	unsigned int crc = 0xFFFFFFFF;
	unsigned int i;

	if (length == 0) {
		return 0;
	}

	for (i = 0; i < length; ++i) {
		crc ^= buf[i];
		crc = tinf_crc32tab[crc & 0x0F] ^ (crc >> 4);
		crc = tinf_crc32tab[crc & 0x0F] ^ (crc >> 4);
	}

	return crc ^ 0xFFFFFFFF;
}


================================================
FILE: src/tinf.h
================================================
/*
 * tinf - tiny inflate library (inflate, gzip, zlib)
 *
 * Copyright (c) 2003-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

#ifndef TINF_H_INCLUDED
#define TINF_H_INCLUDED

#ifdef __cplusplus
extern "C" {
#endif

#define TINF_VER_MAJOR 1        /**< Major version number */
#define TINF_VER_MINOR 2        /**< Minor version number */
#define TINF_VER_PATCH 1        /**< Patch version number */
#define TINF_VER_STRING "1.2.1" /**< Version number as a string */

#ifndef TINFCC
#  ifdef __WATCOMC__
#    define TINFCC __cdecl
#  else
#    define TINFCC
#  endif
#endif

/**
 * Status codes returned.
 *
 * @see tinf_uncompress, tinf_gzip_uncompress, tinf_zlib_uncompress
 */
typedef enum {
	TINF_OK         = 0,  /**< Success */
	TINF_DATA_ERROR = -3, /**< Input error */
	TINF_BUF_ERROR  = -5  /**< Not enough room for output */
} tinf_error_code;

/**
 * Initialize global data used by tinf.
 *
 * @deprecated No longer required, may be removed in a future version.
 */
void TINFCC tinf_init(void);

/**
 * Decompress `sourceLen` bytes of deflate data from `source` to `dest`.
 *
 * The variable `destLen` points to must contain the size of `dest` on entry,
 * and will be set to the size of the decompressed data on success.
 *
 * Reads at most `sourceLen` bytes from `source`.
 * Writes at most `*destLen` bytes to `dest`.
 *
 * @param dest pointer to where to place decompressed data
 * @param destLen pointer to variable containing size of `dest`
 * @param source pointer to compressed data
 * @param sourceLen size of compressed data
 * @return `TINF_OK` on success, error code on error
 */
int TINFCC tinf_uncompress(void *dest, unsigned int *destLen,
                           const void *source, unsigned int sourceLen);

/**
 * Decompress `sourceLen` bytes of gzip data from `source` to `dest`.
 *
 * The variable `destLen` points to must contain the size of `dest` on entry,
 * and will be set to the size of the decompressed data on success.
 *
 * Reads at most `sourceLen` bytes from `source`.
 * Writes at most `*destLen` bytes to `dest`.
 *
 * @param dest pointer to where to place decompressed data
 * @param destLen pointer to variable containing size of `dest`
 * @param source pointer to compressed data
 * @param sourceLen size of compressed data
 * @return `TINF_OK` on success, error code on error
 */
int TINFCC tinf_gzip_uncompress(void *dest, unsigned int *destLen,
                                const void *source, unsigned int sourceLen);

/**
 * Decompress `sourceLen` bytes of zlib data from `source` to `dest`.
 *
 * The variable `destLen` points to must contain the size of `dest` on entry,
 * and will be set to the size of the decompressed data on success.
 *
 * Reads at most `sourceLen` bytes from `source`.
 * Writes at most `*destLen` bytes to `dest`.
 *
 * @param dest pointer to where to place decompressed data
 * @param destLen pointer to variable containing size of `dest`
 * @param source pointer to compressed data
 * @param sourceLen size of compressed data
 * @return `TINF_OK` on success, error code on error
 */
int TINFCC tinf_zlib_uncompress(void *dest, unsigned int *destLen,
                                const void *source, unsigned int sourceLen);

/**
 * Compute Adler-32 checksum of `length` bytes starting at `data`.
 *
 * @param data pointer to data
 * @param length size of data
 * @return Adler-32 checksum
 */
unsigned int TINFCC tinf_adler32(const void *data, unsigned int length);

/**
 * Compute CRC32 checksum of `length` bytes starting at `data`.
 *
 * @param data pointer to data
 * @param length size of data
 * @return CRC32 checksum
 */
unsigned int TINFCC tinf_crc32(const void *data, unsigned int length);

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* TINF_H_INCLUDED */


================================================
FILE: src/tinfgzip.c
================================================
/*
 * tinfgzip - tiny gzip decompressor
 *
 * Copyright (c) 2003-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

#include "tinf.h"

typedef enum {
	FTEXT    = 1,
	FHCRC    = 2,
	FEXTRA   = 4,
	FNAME    = 8,
	FCOMMENT = 16
} tinf_gzip_flag;

static unsigned int read_le16(const unsigned char *p)
{
	return ((unsigned int) p[0])
	     | ((unsigned int) p[1] << 8);
}

static unsigned int read_le32(const unsigned char *p)
{
	return ((unsigned int) p[0])
	     | ((unsigned int) p[1] << 8)
	     | ((unsigned int) p[2] << 16)
	     | ((unsigned int) p[3] << 24);
}

int tinf_gzip_uncompress(void *dest, unsigned int *destLen,
                         const void *source, unsigned int sourceLen)
{
	const unsigned char *src = (const unsigned char *) source;
	unsigned char *dst = (unsigned char *) dest;
	const unsigned char *start;
	unsigned int dlen, crc32;
	int res;
	unsigned char flg;

	/* -- Check header -- */

	/* Check room for at least 10 byte header and 8 byte trailer */
	if (sourceLen < 18) {
		return TINF_DATA_ERROR;
	}

	/* Check id bytes */
	if (src[0] != 0x1F || src[1] != 0x8B) {
		return TINF_DATA_ERROR;
	}

	/* Check method is deflate */
	if (src[2] != 8) {
		return TINF_DATA_ERROR;
	}

	/* Get flag byte */
	flg = src[3];

	/* Check that reserved bits are zero */
	if (flg & 0xE0) {
		return TINF_DATA_ERROR;
	}

	/* -- Find start of compressed data -- */

	/* Skip base header of 10 bytes */
	start = src + 10;

	/* Skip extra data if present */
	if (flg & FEXTRA) {
		unsigned int xlen = read_le16(start);

		if (xlen > sourceLen - 12) {
			return TINF_DATA_ERROR;
		}

		start += xlen + 2;
	}

	/* Skip file name if present */
	if (flg & FNAME) {
		do {
			if (start - src >= sourceLen) {
				return TINF_DATA_ERROR;
			}
		} while (*start++);
	}

	/* Skip file comment if present */
	if (flg & FCOMMENT) {
		do {
			if (start - src >= sourceLen) {
				return TINF_DATA_ERROR;
			}
		} while (*start++);
	}

	/* Check header crc if present */
	if (flg & FHCRC) {
		unsigned int hcrc;

		if (start - src > sourceLen - 2) {
			return TINF_DATA_ERROR;
		}

		hcrc = read_le16(start);

		if (hcrc != (tinf_crc32(src, start - src) & 0x0000FFFF)) {
			return TINF_DATA_ERROR;
		}

		start += 2;
	}

	/* -- Get decompressed length -- */

	dlen = read_le32(&src[sourceLen - 4]);

	if (dlen > *destLen) {
		return TINF_BUF_ERROR;
	}

	/* -- Get CRC32 checksum of original data -- */

	crc32 = read_le32(&src[sourceLen - 8]);

	/* -- Decompress data -- */

	if ((src + sourceLen) - start < 8) {
		return TINF_DATA_ERROR;
	}

	res = tinf_uncompress(dst, destLen, start,
	                      (src + sourceLen) - start - 8);

	if (res != TINF_OK) {
		return TINF_DATA_ERROR;
	}

	if (*destLen != dlen) {
		return TINF_DATA_ERROR;
	}

	/* -- Check CRC32 checksum -- */

	if (crc32 != tinf_crc32(dst, dlen)) {
		return TINF_DATA_ERROR;
	}

	return TINF_OK;
}


================================================
FILE: src/tinflate.c
================================================
/*
 * tinflate - tiny inflate
 *
 * Copyright (c) 2003-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

#include "tinf.h"

#include <assert.h>
#include <limits.h>

#if defined(UINT_MAX) && (UINT_MAX) < 0xFFFFFFFFUL
#  error "tinf requires unsigned int to be at least 32-bit"
#endif

/* -- Internal data structures -- */

struct tinf_tree {
	unsigned short counts[16]; /* Number of codes with a given length */
	unsigned short symbols[288]; /* Symbols sorted by code */
	int max_sym;
};

struct tinf_data {
	const unsigned char *source;
	const unsigned char *source_end;
	unsigned int tag;
	int bitcount;
	int overflow;

	unsigned char *dest_start;
	unsigned char *dest;
	unsigned char *dest_end;

	struct tinf_tree ltree; /* Literal/length tree */
	struct tinf_tree dtree; /* Distance tree */
};

/* -- Utility functions -- */

static unsigned int read_le16(const unsigned char *p)
{
	return ((unsigned int) p[0])
	     | ((unsigned int) p[1] << 8);
}

/* Build fixed Huffman trees */
static void tinf_build_fixed_trees(struct tinf_tree *lt, struct tinf_tree *dt)
{
	int i;

	/* Build fixed literal/length tree */
	for (i = 0; i < 16; ++i) {
		lt->counts[i] = 0;
	}

	lt->counts[7] = 24;
	lt->counts[8] = 152;
	lt->counts[9] = 112;

	for (i = 0; i < 24; ++i) {
		lt->symbols[i] = 256 + i;
	}
	for (i = 0; i < 144; ++i) {
		lt->symbols[24 + i] = i;
	}
	for (i = 0; i < 8; ++i) {
		lt->symbols[24 + 144 + i] = 280 + i;
	}
	for (i = 0; i < 112; ++i) {
		lt->symbols[24 + 144 + 8 + i] = 144 + i;
	}

	lt->max_sym = 285;

	/* Build fixed distance tree */
	for (i = 0; i < 16; ++i) {
		dt->counts[i] = 0;
	}

	dt->counts[5] = 32;

	for (i = 0; i < 32; ++i) {
		dt->symbols[i] = i;
	}

	dt->max_sym = 29;
}

/* Given an array of code lengths, build a tree */
static int tinf_build_tree(struct tinf_tree *t, const unsigned char *lengths,
                           unsigned int num)
{
	unsigned short offs[16];
	unsigned int i, num_codes, available;

	assert(num <= 288);

	for (i = 0; i < 16; ++i) {
		t->counts[i] = 0;
	}

	t->max_sym = -1;

	/* Count number of codes for each non-zero length */
	for (i = 0; i < num; ++i) {
		assert(lengths[i] <= 15);

		if (lengths[i]) {
			t->max_sym = i;
			t->counts[lengths[i]]++;
		}
	}

	/* Compute offset table for distribution sort */
	for (available = 1, num_codes = 0, i = 0; i < 16; ++i) {
		unsigned int used = t->counts[i];

		/* Check length contains no more codes than available */
		if (used > available) {
			return TINF_DATA_ERROR;
		}
		available = 2 * (available - used);

		offs[i] = num_codes;
		num_codes += used;
	}

	/*
	 * Check all codes were used, or for the special case of only one
	 * code that it has length 1
	 */
	if ((num_codes > 1 && available > 0)
	 || (num_codes == 1 && t->counts[1] != 1)) {
		return TINF_DATA_ERROR;
	}

	/* Fill in symbols sorted by code */
	for (i = 0; i < num; ++i) {
		if (lengths[i]) {
			t->symbols[offs[lengths[i]]++] = i;
		}
	}

	/*
	 * For the special case of only one code (which will be 0) add a
	 * code 1 which results in a symbol that is too large
	 */
	if (num_codes == 1) {
		t->counts[1] = 2;
		t->symbols[1] = t->max_sym + 1;
	}

	return TINF_OK;
}

/* -- Decode functions -- */

static void tinf_refill(struct tinf_data *d, int num)
{
	assert(num >= 0 && num <= 32);

	/* Read bytes until at least num bits available */
	while (d->bitcount < num) {
		if (d->source != d->source_end) {
			d->tag |= (unsigned int) *d->source++ << d->bitcount;
		}
		else {
			d->overflow = 1;
		}
		d->bitcount += 8;
	}

	assert(d->bitcount <= 32);
}

static unsigned int tinf_getbits_no_refill(struct tinf_data *d, int num)
{
	unsigned int bits;

	assert(num >= 0 && num <= d->bitcount);

	/* Get bits from tag */
	bits = d->tag & ((1UL << num) - 1);

	/* Remove bits from tag */
	d->tag >>= num;
	d->bitcount -= num;

	return bits;
}

/* Get num bits from source stream */
static unsigned int tinf_getbits(struct tinf_data *d, int num)
{
	tinf_refill(d, num);
	return tinf_getbits_no_refill(d, num);
}

/* Read a num bit value from stream and add base */
static unsigned int tinf_getbits_base(struct tinf_data *d, int num, int base)
{
	return base + (num ? tinf_getbits(d, num) : 0);
}

/* Given a data stream and a tree, decode a symbol */
static int tinf_decode_symbol(struct tinf_data *d, const struct tinf_tree *t)
{
	int base = 0, offs = 0;
	int len;

	/*
	 * Get more bits while code index is above number of codes
	 *
	 * Rather than the actual code, we are computing the position of the
	 * code in the sorted order of codes, which is the index of the
	 * corresponding symbol.
	 *
	 * Conceptually, for each code length (level in the tree), there are
	 * counts[len] leaves on the left and internal nodes on the right.
	 * The index we have decoded so far is base + offs, and if that
	 * falls within the leaves we are done. Otherwise we adjust the range
	 * of offs and add one more bit to it.
	 */
	for (len = 1; ; ++len) {
		offs = 2 * offs + tinf_getbits(d, 1);

		assert(len <= 15);

		if (offs < t->counts[len]) {
			break;
		}

		base += t->counts[len];
		offs -= t->counts[len];
	}

	assert(base + offs >= 0 && base + offs < 288);

	return t->symbols[base + offs];
}

/* Given a data stream, decode dynamic trees from it */
static int tinf_decode_trees(struct tinf_data *d, struct tinf_tree *lt,
                             struct tinf_tree *dt)
{
	unsigned char lengths[288 + 32];

	/* Special ordering of code length codes */
	static const unsigned char clcidx[19] = {
		16, 17, 18, 0,  8, 7,  9, 6, 10, 5,
		11,  4, 12, 3, 13, 2, 14, 1, 15
	};

	unsigned int hlit, hdist, hclen;
	unsigned int i, num, length;
	int res;

	/* Get 5 bits HLIT (257-286) */
	hlit = tinf_getbits_base(d, 5, 257);

	/* Get 5 bits HDIST (1-32) */
	hdist = tinf_getbits_base(d, 5, 1);

	/* Get 4 bits HCLEN (4-19) */
	hclen = tinf_getbits_base(d, 4, 4);

	/*
	 * The RFC limits the range of HLIT to 286, but lists HDIST as range
	 * 1-32, even though distance codes 30 and 31 have no meaning. While
	 * we could allow the full range of HLIT and HDIST to make it possible
	 * to decode the fixed trees with this function, we consider it an
	 * error here.
	 *
	 * See also: https://github.com/madler/zlib/issues/82
	 */
	if (hlit > 286 || hdist > 30) {
		return TINF_DATA_ERROR;
	}

	for (i = 0; i < 19; ++i) {
		lengths[i] = 0;
	}

	/* Read code lengths for code length alphabet */
	for (i = 0; i < hclen; ++i) {
		/* Get 3 bits code length (0-7) */
		unsigned int clen = tinf_getbits(d, 3);

		lengths[clcidx[i]] = clen;
	}

	/* Build code length tree (in literal/length tree to save space) */
	res = tinf_build_tree(lt, lengths, 19);

	if (res != TINF_OK) {
		return res;
	}

	/* Check code length tree is not empty */
	if (lt->max_sym == -1) {
		return TINF_DATA_ERROR;
	}

	/* Decode code lengths for the dynamic trees */
	for (num = 0; num < hlit + hdist; ) {
		int sym = tinf_decode_symbol(d, lt);

		if (sym > lt->max_sym) {
			return TINF_DATA_ERROR;
		}

		switch (sym) {
		case 16:
			/* Copy previous code length 3-6 times (read 2 bits) */
			if (num == 0) {
				return TINF_DATA_ERROR;
			}
			sym = lengths[num - 1];
			length = tinf_getbits_base(d, 2, 3);
			break;
		case 17:
			/* Repeat code length 0 for 3-10 times (read 3 bits) */
			sym = 0;
			length = tinf_getbits_base(d, 3, 3);
			break;
		case 18:
			/* Repeat code length 0 for 11-138 times (read 7 bits) */
			sym = 0;
			length = tinf_getbits_base(d, 7, 11);
			break;
		default:
			/* Values 0-15 represent the actual code lengths */
			length = 1;
			break;
		}

		if (length > hlit + hdist - num) {
			return TINF_DATA_ERROR;
		}

		while (length--) {
			lengths[num++] = sym;
		}
	}

	/* Check EOB symbol is present */
	if (lengths[256] == 0) {
		return TINF_DATA_ERROR;
	}

	/* Build dynamic trees */
	res = tinf_build_tree(lt, lengths, hlit);

	if (res != TINF_OK) {
		return res;
	}

	res = tinf_build_tree(dt, lengths + hlit, hdist);

	if (res != TINF_OK) {
		return res;
	}

	return TINF_OK;
}

/* -- Block inflate functions -- */

/* Given a stream and two trees, inflate a block of data */
static int tinf_inflate_block_data(struct tinf_data *d, struct tinf_tree *lt,
                                   struct tinf_tree *dt)
{
	/* Extra bits and base tables for length codes */
	static const unsigned char length_bits[30] = {
		0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
		1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
		4, 4, 4, 4, 5, 5, 5, 5, 0, 127
	};

	static const unsigned short length_base[30] = {
		 3,  4,  5,   6,   7,   8,   9,  10,  11,  13,
		15, 17, 19,  23,  27,  31,  35,  43,  51,  59,
		67, 83, 99, 115, 131, 163, 195, 227, 258,   0
	};

	/* Extra bits and base tables for distance codes */
	static const unsigned char dist_bits[30] = {
		0, 0,  0,  0,  1,  1,  2,  2,  3,  3,
		4, 4,  5,  5,  6,  6,  7,  7,  8,  8,
		9, 9, 10, 10, 11, 11, 12, 12, 13, 13
	};

	static const unsigned short dist_base[30] = {
		   1,    2,    3,    4,    5,    7,    9,    13,    17,    25,
		  33,   49,   65,   97,  129,  193,  257,   385,   513,   769,
		1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
	};

	for (;;) {
		int sym = tinf_decode_symbol(d, lt);

		/* Check for overflow in bit reader */
		if (d->overflow) {
			return TINF_DATA_ERROR;
		}

		if (sym < 256) {
			if (d->dest == d->dest_end) {
				return TINF_BUF_ERROR;
			}
			*d->dest++ = sym;
		}
		else {
			int length, dist, offs;
			int i;

			/* Check for end of block */
			if (sym == 256) {
				return TINF_OK;
			}

			/* Check sym is within range and distance tree is not empty */
			if (sym > lt->max_sym || sym - 257 > 28 || dt->max_sym == -1) {
				return TINF_DATA_ERROR;
			}

			sym -= 257;

			/* Possibly get more bits from length code */
			length = tinf_getbits_base(d, length_bits[sym],
			                           length_base[sym]);

			dist = tinf_decode_symbol(d, dt);

			/* Check dist is within range */
			if (dist > dt->max_sym || dist > 29) {
				return TINF_DATA_ERROR;
			}

			/* Possibly get more bits from distance code */
			offs = tinf_getbits_base(d, dist_bits[dist],
			                         dist_base[dist]);

			if (offs > d->dest - d->dest_start) {
				return TINF_DATA_ERROR;
			}

			if (d->dest_end - d->dest < length) {
				return TINF_BUF_ERROR;
			}

			/* Copy match */
			for (i = 0; i < length; ++i) {
				d->dest[i] = d->dest[i - offs];
			}

			d->dest += length;
		}
	}
}

/* Inflate an uncompressed block of data */
static int tinf_inflate_uncompressed_block(struct tinf_data *d)
{
	unsigned int length, invlength;

	if (d->source_end - d->source < 4) {
		return TINF_DATA_ERROR;
	}

	/* Get length */
	length = read_le16(d->source);

	/* Get one's complement of length */
	invlength = read_le16(d->source + 2);

	/* Check length */
	if (length != (~invlength & 0x0000FFFF)) {
		return TINF_DATA_ERROR;
	}

	d->source += 4;

	if (d->source_end - d->source < length) {
		return TINF_DATA_ERROR;
	}

	if (d->dest_end - d->dest < length) {
		return TINF_BUF_ERROR;
	}

	/* Copy block */
	while (length--) {
		*d->dest++ = *d->source++;
	}

	/* Make sure we start next block on a byte boundary */
	d->tag = 0;
	d->bitcount = 0;

	return TINF_OK;
}

/* Inflate a block of data compressed with fixed Huffman trees */
static int tinf_inflate_fixed_block(struct tinf_data *d)
{
	/* Build fixed Huffman trees */
	tinf_build_fixed_trees(&d->ltree, &d->dtree);

	/* Decode block using fixed trees */
	return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
}

/* Inflate a block of data compressed with dynamic Huffman trees */
static int tinf_inflate_dynamic_block(struct tinf_data *d)
{
	/* Decode trees from stream */
	int res = tinf_decode_trees(d, &d->ltree, &d->dtree);

	if (res != TINF_OK) {
		return res;
	}

	/* Decode block using decoded trees */
	return tinf_inflate_block_data(d, &d->ltree, &d->dtree);
}

/* -- Public functions -- */

/* Initialize global (static) data */
void tinf_init(void)
{
	return;
}

/* Inflate stream from source to dest */
int tinf_uncompress(void *dest, unsigned int *destLen,
                    const void *source, unsigned int sourceLen)
{
	struct tinf_data d;
	int bfinal;

	/* Initialise data */
	d.source = (const unsigned char *) source;
	d.source_end = d.source + sourceLen;
	d.tag = 0;
	d.bitcount = 0;
	d.overflow = 0;

	d.dest = (unsigned char *) dest;
	d.dest_start = d.dest;
	d.dest_end = d.dest + *destLen;

	do {
		unsigned int btype;
		int res;

		/* Read final block flag */
		bfinal = tinf_getbits(&d, 1);

		/* Read block type (2 bits) */
		btype = tinf_getbits(&d, 2);

		/* Decompress block */
		switch (btype) {
		case 0:
			/* Decompress uncompressed block */
			res = tinf_inflate_uncompressed_block(&d);
			break;
		case 1:
			/* Decompress block with fixed Huffman trees */
			res = tinf_inflate_fixed_block(&d);
			break;
		case 2:
			/* Decompress block with dynamic Huffman trees */
			res = tinf_inflate_dynamic_block(&d);
			break;
		default:
			res = TINF_DATA_ERROR;
			break;
		}

		if (res != TINF_OK) {
			return res;
		}
	} while (!bfinal);

	/* Check for overflow in bit reader */
	if (d.overflow) {
		return TINF_DATA_ERROR;
	}

	*destLen = d.dest - d.dest_start;

	return TINF_OK;
}

/* clang -g -O1 -fsanitize=fuzzer,address -DTINF_FUZZING tinflate.c */
#if defined(TINF_FUZZING)
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

unsigned char depacked[64 * 1024];

extern int
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
	if (size > UINT_MAX / 2) { return 0; }
	unsigned int destLen = sizeof(depacked);
	tinf_uncompress(depacked, &destLen, data, size);
	return 0;
}
#endif


================================================
FILE: src/tinfzlib.c
================================================
/*
 * tinfzlib - tiny zlib decompressor
 *
 * Copyright (c) 2003-2019 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

#include "tinf.h"

static unsigned int read_be32(const unsigned char *p)
{
	return ((unsigned int) p[0] << 24)
	     | ((unsigned int) p[1] << 16)
	     | ((unsigned int) p[2] << 8)
	     | ((unsigned int) p[3]);
}

int tinf_zlib_uncompress(void *dest, unsigned int *destLen,
                         const void *source, unsigned int sourceLen)
{
	const unsigned char *src = (const unsigned char *) source;
	unsigned char *dst = (unsigned char *) dest;
	unsigned int a32;
	int res;
	unsigned char cmf, flg;

	/* -- Check header -- */

	/* Check room for at least 2 byte header and 4 byte trailer */
	if (sourceLen < 6) {
		return TINF_DATA_ERROR;
	}

	/* Get header bytes */
	cmf = src[0];
	flg = src[1];

	/* Check checksum */
	if ((256 * cmf + flg) % 31) {
		return TINF_DATA_ERROR;
	}

	/* Check method is deflate */
	if ((cmf & 0x0F) != 8) {
		return TINF_DATA_ERROR;
	}

	/* Check window size is valid */
	if ((cmf >> 4) > 7) {
		return TINF_DATA_ERROR;
	}

	/* Check there is no preset dictionary */
	if (flg & 0x20) {
		return TINF_DATA_ERROR;
	}

	/* -- Get Adler-32 checksum of original data -- */

	a32 = read_be32(&src[sourceLen - 4]);

	/* -- Decompress data -- */

	res = tinf_uncompress(dst, destLen, src + 2, sourceLen - 6);

	if (res != TINF_OK) {
		return TINF_DATA_ERROR;
	}

	/* -- Check Adler-32 checksum -- */

	if (a32 != tinf_adler32(dst, *destLen)) {
		return TINF_DATA_ERROR;
	}

	return TINF_OK;
}


================================================
FILE: test/greatest.h
================================================
/*
 * Copyright (c) 2011-2021 Scott Vokes <vokes.s@gmail.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef GREATEST_H
#define GREATEST_H

#if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS)
extern "C" {
#endif

/* 1.5.0 */
#define GREATEST_VERSION_MAJOR 1
#define GREATEST_VERSION_MINOR 5
#define GREATEST_VERSION_PATCH 0

/* A unit testing system for C, contained in 1 file.
 * It doesn't use dynamic allocation or depend on anything
 * beyond ANSI C89.
 *
 * An up-to-date version can be found at:
 *     https://github.com/silentbicycle/greatest/
 */


/*********************************************************************
 * Minimal test runner template
 *********************************************************************/
#if 0

#include "greatest.h"

TEST foo_should_foo(void) {
    PASS();
}

static void setup_cb(void *data) {
    printf("setup callback for each test case\n");
}

static void teardown_cb(void *data) {
    printf("teardown callback for each test case\n");
}

SUITE(suite) {
    /* Optional setup/teardown callbacks which will be run before/after
     * every test case. If using a test suite, they will be cleared when
     * the suite finishes. */
    SET_SETUP(setup_cb, voidp_to_callback_data);
    SET_TEARDOWN(teardown_cb, voidp_to_callback_data);

    RUN_TEST(foo_should_foo);
}

/* Add definitions that need to be in the test runner's main file. */
GREATEST_MAIN_DEFS();

/* Set up, run suite(s) of tests, report pass/fail/skip stats. */
int run_tests(void) {
    GREATEST_INIT();            /* init. greatest internals */
    /* List of suites to run (if any). */
    RUN_SUITE(suite);

    /* Tests can also be run directly, without using test suites. */
    RUN_TEST(foo_should_foo);

    GREATEST_PRINT_REPORT();          /* display results */
    return greatest_all_passed();
}

/* main(), for a standalone command-line test runner.
 * This replaces run_tests above, and adds command line option
 * handling and exiting with a pass/fail status. */
int main(int argc, char **argv) {
    GREATEST_MAIN_BEGIN();      /* init & parse command-line args */
    RUN_SUITE(suite);
    GREATEST_MAIN_END();        /* display results */
}

#endif
/*********************************************************************/


#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>

/***********
 * Options *
 ***********/

/* Default column width for non-verbose output. */
#ifndef GREATEST_DEFAULT_WIDTH
#define GREATEST_DEFAULT_WIDTH 72
#endif

/* FILE *, for test logging. */
#ifndef GREATEST_STDOUT
#define GREATEST_STDOUT stdout
#endif

/* Remove GREATEST_ prefix from most commonly used symbols? */
#ifndef GREATEST_USE_ABBREVS
#define GREATEST_USE_ABBREVS 1
#endif

/* Set to 0 to disable all use of setjmp/longjmp. */
#ifndef GREATEST_USE_LONGJMP
#define GREATEST_USE_LONGJMP 0
#endif

/* Make it possible to replace fprintf with another
 * function with the same interface. */
#ifndef GREATEST_FPRINTF
#define GREATEST_FPRINTF fprintf
#endif

#if GREATEST_USE_LONGJMP
#include <setjmp.h>
#endif

/* Set to 0 to disable all use of time.h / clock(). */
#ifndef GREATEST_USE_TIME
#define GREATEST_USE_TIME 1
#endif

#if GREATEST_USE_TIME
#include <time.h>
#endif

/* Floating point type, for ASSERT_IN_RANGE. */
#ifndef GREATEST_FLOAT
#define GREATEST_FLOAT double
#define GREATEST_FLOAT_FMT "%g"
#endif

/* Size of buffer for test name + optional '_' separator and suffix */
#ifndef GREATEST_TESTNAME_BUF_SIZE
#define GREATEST_TESTNAME_BUF_SIZE 128
#endif


/*********
 * Types *
 *********/

/* Info for the current running suite. */
typedef struct greatest_suite_info {
    unsigned int tests_run;
    unsigned int passed;
    unsigned int failed;
    unsigned int skipped;

#if GREATEST_USE_TIME
    /* timers, pre/post running suite and individual tests */
    clock_t pre_suite;
    clock_t post_suite;
    clock_t pre_test;
    clock_t post_test;
#endif
} greatest_suite_info;

/* Type for a suite function. */
typedef void greatest_suite_cb(void);

/* Types for setup/teardown callbacks. If non-NULL, these will be run
 * and passed the pointer to their additional data. */
typedef void greatest_setup_cb(void *udata);
typedef void greatest_teardown_cb(void *udata);

/* Type for an equality comparison between two pointers of the same type.
 * Should return non-0 if equal, otherwise 0.
 * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */
typedef int greatest_equal_cb(const void *expd, const void *got, void *udata);

/* Type for a callback that prints a value pointed to by T.
 * Return value has the same meaning as printf's.
 * UDATA is a closure value, passed through from ASSERT_EQUAL_T[m]. */
typedef int greatest_printf_cb(const void *t, void *udata);

/* Callbacks for an arbitrary type; needed for type-specific
 * comparisons via GREATEST_ASSERT_EQUAL_T[m].*/
typedef struct greatest_type_info {
    greatest_equal_cb *equal;
    greatest_printf_cb *print;
} greatest_type_info;

typedef struct greatest_memory_cmp_env {
    const unsigned char *exp;
    const unsigned char *got;
    size_t size;
} greatest_memory_cmp_env;

/* Callbacks for string and raw memory types. */
extern greatest_type_info greatest_type_info_string;
extern greatest_type_info greatest_type_info_memory;

typedef enum {
    GREATEST_FLAG_FIRST_FAIL = 0x01,
    GREATEST_FLAG_LIST_ONLY = 0x02,
    GREATEST_FLAG_ABORT_ON_FAIL = 0x04
} greatest_flag_t;

/* Internal state for a PRNG, used to shuffle test order. */
struct greatest_prng {
    unsigned char random_order; /* use random ordering? */
    unsigned char initialized;  /* is random ordering initialized? */
    unsigned char pad_0[6];
    unsigned long state;        /* PRNG state */
    unsigned long count;        /* how many tests, this pass */
    unsigned long count_ceil;   /* total number of tests */
    unsigned long count_run;    /* total tests run */
    unsigned long a;            /* LCG multiplier */
    unsigned long c;            /* LCG increment */
    unsigned long m;            /* LCG modulus, based on count_ceil */
};

/* Struct containing all test runner state. */
typedef struct greatest_run_info {
    unsigned char flags;
    unsigned char verbosity;
    unsigned char running_test; /* guard for nested RUN_TEST calls */
    unsigned char exact_name_match;

    unsigned int tests_run;     /* total test count */

    /* currently running test suite */
    greatest_suite_info suite;

    /* overall pass/fail/skip counts */
    unsigned int passed;
    unsigned int failed;
    unsigned int skipped;
    unsigned int assertions;

    /* info to print about the most recent failure */
    unsigned int fail_line;
    unsigned int pad_1;
    const char *fail_file;
    const char *msg;

    /* current setup/teardown hooks and userdata */
    greatest_setup_cb *setup;
    void *setup_udata;
    greatest_teardown_cb *teardown;
    void *teardown_udata;

    /* formatting info for ".....s...F"-style output */
    unsigned int col;
    unsigned int width;

    /* only run a specific suite or test */
    const char *suite_filter;
    const char *test_filter;
    const char *test_exclude;
    const char *name_suffix;    /* print suffix with test name */
    char name_buf[GREATEST_TESTNAME_BUF_SIZE];

    struct greatest_prng prng[2]; /* 0: suites, 1: tests */

#if GREATEST_USE_TIME
    /* overall timers */
    clock_t begin;
    clock_t end;
#endif

#if GREATEST_USE_LONGJMP
    int pad_jmp_buf;
    unsigned char pad_2[4];
    jmp_buf jump_dest;
#endif
} greatest_run_info;

struct greatest_report_t {
    /* overall pass/fail/skip counts */
    unsigned int passed;
    unsigned int failed;
    unsigned int skipped;
    unsigned int assertions;
};

/* Global var for the current testing context.
 * Initialized by GREATEST_MAIN_DEFS(). */
extern greatest_run_info greatest_info;

/* Type for ASSERT_ENUM_EQ's ENUM_STR argument. */
typedef const char *greatest_enum_str_fun(int value);


/**********************
 * Exported functions *
 **********************/

/* These are used internally by greatest macros. */
int greatest_test_pre(const char *name);
void greatest_test_post(int res);
int greatest_do_assert_equal_t(const void *expd, const void *got,
    greatest_type_info *type_info, void *udata);
void greatest_prng_init_first_pass(int id);
int greatest_prng_init_second_pass(int id, unsigned long seed);
void greatest_prng_step(int id);

/* These are part of the public greatest API. */
void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata);
void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata);
void GREATEST_INIT(void);
void GREATEST_PRINT_REPORT(void);
int greatest_all_passed(void);
void greatest_set_suite_filter(const char *filter);
void greatest_set_test_filter(const char *filter);
void greatest_set_test_exclude(const char *filter);
void greatest_set_exact_name_match(void);
void greatest_stop_at_first_fail(void);
void greatest_abort_on_fail(void);
void greatest_list_only(void);
void greatest_get_report(struct greatest_report_t *report);
unsigned int greatest_get_verbosity(void);
void greatest_set_verbosity(unsigned int verbosity);
void greatest_set_flag(greatest_flag_t flag);
void greatest_set_test_suffix(const char *suffix);


/********************
* Language Support *
********************/

/* If __VA_ARGS__ (C99) is supported, allow parametric testing
* without needing to manually manage the argument struct. */
#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 19901L) ||        \
    (defined(_MSC_VER) && _MSC_VER >= 1800)
#define GREATEST_VA_ARGS
#endif


/**********
 * Macros *
 **********/

/* Define a suite. (The duplication is intentional -- it eliminates
 * a warning from -Wmissing-declarations.) */
#define GREATEST_SUITE(NAME) void NAME(void); void NAME(void)

/* Declare a suite, provided by another compilation unit. */
#define GREATEST_SUITE_EXTERN(NAME) void NAME(void)

/* Start defining a test function.
 * The arguments are not included, to allow parametric testing. */
#define GREATEST_TEST static enum greatest_test_res

/* PASS/FAIL/SKIP result from a test. Used internally. */
typedef enum greatest_test_res {
    GREATEST_TEST_RES_PASS = 0,
    GREATEST_TEST_RES_FAIL = -1,
    GREATEST_TEST_RES_SKIP = 1
} greatest_test_res;

/* Run a suite. */
#define GREATEST_RUN_SUITE(S_NAME) greatest_run_suite(S_NAME, #S_NAME)

/* Run a test in the current suite. */
#define GREATEST_RUN_TEST(TEST)                                         \
    do {                                                                \
        if (greatest_test_pre(#TEST) == 1) {                            \
            enum greatest_test_res res = GREATEST_SAVE_CONTEXT();       \
            if (res == GREATEST_TEST_RES_PASS) {                        \
                res = TEST();                                           \
            }                                                           \
            greatest_test_post(res);                                    \
        }                                                               \
    } while (0)

/* Ignore a test, don't warn about it being unused. */
#define GREATEST_IGNORE_TEST(TEST) (void)TEST

/* Run a test in the current suite with one void * argument,
 * which can be a pointer to a struct with multiple arguments. */
#define GREATEST_RUN_TEST1(TEST, ENV)                                   \
    do {                                                                \
        if (greatest_test_pre(#TEST) == 1) {                            \
            enum greatest_test_res res = GREATEST_SAVE_CONTEXT();       \
            if (res == GREATEST_TEST_RES_PASS) {                        \
                res = TEST(ENV);                                        \
            }                                                           \
            greatest_test_post(res);                                    \
        }                                                               \
    } while (0)

#ifdef GREATEST_VA_ARGS
#define GREATEST_RUN_TESTp(TEST, ...)                                   \
    do {                                                                \
        if (greatest_test_pre(#TEST) == 1) {                            \
            enum greatest_test_res res = GREATEST_SAVE_CONTEXT();       \
            if (res == GREATEST_TEST_RES_PASS) {                        \
                res = TEST(__VA_ARGS__);                                \
            }                                                           \
            greatest_test_post(res);                                    \
        }                                                               \
    } while (0)
#endif


/* Check if the test runner is in verbose mode. */
#define GREATEST_IS_VERBOSE() ((greatest_info.verbosity) > 0)
#define GREATEST_LIST_ONLY()                                            \
    (greatest_info.flags & GREATEST_FLAG_LIST_ONLY)
#define GREATEST_FIRST_FAIL()                                           \
    (greatest_info.flags & GREATEST_FLAG_FIRST_FAIL)
#define GREATEST_ABORT_ON_FAIL()                                        \
    (greatest_info.flags & GREATEST_FLAG_ABORT_ON_FAIL)
#define GREATEST_FAILURE_ABORT()                                        \
    (GREATEST_FIRST_FAIL() &&                                           \
        (greatest_info.suite.failed > 0 || greatest_info.failed > 0))

/* Message-less forms of tests defined below. */
#define GREATEST_PASS() GREATEST_PASSm(NULL)
#define GREATEST_FAIL() GREATEST_FAILm(NULL)
#define GREATEST_SKIP() GREATEST_SKIPm(NULL)
#define GREATEST_ASSERT(COND)                                           \
    GREATEST_ASSERTm(#COND, COND)
#define GREATEST_ASSERT_OR_LONGJMP(COND)                                \
    GREATEST_ASSERT_OR_LONGJMPm(#COND, COND)
#define GREATEST_ASSERT_FALSE(COND)                                     \
    GREATEST_ASSERT_FALSEm(#COND, COND)
#define GREATEST_ASSERT_EQ(EXP, GOT)                                    \
    GREATEST_ASSERT_EQm(#EXP " != " #GOT, EXP, GOT)
#define GREATEST_ASSERT_NEQ(EXP, GOT)                                   \
    GREATEST_ASSERT_NEQm(#EXP " == " #GOT, EXP, GOT)
#define GREATEST_ASSERT_GT(EXP, GOT)                                    \
    GREATEST_ASSERT_GTm(#EXP " <= " #GOT, EXP, GOT)
#define GREATEST_ASSERT_GTE(EXP, GOT)                                   \
    GREATEST_ASSERT_GTEm(#EXP " < " #GOT, EXP, GOT)
#define GREATEST_ASSERT_LT(EXP, GOT)                                    \
    GREATEST_ASSERT_LTm(#EXP " >= " #GOT, EXP, GOT)
#define GREATEST_ASSERT_LTE(EXP, GOT)                                   \
    GREATEST_ASSERT_LTEm(#EXP " > " #GOT, EXP, GOT)
#define GREATEST_ASSERT_EQ_FMT(EXP, GOT, FMT)                           \
    GREATEST_ASSERT_EQ_FMTm(#EXP " != " #GOT, EXP, GOT, FMT)
#define GREATEST_ASSERT_IN_RANGE(EXP, GOT, TOL)                         \
    GREATEST_ASSERT_IN_RANGEm(#EXP " != " #GOT " +/- " #TOL, EXP, GOT, TOL)
#define GREATEST_ASSERT_EQUAL_T(EXP, GOT, TYPE_INFO, UDATA)             \
    GREATEST_ASSERT_EQUAL_Tm(#EXP " != " #GOT, EXP, GOT, TYPE_INFO, UDATA)
#define GREATEST_ASSERT_STR_EQ(EXP, GOT)                                \
    GREATEST_ASSERT_STR_EQm(#EXP " != " #GOT, EXP, GOT)
#define GREATEST_ASSERT_STRN_EQ(EXP, GOT, SIZE)                         \
    GREATEST_ASSERT_STRN_EQm(#EXP " != " #GOT, EXP, GOT, SIZE)
#define GREATEST_ASSERT_MEM_EQ(EXP, GOT, SIZE)                          \
    GREATEST_ASSERT_MEM_EQm(#EXP " != " #GOT, EXP, GOT, SIZE)
#define GREATEST_ASSERT_ENUM_EQ(EXP, GOT, ENUM_STR)                     \
    GREATEST_ASSERT_ENUM_EQm(#EXP " != " #GOT, EXP, GOT, ENUM_STR)

/* The following forms take an additional message argument first,
 * to be displayed by the test runner. */

/* Fail if a condition is not true, with message. */
#define GREATEST_ASSERTm(MSG, COND)                                     \
    do {                                                                \
        greatest_info.assertions++;                                     \
        if (!(COND)) { GREATEST_FAILm(MSG); }                           \
    } while (0)

/* Fail if a condition is not true, longjmping out of test. */
#define GREATEST_ASSERT_OR_LONGJMPm(MSG, COND)                          \
    do {                                                                \
        greatest_info.assertions++;                                     \
        if (!(COND)) { GREATEST_FAIL_WITH_LONGJMPm(MSG); }              \
    } while (0)

/* Fail if a condition is not false, with message. */
#define GREATEST_ASSERT_FALSEm(MSG, COND)                               \
    do {                                                                \
        greatest_info.assertions++;                                     \
        if ((COND)) { GREATEST_FAILm(MSG); }                            \
    } while (0)

/* Internal macro for relational assertions */
#define GREATEST__REL(REL, MSG, EXP, GOT)                               \
    do {                                                                \
        greatest_info.assertions++;                                     \
        if (!((EXP) REL (GOT))) { GREATEST_FAILm(MSG); }                \
    } while (0)

/* Fail if EXP is not ==, !=, >, <, >=, or <= to GOT. */
#define GREATEST_ASSERT_EQm(MSG,E,G) GREATEST__REL(==, MSG,E,G)
#define GREATEST_ASSERT_NEQm(MSG,E,G) GREATEST__REL(!=, MSG,E,G)
#define GREATEST_ASSERT_GTm(MSG,E,G) GREATEST__REL(>, MSG,E,G)
#define GREATEST_ASSERT_GTEm(MSG,E,G) GREATEST__REL(>=, MSG,E,G)
#define GREATEST_ASSERT_LTm(MSG,E,G) GREATEST__REL(<, MSG,E,G)
#define GREATEST_ASSERT_LTEm(MSG,E,G) GREATEST__REL(<=, MSG,E,G)

/* Fail if EXP != GOT (equality comparison by ==).
 * Warning: FMT, EXP, and GOT will be evaluated more
 * than once on failure. */
#define GREATEST_ASSERT_EQ_FMTm(MSG, EXP, GOT, FMT)                     \
    do {                                                                \
        greatest_info.assertions++;                                     \
        if ((EXP) != (GOT)) {                                           \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: ");          \
            GREATEST_FPRINTF(GREATEST_STDOUT, FMT, EXP);                \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\n     Got: ");          \
            GREATEST_FPRINTF(GREATEST_STDOUT, FMT, GOT);                \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\n");                    \
            GREATEST_FAILm(MSG);                                        \
        }                                                               \
    } while (0)

/* Fail if EXP is not equal to GOT, printing enum IDs. */
#define GREATEST_ASSERT_ENUM_EQm(MSG, EXP, GOT, ENUM_STR)               \
    do {                                                                \
        int greatest_EXP = (int)(EXP);                                  \
        int greatest_GOT = (int)(GOT);                                  \
        greatest_enum_str_fun *greatest_ENUM_STR = ENUM_STR;            \
        if (greatest_EXP != greatest_GOT) {                             \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: %s",         \
                greatest_ENUM_STR(greatest_EXP));                       \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\n     Got: %s\n",       \
                greatest_ENUM_STR(greatest_GOT));                       \
            GREATEST_FAILm(MSG);                                        \
        }                                                               \
    } while (0)                                                         \

/* Fail if GOT not in range of EXP +|- TOL. */
#define GREATEST_ASSERT_IN_RANGEm(MSG, EXP, GOT, TOL)                   \
    do {                                                                \
        GREATEST_FLOAT greatest_EXP = (EXP);                            \
        GREATEST_FLOAT greatest_GOT = (GOT);                            \
        GREATEST_FLOAT greatest_TOL = (TOL);                            \
        greatest_info.assertions++;                                     \
        if ((greatest_EXP > greatest_GOT &&                             \
                greatest_EXP - greatest_GOT > greatest_TOL) ||          \
            (greatest_EXP < greatest_GOT &&                             \
                greatest_GOT - greatest_EXP > greatest_TOL)) {          \
            GREATEST_FPRINTF(GREATEST_STDOUT,                           \
                "\nExpected: " GREATEST_FLOAT_FMT                       \
                " +/- " GREATEST_FLOAT_FMT                              \
                "\n     Got: " GREATEST_FLOAT_FMT                       \
                "\n",                                                   \
                greatest_EXP, greatest_TOL, greatest_GOT);              \
            GREATEST_FAILm(MSG);                                        \
        }                                                               \
    } while (0)

/* Fail if EXP is not equal to GOT, according to strcmp. */
#define GREATEST_ASSERT_STR_EQm(MSG, EXP, GOT)                          \
    do {                                                                \
        GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT,                         \
            &greatest_type_info_string, NULL);                          \
    } while (0)                                                         \

/* Fail if EXP is not equal to GOT, according to strncmp. */
#define GREATEST_ASSERT_STRN_EQm(MSG, EXP, GOT, SIZE)                   \
    do {                                                                \
        size_t size = SIZE;                                             \
        GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT,                         \
            &greatest_type_info_string, &size);                         \
    } while (0)                                                         \

/* Fail if EXP is not equal to GOT, according to memcmp. */
#define GREATEST_ASSERT_MEM_EQm(MSG, EXP, GOT, SIZE)                    \
    do {                                                                \
        greatest_memory_cmp_env env;                                    \
        env.exp = (const unsigned char *)EXP;                           \
        env.got = (const unsigned char *)GOT;                           \
        env.size = SIZE;                                                \
        GREATEST_ASSERT_EQUAL_Tm(MSG, env.exp, env.got,                 \
            &greatest_type_info_memory, &env);                          \
    } while (0)                                                         \

/* Fail if EXP is not equal to GOT, according to a comparison
 * callback in TYPE_INFO. If they are not equal, optionally use a
 * print callback in TYPE_INFO to print them. */
#define GREATEST_ASSERT_EQUAL_Tm(MSG, EXP, GOT, TYPE_INFO, UDATA)       \
    do {                                                                \
        greatest_type_info *type_info = (TYPE_INFO);                    \
        greatest_info.assertions++;                                     \
        if (!greatest_do_assert_equal_t(EXP, GOT,                       \
                type_info, UDATA)) {                                    \
            if (type_info == NULL || type_info->equal == NULL) {        \
                GREATEST_FAILm("type_info->equal callback missing!");   \
            } else {                                                    \
                GREATEST_FAILm(MSG);                                    \
            }                                                           \
        }                                                               \
    } while (0)                                                         \

/* Pass. */
#define GREATEST_PASSm(MSG)                                             \
    do {                                                                \
        greatest_info.msg = MSG;                                        \
        return GREATEST_TEST_RES_PASS;                                  \
    } while (0)

/* Fail. */
#define GREATEST_FAILm(MSG)                                             \
    do {                                                                \
        greatest_info.fail_file = __FILE__;                             \
        greatest_info.fail_line = __LINE__;                             \
        greatest_info.msg = MSG;                                        \
        if (GREATEST_ABORT_ON_FAIL()) { abort(); }                      \
        return GREATEST_TEST_RES_FAIL;                                  \
    } while (0)

/* Optional GREATEST_FAILm variant that longjmps. */
#if GREATEST_USE_LONGJMP
#define GREATEST_FAIL_WITH_LONGJMP() GREATEST_FAIL_WITH_LONGJMPm(NULL)
#define GREATEST_FAIL_WITH_LONGJMPm(MSG)                                \
    do {                                                                \
        greatest_info.fail_file = __FILE__;                             \
        greatest_info.fail_line = __LINE__;                             \
        greatest_info.msg = MSG;                                        \
        longjmp(greatest_info.jump_dest, GREATEST_TEST_RES_FAIL);       \
    } while (0)
#endif

/* Skip the current test. */
#define GREATEST_SKIPm(MSG)                                             \
    do {                                                                \
        greatest_info.msg = MSG;                                        \
        return GREATEST_TEST_RES_SKIP;                                  \
    } while (0)

/* Check the result of a subfunction using ASSERT, etc. */
#define GREATEST_CHECK_CALL(RES)                                        \
    do {                                                                \
        enum greatest_test_res greatest_RES = RES;                      \
        if (greatest_RES != GREATEST_TEST_RES_PASS) {                   \
            return greatest_RES;                                        \
        }                                                               \
    } while (0)                                                         \

#if GREATEST_USE_TIME
#define GREATEST_SET_TIME(NAME)                                         \
    NAME = clock();                                                     \
    if (NAME == (clock_t) -1) {                                         \
        GREATEST_FPRINTF(GREATEST_STDOUT,                               \
            "clock error: %s\n", #NAME);                                \
        exit(EXIT_FAILURE);                                             \
    }

#define GREATEST_CLOCK_DIFF(C1, C2)                                     \
    GREATEST_FPRINTF(GREATEST_STDOUT, " (%lu ticks, %.3f sec)",         \
        (long unsigned int) (C2) - (long unsigned int)(C1),             \
        (double)((C2) - (C1)) / (1.0 * (double)CLOCKS_PER_SEC))
#else
#define GREATEST_SET_TIME(UNUSED)
#define GREATEST_CLOCK_DIFF(UNUSED1, UNUSED2)
#endif

#if GREATEST_USE_LONGJMP
#define GREATEST_SAVE_CONTEXT()                                         \
        /* setjmp returns 0 (GREATEST_TEST_RES_PASS) on first call *    \
         * so the test runs, then RES_FAIL from FAIL_WITH_LONGJMP. */   \
        ((enum greatest_test_res)(setjmp(greatest_info.jump_dest)))
#else
#define GREATEST_SAVE_CONTEXT()                                         \
    /*a no-op, since setjmp/longjmp aren't being used */                \
    GREATEST_TEST_RES_PASS
#endif

/* Run every suite / test function run within BODY in pseudo-random
 * order, seeded by SEED. (The top 3 bits of the seed are ignored.)
 *
 * This should be called like:
 *     GREATEST_SHUFFLE_TESTS(seed, {
 *         GREATEST_RUN_TEST(some_test);
 *         GREATEST_RUN_TEST(some_other_test);
 *         GREATEST_RUN_TEST(yet_another_test);
 *     });
 *
 * Note that the body of the second argument will be evaluated
 * multiple times. */
#define GREATEST_SHUFFLE_SUITES(SD, BODY) GREATEST_SHUFFLE(0, SD, BODY)
#define GREATEST_SHUFFLE_TESTS(SD, BODY) GREATEST_SHUFFLE(1, SD, BODY)
#define GREATEST_SHUFFLE(ID, SD, BODY)                                  \
    do {                                                                \
        struct greatest_prng *prng = &greatest_info.prng[ID];           \
        greatest_prng_init_first_pass(ID);                              \
        do {                                                            \
            prng->count = 0;                                            \
            if (prng->initialized) { greatest_prng_step(ID); }          \
            BODY;                                                       \
            if (!prng->initialized) {                                   \
                if (!greatest_prng_init_second_pass(ID, SD)) { break; } \
            } else if (prng->count_run == prng->count_ceil) {           \
                break;                                                  \
            }                                                           \
        } while (!GREATEST_FAILURE_ABORT());                            \
        prng->count_run = prng->random_order = prng->initialized = 0;   \
    } while(0)

/* Include several function definitions in the main test file. */
#define GREATEST_MAIN_DEFS()                                            \
                                                                        \
/* Is FILTER a subset of NAME? */                                       \
static int greatest_name_match(const char *name, const char *filter,    \
        int res_if_none) {                                              \
    size_t offset = 0;                                                  \
    size_t filter_len = filter ? strlen(filter) : 0;                    \
    if (filter_len == 0) { return res_if_none; } /* no filter */        \
    if (greatest_info.exact_name_match && strlen(name) != filter_len) { \
        return 0; /* ignore substring matches */                        \
    }                                                                   \
    while (name[offset] != '\0') {                                      \
        if (name[offset] == filter[0]) {                                \
            if (0 == strncmp(&name[offset], filter, filter_len)) {      \
                return 1;                                               \
            }                                                           \
        }                                                               \
        offset++;                                                       \
    }                                                                   \
                                                                        \
    return 0;                                                           \
}                                                                       \
                                                                        \
static void greatest_buffer_test_name(const char *name) {               \
    struct greatest_run_info *g = &greatest_info;                       \
    size_t len = strlen(name), size = sizeof(g->name_buf);              \
    memset(g->name_buf, 0x00, size);                                    \
    (void)strncat(g->name_buf, name, size - 1);                         \
    if (g->name_suffix && (len + 1 < size)) {                           \
        g->name_buf[len] = '_';                                         \
        strncat(&g->name_buf[len+1], g->name_suffix, size-(len+2));     \
    }                                                                   \
}                                                                       \
                                                                        \
/* Before running a test, check the name filtering and                  \
 * test shuffling state, if applicable, and then call setup hooks. */   \
int greatest_test_pre(const char *name) {                               \
    struct greatest_run_info *g = &greatest_info;                       \
    int match;                                                          \
    greatest_buffer_test_name(name);                                    \
    match = greatest_name_match(g->name_buf, g->test_filter, 1) &&      \
      !greatest_name_match(g->name_buf, g->test_exclude, 0);            \
    if (GREATEST_LIST_ONLY()) {   /* just listing test names */         \
        if (match) {                                                    \
            GREATEST_FPRINTF(GREATEST_STDOUT, "  %s\n", g->name_buf);   \
        }                                                               \
        goto clear;                                                     \
    }                                                                   \
    if (match && (!GREATEST_FIRST_FAIL() || g->suite.failed == 0)) {    \
            struct greatest_prng *p = &g->prng[1];                      \
        if (p->random_order) {                                          \
            p->count++;                                                 \
            if (!p->initialized || ((p->count - 1) != p->state)) {      \
                goto clear;       /* don't run this test yet */         \
            }                                                           \
        }                                                               \
        if (g->running_test) {                                          \
            fprintf(stderr, "Error: Test run inside another test.\n");  \
            return 0;                                                   \
        }                                                               \
        GREATEST_SET_TIME(g->suite.pre_test);                           \
        if (g->setup) { g->setup(g->setup_udata); }                     \
        p->count_run++;                                                 \
        g->running_test = 1;                                            \
        return 1;                 /* test should be run */              \
    } else {                                                            \
        goto clear;               /* skipped */                         \
    }                                                                   \
clear:                                                                  \
    g->name_suffix = NULL;                                              \
    return 0;                                                           \
}                                                                       \
                                                                        \
static void greatest_do_pass(void) {                                    \
    struct greatest_run_info *g = &greatest_info;                       \
    if (GREATEST_IS_VERBOSE()) {                                        \
        GREATEST_FPRINTF(GREATEST_STDOUT, "PASS %s: %s",                \
            g->name_buf, g->msg ? g->msg : "");                         \
    } else {                                                            \
        GREATEST_FPRINTF(GREATEST_STDOUT, ".");                         \
    }                                                                   \
    g->suite.passed++;                                                  \
}                                                                       \
                                                                        \
static void greatest_do_fail(void) {                                    \
    struct greatest_run_info *g = &greatest_info;                       \
    if (GREATEST_IS_VERBOSE()) {                                        \
        GREATEST_FPRINTF(GREATEST_STDOUT,                               \
            "FAIL %s: %s (%s:%u)", g->name_buf,                         \
            g->msg ? g->msg : "", g->fail_file, g->fail_line);          \
    } else {                                                            \
        GREATEST_FPRINTF(GREATEST_STDOUT, "F");                         \
        g->col++;  /* add linebreak if in line of '.'s */               \
        if (g->col != 0) {                                              \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\n");                    \
            g->col = 0;                                                 \
        }                                                               \
        GREATEST_FPRINTF(GREATEST_STDOUT, "FAIL %s: %s (%s:%u)\n",      \
            g->name_buf, g->msg ? g->msg : "",                          \
            g->fail_file, g->fail_line);                                \
    }                                                                   \
    g->suite.failed++;                                                  \
}                                                                       \
                                                                        \
static void greatest_do_skip(void) {                                    \
    struct greatest_run_info *g = &greatest_info;                       \
    if (GREATEST_IS_VERBOSE()) {                                        \
        GREATEST_FPRINTF(GREATEST_STDOUT, "SKIP %s: %s",                \
            g->name_buf, g->msg ? g->msg : "");                         \
    } else {                                                            \
        GREATEST_FPRINTF(GREATEST_STDOUT, "s");                         \
    }                                                                   \
    g->suite.skipped++;                                                 \
}                                                                       \
                                                                        \
void greatest_test_post(int res) {                                      \
    GREATEST_SET_TIME(greatest_info.suite.post_test);                   \
    if (greatest_info.teardown) {                                       \
        void *udata = greatest_info.teardown_udata;                     \
        greatest_info.teardown(udata);                                  \
    }                                                                   \
                                                                        \
    greatest_info.running_test = 0;                                     \
    if (res <= GREATEST_TEST_RES_FAIL) {                                \
        greatest_do_fail();                                             \
    } else if (res >= GREATEST_TEST_RES_SKIP) {                         \
        greatest_do_skip();                                             \
    } else if (res == GREATEST_TEST_RES_PASS) {                         \
        greatest_do_pass();                                             \
    }                                                                   \
    greatest_info.name_suffix = NULL;                                   \
    greatest_info.suite.tests_run++;                                    \
    greatest_info.col++;                                                \
    if (GREATEST_IS_VERBOSE()) {                                        \
        GREATEST_CLOCK_DIFF(greatest_info.suite.pre_test,               \
            greatest_info.suite.post_test);                             \
        GREATEST_FPRINTF(GREATEST_STDOUT, "\n");                        \
    } else if (greatest_info.col % greatest_info.width == 0) {          \
        GREATEST_FPRINTF(GREATEST_STDOUT, "\n");                        \
        greatest_info.col = 0;                                          \
    }                                                                   \
    fflush(GREATEST_STDOUT);                                            \
}                                                                       \
                                                                        \
static void report_suite(void) {                                        \
    if (greatest_info.suite.tests_run > 0) {                            \
        GREATEST_FPRINTF(GREATEST_STDOUT,                               \
            "\n%u test%s - %u passed, %u failed, %u skipped",           \
            greatest_info.suite.tests_run,                              \
            greatest_info.suite.tests_run == 1 ? "" : "s",              \
            greatest_info.suite.passed,                                 \
            greatest_info.suite.failed,                                 \
            greatest_info.suite.skipped);                               \
        GREATEST_CLOCK_DIFF(greatest_info.suite.pre_suite,              \
            greatest_info.suite.post_suite);                            \
        GREATEST_FPRINTF(GREATEST_STDOUT, "\n");                        \
    }                                                                   \
}                                                                       \
                                                                        \
static void update_counts_and_reset_suite(void) {                       \
    greatest_info.setup = NULL;                                         \
    greatest_info.setup_udata = NULL;                                   \
    greatest_info.teardown = NULL;                                      \
    greatest_info.teardown_udata = NULL;                                \
    greatest_info.passed += greatest_info.suite.passed;                 \
    greatest_info.failed += greatest_info.suite.failed;                 \
    greatest_info.skipped += greatest_info.suite.skipped;               \
    greatest_info.tests_run += greatest_info.suite.tests_run;           \
    memset(&greatest_info.suite, 0, sizeof(greatest_info.suite));       \
    greatest_info.col = 0;                                              \
}                                                                       \
                                                                        \
static int greatest_suite_pre(const char *suite_name) {                 \
    struct greatest_prng *p = &greatest_info.prng[0];                   \
    if (!greatest_name_match(suite_name, greatest_info.suite_filter, 1) \
        || (GREATEST_FAILURE_ABORT())) { return 0; }                    \
    if (p->random_order) {                                              \
        p->count++;                                                     \
        if (!p->initialized || ((p->count - 1) != p->state)) {          \
            return 0; /* don't run this suite yet */                    \
        }                                                               \
    }                                                                   \
    p->count_run++;                                                     \
    update_counts_and_reset_suite();                                    \
    GREATEST_FPRINTF(GREATEST_STDOUT, "\n* Suite %s:\n", suite_name);   \
    GREATEST_SET_TIME(greatest_info.suite.pre_suite);                   \
    return 1;                                                           \
}                                                                       \
                                                                        \
static void greatest_suite_post(void) {                                 \
    GREATEST_SET_TIME(greatest_info.suite.post_suite);                  \
    report_suite();                                                     \
}                                                                       \
                                                                        \
static void greatest_run_suite(greatest_suite_cb *suite_cb,             \
                               const char *suite_name) {                \
    if (greatest_suite_pre(suite_name)) {                               \
        suite_cb();                                                     \
        greatest_suite_post();                                          \
    }                                                                   \
}                                                                       \
                                                                        \
int greatest_do_assert_equal_t(const void *expd, const void *got,       \
        greatest_type_info *type_info, void *udata) {                   \
    int eq = 0;                                                         \
    if (type_info == NULL || type_info->equal == NULL) { return 0; }    \
    eq = type_info->equal(expd, got, udata);                            \
    if (!eq) {                                                          \
        if (type_info->print != NULL) {                                 \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\nExpected: ");          \
            (void)type_info->print(expd, udata);                        \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\n     Got: ");          \
            (void)type_info->print(got, udata);                         \
            GREATEST_FPRINTF(GREATEST_STDOUT, "\n");                    \
        }                                                               \
    }                                                                   \
    return eq;                                                          \
}                                                                       \
                                                                        \
static void greatest_usage(const char *name) {                          \
    GREATEST_FPRINTF(GREATEST_STDOUT,                                   \
        "Usage: %s [-hlfavex] [-s SUITE] [-t TEST] [-x EXCLUDE]\n"      \
        "  -h, --help  print this Help\n"                               \
        "  -l          List suites and tests, then exit (dry run)\n"    \
        "  -f          Stop runner after first failure\n"               \
        "  -a          Abort on first failure (implies -f)\n"           \
        "  -v          Verbose output\n"                                \
        "  -s SUITE    only run suites containing substring SUITE\n"    \
        "  -t TEST     only run tests containing substring TEST\n"      \
        "  -e          only run exact name match for -s or -t\n"        \
        "  -x EXCLUDE  exclude tests containing substring EXCLUDE\n",   \
        name);                                                          \
}                                                                       \
                                                                        \
static void greatest_parse_options(int argc, char **argv) {             \
    int i = 0;                                                          \
    for (i = 1; i < argc; i++) {                                        \
        if (argv[i][0] == '-') {                                        \
            char f = argv[i][1];                                        \
            if ((f == 's' || f == 't' || f == 'x') && argc <= i + 1) {  \
                greatest_usage(argv[0]); exit(EXIT_FAILURE);            \
            }                                                           \
            switch (f) {                                                \
            case 's': /* suite name filter */                           \
                greatest_set_suite_filter(argv[i + 1]); i++; break;     \
            case 't': /* test name filter */                            \
                greatest_set_test_filter(argv[i + 1]); i++; break;      \
            case 'x': /* test name exclusion */                         \
                greatest_set_test_exclude(argv[i + 1]); i++; break;     \
            case 'e': /* exact name match */                            \
                greatest_set_exact_name_match(); break;                 \
            case 'f': /* first fail flag */                             \
                greatest_stop_at_first_fail(); break;                   \
            case 'a': /* abort() on fail flag */                        \
                greatest_abort_on_fail(); break;                        \
            case 'l': /* list only (dry run) */                         \
                greatest_list_only(); break;                            \
            case 'v': /* first fail flag */                             \
                greatest_info.verbosity++; break;                       \
            case 'h': /* help */                                        \
                greatest_usage(argv[0]); exit(EXIT_SUCCESS);            \
            default:                                                    \
            case '-':                                                   \
                if (0 == strncmp("--help", argv[i], 6)) {               \
                    greatest_usage(argv[0]); exit(EXIT_SUCCESS);        \
                } else if (0 == strcmp("--", argv[i])) {                \
                    return; /* ignore following arguments */            \
                }                                                       \
                GREATEST_FPRINTF(GREATEST_STDOUT,                       \
                    "Unknown argument '%s'\n", argv[i]);                \
                greatest_usage(argv[0]);                                \
                exit(EXIT_FAILURE);                                     \
            }                                                           \
        }                                                               \
    }                                                                   \
}                                                                       \
                                                                        \
int greatest_all_passed(void) { return (greatest_info.failed == 0); }   \
                                                                        \
void greatest_set_test_filter(const char *filter) {                     \
    greatest_info.test_filter = filter;                                 \
}                                                                       \
                                                                        \
void greatest_set_test_exclude(const char *filter) {                    \
    greatest_info.test_exclude = filter;                                \
}                                                                       \
                                                                        \
void greatest_set_suite_filter(const char *filter) {                    \
    greatest_info.suite_filter = filter;                                \
}                                                                       \
                                                                        \
void greatest_set_exact_name_match(void) {                              \
    greatest_info.exact_name_match = 1;                                 \
}                                                                       \
                                                                        \
void greatest_stop_at_first_fail(void) {                                \
    greatest_set_flag(GREATEST_FLAG_FIRST_FAIL);                        \
}                                                                       \
                                                                        \
void greatest_abort_on_fail(void) {                                     \
    greatest_set_flag(GREATEST_FLAG_ABORT_ON_FAIL);                     \
}                                                                       \
                                                                        \
void greatest_list_only(void) {                                         \
    greatest_set_flag(GREATEST_FLAG_LIST_ONLY);                         \
}                                                                       \
                                                                        \
void greatest_get_report(struct greatest_report_t *report) {            \
    if (report) {                                                       \
        report->passed = greatest_info.passed;                          \
        report->failed = greatest_info.failed;                          \
        report->skipped = greatest_info.skipped;                        \
        report->assertions = greatest_info.assertions;                  \
    }                                                                   \
}                                                                       \
                                                                        \
unsigned int greatest_get_verbosity(void) {                             \
    return greatest_info.verbosity;                                     \
}                                                                       \
                                                                        \
void greatest_set_verbosity(unsigned int verbosity) {                   \
    greatest_info.verbosity = (unsigned char)verbosity;                 \
}                                                                       \
                                                                        \
void greatest_set_flag(greatest_flag_t flag) {                          \
    greatest_info.flags = (unsigned char)(greatest_info.flags | flag);  \
}                                                                       \
                                                                        \
void greatest_set_test_suffix(const char *suffix) {                     \
    greatest_info.name_suffix = suffix;                                 \
}                                                                       \
                                                                        \
void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) {        \
    greatest_info.setup = cb;                                           \
    greatest_info.setup_udata = udata;                                  \
}                                                                       \
                                                                        \
void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) {  \
    greatest_info.teardown = cb;                                        \
    greatest_info.teardown_udata = udata;                               \
}                                                                       \
                                                                        \
static int greatest_string_equal_cb(const void *expd, const void *got,  \
    void *udata) {                                                      \
    size_t *size = (size_t *)udata;                                     \
    return (size != NULL                                                \
        ? (0 == strncmp((const char *)expd, (const char *)got, *size))  \
        : (0 == strcmp((const char *)expd, (const char *)got)));        \
}                                                                       \
                                                                        \
static int greatest_string_printf_cb(const void *t, void *udata) {      \
    (void)udata; /* note: does not check \0 termination. */             \
    return GREATEST_FPRINTF(GREATEST_STDOUT, "%s", (const char *)t);    \
}                                                                       \
                                                                        \
greatest_type_info greatest_type_info_string = {                        \
    greatest_string_equal_cb, greatest_string_printf_cb,                \
};                                                                      \
                                                                        \
static int greatest_memory_equal_cb(const void *expd, const void *got,  \
    void *udata) {                                                      \
    greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata;    \
    return (0 == memcmp(expd, got, env->size));                         \
}                                                                       \
                                                                        \
/* Hexdump raw memory, with differences highlighted */                  \
static int greatest_memory_printf_cb(const void *t, void *udata) {      \
    greatest_memory_cmp_env *env = (greatest_memory_cmp_env *)udata;    \
    const unsigned char *buf = (const unsigned char *)t;                \
    unsigned char diff_mark = ' ';                                      \
    FILE *out = GREATEST_STDOUT;                                        \
    size_t i, line_i, line_len = 0;                                     \
    int len = 0;   /* format hexdump with differences highlighted */    \
    for (i = 0; i < env->size; i+= line_len) {                          \
        diff_mark = ' ';                                                \
        line_len = env->size - i;                                       \
        if (line_len > 16) { line_len = 16; }                           \
        for (line_i = i; line_i < i + line_len; line_i++) {             \
            if (env->exp[line_i] != env->got[line_i]) diff_mark = 'X';  \
        }                                                               \
        len += GREATEST_FPRINTF(out, "\n%04x %c ",                      \
            (unsigned int)i, diff_mark);                                \
        for (line_i = i; line_i < i + line_len; line_i++) {             \
            int m = env->exp[line_i] == env->got[line_i]; /* match? */  \
            len += GREATEST_FPRINTF(out, "%02x%c",                      \
                buf[line_i], m ? ' ' : '<');                            \
        }                                                               \
        for (line_i = 0; line_i < 16 - line_len; line_i++) {            \
            len += GREATEST_FPRINTF(out, "   ");                        \
        }                                                               \
        GREATEST_FPRINTF(out, " ");                                     \
        for (line_i = i; line_i < i + line_len; line_i++) {             \
            unsigned char c = buf[line_i];                              \
            len += GREATEST_FPRINTF(out, "%c", isprint(c) ? c : '.');   \
        }                                                               \
    }                                                                   \
    len += GREATEST_FPRINTF(out, "\n");                                 \
    return len;                                                         \
}                                                                       \
                                                                        \
void greatest_prng_init_first_pass(int id) {                            \
    greatest_info.prng[id].random_order = 1;                            \
    greatest_info.prng[id].count_run = 0;                               \
}                                                                       \
                                                                        \
int greatest_prng_init_second_pass(int id, unsigned long seed) {        \
    struct greatest_prng *p = &greatest_info.prng[id];                  \
    if (p->count == 0) { return 0; }                                    \
    p->count_ceil = p->count;                                           \
    for (p->m = 1; p->m < p->count; p->m <<= 1) {}                      \
    p->state = seed & 0x1fffffff;     /* only use lower 29 bits */      \
    p->a = 4LU * p->state;            /* to avoid overflow when */      \
    p->a = (p->a ? p->a : 4) | 1;            /* multiplied by 4 */      \
    p->c = 2147483647;        /* and so p->c ((2 ** 31) - 1) is */      \
    p->initialized = 1;     /* always relatively prime to p->a. */      \
    fprintf(stderr, "init_second_pass: a %lu, c %lu, state %lu\n",      \
        p->a, p->c, p->state);                                          \
    return 1;                                                           \
}                                                                       \
                                                                        \
/* Step the pseudorandom number generator until its state reaches       \
 * another test ID between 0 and the test count.                        \
 * This use a linear congruential pseudorandom number generator,        \
 * with the power-of-two ceiling of the test count as the modulus, the  \
 * masked seed as the multiplier, and a prime as the increment. For     \
 * each generated value < the test count, run the corresponding test.   \
 * This will visit all IDs 0 <= X < mod once before repeating,          \
 * with a starting position chosen based on the initial seed.           \
 * For details, see: Knuth, The Art of Computer Programming             \
 * Volume. 2, section 3.2.1. */                                         \
void greatest_prng_step(int id) {                                       \
    struct greatest_prng *p = &greatest_info.prng[id];                  \
    do {                                                                \
        p->state = ((p->a * p->state) + p->c) & (p->m - 1);             \
    } while (p->state >= p->count_ceil);                                \
}                                                                       \
                                                                        \
void GREATEST_INIT(void) {                                              \
    /* Suppress unused function warning if features aren't used */      \
    (void)greatest_run_suite;                                           \
    (void)greatest_parse_options;                                       \
    (void)greatest_prng_step;                                           \
    (void)greatest_prng_init_first_pass;                                \
    (void)greatest_prng_init_second_pass;                               \
    (void)greatest_set_test_suffix;                                     \
                                                                        \
    memset(&greatest_info, 0, sizeof(greatest_info));                   \
    greatest_info.width = GREATEST_DEFAULT_WIDTH;                       \
    GREATEST_SET_TIME(greatest_info.begin);                             \
}                                                                       \
                                                                        \
/* Report passes, failures, skipped tests, the number of                \
 * assertions, and the overall run time. */                             \
void GREATEST_PRINT_REPORT(void) {                                      \
    if (!GREATEST_LIST_ONLY()) {                                        \
        update_counts_and_reset_suite();                                \
        GREATEST_SET_TIME(greatest_info.end);                           \
        GREATEST_FPRINTF(GREATEST_STDOUT,                               \
            "\nTotal: %u test%s",                                       \
            greatest_info.tests_run,                                    \
            greatest_info.tests_run == 1 ? "" : "s");                   \
        GREATEST_CLOCK_DIFF(greatest_info.begin,                        \
            greatest_info.end);                                         \
        GREATEST_FPRINTF(GREATEST_STDOUT, ", %u assertion%s\n",         \
            greatest_info.assertions,                                   \
            greatest_info.assertions == 1 ? "" : "s");                  \
        GREATEST_FPRINTF(GREATEST_STDOUT,                               \
            "Pass: %u, fail: %u, skip: %u.\n",                          \
            greatest_info.passed,                                       \
            greatest_info.failed, greatest_info.skipped);               \
    }                                                                   \
}                                                                       \
                                                                        \
greatest_type_info greatest_type_info_memory = {                        \
    greatest_memory_equal_cb, greatest_memory_printf_cb,                \
};                                                                      \
                                                                        \
greatest_run_info greatest_info

/* Handle command-line arguments, etc. */
#define GREATEST_MAIN_BEGIN()                                           \
    do {                                                                \
        GREATEST_INIT();                                                \
        greatest_parse_options(argc, argv);                             \
    } while (0)

/* Report results, exit with exit status based on results. */
#define GREATEST_MAIN_END()                                             \
    do {                                                                \
        GREATEST_PRINT_REPORT();                                        \
        return (greatest_all_passed() ? EXIT_SUCCESS : EXIT_FAILURE);   \
    } while (0)

/* Make abbreviations without the GREATEST_ prefix for the
 * most commonly used symbols. */
#if GREATEST_USE_ABBREVS
#define TEST           GREATEST_TEST
#define SUITE          GREATEST_SUITE
#define SUITE_EXTERN   GREATEST_SUITE_EXTERN
#define RUN_TEST       GREATEST_RUN_TEST
#define RUN_TEST1      GREATEST_RUN_TEST1
#define RUN_SUITE      GREATEST_RUN_SUITE
#define IGNORE_TEST    GREATEST_IGNORE_TEST
#define ASSERT         GREATEST_ASSERT
#define ASSERTm        GREATEST_ASSERTm
#define ASSERT_FALSE   GREATEST_ASSERT_FALSE
#define ASSERT_EQ      GREATEST_ASSERT_EQ
#define ASSERT_NEQ     GREATEST_ASSERT_NEQ
#define ASSERT_GT      GREATEST_ASSERT_GT
#define ASSERT_GTE     GREATEST_ASSERT_GTE
#define ASSERT_LT      GREATEST_ASSERT_LT
#define ASSERT_LTE     GREATEST_ASSERT_LTE
#define ASSERT_EQ_FMT  GREATEST_ASSERT_EQ_FMT
#define ASSERT_IN_RANGE GREATEST_ASSERT_IN_RANGE
#define ASSERT_EQUAL_T GREATEST_ASSERT_EQUAL_T
#define ASSERT_STR_EQ  GREATEST_ASSERT_STR_EQ
#define ASSERT_STRN_EQ GREATEST_ASSERT_STRN_EQ
#define ASSERT_MEM_EQ  GREATEST_ASSERT_MEM_EQ
#define ASSERT_ENUM_EQ GREATEST_ASSERT_ENUM_EQ
#define ASSERT_FALSEm  GREATEST_ASSERT_FALSEm
#define ASSERT_EQm     GREATEST_ASSERT_EQm
#define ASSERT_NEQm    GREATEST_ASSERT_NEQm
#define ASSERT_GTm     GREATEST_ASSERT_GTm
#define ASSERT_GTEm    GREATEST_ASSERT_GTEm
#define ASSERT_LTm     GREATEST_ASSERT_LTm
#define ASSERT_LTEm    GREATEST_ASSERT_LTEm
#define ASSERT_EQ_FMTm GREATEST_ASSERT_EQ_FMTm
#define ASSERT_IN_RANGEm GREATEST_ASSERT_IN_RANGEm
#define ASSERT_EQUAL_Tm GREATEST_ASSERT_EQUAL_Tm
#define ASSERT_STR_EQm GREATEST_ASSERT_STR_EQm
#define ASSERT_STRN_EQm GREATEST_ASSERT_STRN_EQm
#define ASSERT_MEM_EQm GREATEST_ASSERT_MEM_EQm
#define ASSERT_ENUM_EQm GREATEST_ASSERT_ENUM_EQm
#define PASS           GREATEST_PASS
#define FAIL           GREATEST_FAIL
#define SKIP           GREATEST_SKIP
#define PASSm          GREATEST_PASSm
#define FAILm          GREATEST_FAILm
#define SKIPm          GREATEST_SKIPm
#define SET_SETUP      GREATEST_SET_SETUP_CB
#define SET_TEARDOWN   GREATEST_SET_TEARDOWN_CB
#define CHECK_CALL     GREATEST_CHECK_CALL
#define SHUFFLE_TESTS  GREATEST_SHUFFLE_TESTS
#define SHUFFLE_SUITES GREATEST_SHUFFLE_SUITES

#ifdef GREATEST_VA_ARGS
#define RUN_TESTp      GREATEST_RUN_TESTp
#endif

#if GREATEST_USE_LONGJMP
#define ASSERT_OR_LONGJMP  GREATEST_ASSERT_OR_LONGJMP
#define ASSERT_OR_LONGJMPm GREATEST_ASSERT_OR_LONGJMPm
#define FAIL_WITH_LONGJMP  GREATEST_FAIL_WITH_LONGJMP
#define FAIL_WITH_LONGJMPm GREATEST_FAIL_WITH_LONGJMPm
#endif

#endif /* USE_ABBREVS */

#if defined(__cplusplus) && !defined(GREATEST_NO_EXTERN_CPLUSPLUS)
}
#endif

#endif


================================================
FILE: test/test_tinf.c
================================================
/*
 * tinf unit test
 *
 * Copyright (c) 2014-2022 Joergen Ibsen
 *
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 *   1. The origin of this software must not be misrepresented; you must
 *      not claim that you wrote the original software. If you use this
 *      software in a product, an acknowledgment in the product
 *      documentation would be appreciated but is not required.
 *
 *   2. Altered source versions must be plainly marked as such, and must
 *      not be misrepresented as being the original software.
 *
 *   3. This notice may not be removed or altered from any source
 *      distribution.
 */

#include "tinf.h"

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include "greatest.h"

#ifndef ARRAY_SIZE
#  define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#endif

static const unsigned char robuffer[] = { 0 };

static unsigned char buffer[4096];

struct packed_data {
	unsigned int src_size;
	unsigned int depacked_size;
	const unsigned char data[32];
};

static const struct packed_data inflate_errors[] = {
	/* Unable to read first byte */
	{ 0, 1, { 0x42 } },
	/* No next block after non-final block */
	{ 5, 1, { 0x00, 0x00, 0x00, 0xFF, 0xFF } },
	/* Invalid block type 11 */
	{ 13, 1, { 0x07, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xFF, 0x6B, 0x01, 0x00 } },

	/* Uncompressed block incomplete */
	{ 4, 1, { 0x01, 0x00, 0x00, 0xFF } },
	/* Uncompressed block inv length wrong */
	{ 5, 1, { 0x01, 0x00, 0x00, 0x00, 0x00 } },
	/* Uncompressed block missing data */
	{ 5, 1, { 0x01, 0x01, 0x00, 0xFE, 0xFF } },
	/* Uncompressed block writing one past end */
	{ 7, 1, { 0x01, 0x02, 0x00, 0xFD, 0xFF, 0x42, 0x42 } },

	/* Fixed incomplete */
	{ 2, 1, { 0x63, 0x00 } },
	/* Fixed reading one byte before start */
	{ 4, 4, { 0x63, 0x00, 0x42, 0x00 } },
	/* Fixed literal writing one byte past end */
	{ 4, 1, { 0x63, 0x60, 0x00, 0x00 } },
	/* Fixed match writing one byte past end */
	{ 4, 3, { 0x63, 0x00, 0x02, 0x00 } },
	/* Fixed len > 285 */
	{ 4, 1024, { 0x63, 0x18, 0x03, 0x00 } },
	/* Fixed dist > 29 */
	{ 4, 4, { 0x63, 0x00, 0x3E, 0x00 } },

	/* Dynamic incomplete no HDIST */
	{ 1, 1, { 0x05 } },
	/* Dynamic incomplete HCLEN */
	{ 2, 1, { 0x05, 0x00 } },
	/* Dynamic incomplete code length code lengths */
	{ 4, 1, { 0x05, 0x40, 0x00, 0x04 } },
	/* Dynamic code length code lengths all zero*/
	{ 6, 1, { 0x05, 0x0B, 0x00, 0x00, 0x00, 0x00 } },
	/* Dynamic incomplete literal code lengths */
	{ 4, 1, { 0x05, 0x20, 0x00, 0x04 } },
	/* Dynamic 256 has code length 0 */
	{ 13, 1, { 0x05, 0xCB, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF, 0xD7, 0x02, 0x00 } },
	/* Dynamic only 256 available, but data contains 1 bit */
	{ 13, 1, { 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x7F, 0xEB, 0x00, 0x02 } },
	/* Dynamic only one distance code, but compressed data contains 1 bit */
	{ 13, 4, { 0x0D, 0xC0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x3F, 0x0F } },
	/* Dynamic all distance codes zero, but compressed data contains match */
	{ 14, 4, { 0x0D, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x1F, 0xC0, 0x02 } },
	/* Dynamic only one code length code length, but compressed data contains 1 bit */
	{ 8, 4, { 0x05, 0x00, 0x80, 0xC0, 0xBF, 0x37, 0x00, 0x00 } },
	/* Dynamic first code length code is copy prev length  */
	{ 13, 1, { 0x05, 0xCA, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xF1, 0x87, 0x0E, 0x00 } },
	/* Dynamic underfull code length in code length code (missing len 2 code) */
	{ 13, 1, { 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x7F, 0xEB, 0x00, 0x00 } },
	/* Dynamic overfull code length in code length code (extra len 2 code) */
	{ 13, 1, { 0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x82, 0x20, 0x7F, 0xEB, 0x00, 0x00 } },
	/* Dynamic overfull code length in literal/length code (extra len 1 codes) */
	{ 15, 4, { 0x0D, 0xC3, 0x37, 0x01, 0x00, 0x00, 0x00, 0x80, 0x20, 0x46, 0xFF, 0xCE, 0xCA, 0x61, 0x01 } },
	/* Dynamic underfull code length in distance code (missing len 2 code) */
	{ 14, 4, { 0x0D, 0xCE, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFD, 0xA9, 0xBB, 0x09, 0x1A } },
	/* Dynamic overfull code length in distance code (extra len 2 code) */
	{ 15, 4, { 0x0D, 0xCE, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFD, 0xA9, 0xBB, 0x1F, 0xA0, 0x01 } },
	/* Dynamic HLIT too large (30 = 287) */
	{ 15, 4, { 0xF5, 0xCB, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x9F, 0x24, 0x00, 0x01 } },
	/* Dynamic HDIST too large (30 = 31) */
	{ 15, 4, { 0xED, 0xDE, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC, 0xA9, 0x5F, 0x24, 0x13, 0x01 } },
	/* Dynamic number of literal/length codes too large (last repeat exceeds limit) */
	{ 15, 4, { 0x0D, 0xCB, 0x37, 0x01, 0x00, 0x00, 0x00, 0x80, 0x20, 0xFA, 0xA7, 0x56, 0x08, 0x60, 0x01 } }
};

static const struct packed_data zlib_errors[] = {
	/* Too short (not enough room for 2 byte header and 4 byte trailer) */
	{ 5, 1, { 0x78, 0x9C, 0x63, 0x00, 0x00 } },
	/* Too short, but last 4 bytes are valid Adler-32 */
	{ 8, 1, { 0x78, 0x9C, 0x63, 0x04, 0x00, 0x02, 0x00, 0x02 } },
	/* Header checksum error */
	{ 9, 1, { 0x78, 0x9D, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } },
	/* Method not deflate */
	{ 9, 1, { 0x74, 0x9D, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } },
	/* Window size invalid */
	{ 9, 1, { 0x88, 0x98, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } },
	/* Preset dictionary (not supported by tinf) */
	{ 13, 1, { 0x78, 0xBB, 0x00, 0x00, 0x00, 0x01, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } },

	/* Adler-32 checksum does not match value in trailer */
	{ 9, 1, { 0x78, 0x9C, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },

	/* Decompression error (bad block type) */
	{ 9, 1, { 0x78, 0x9C, 0x67, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01 } }
};

static const struct packed_data gzip_errors[] = {
	/* Too short (not enough room for 10 byte header and 8 byte trailer) */
	{ 17, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2 } },
	/* Too short, but last 8 bytes are valid CRC32 and size */
	{ 19, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
	/* Error in first id byte */
	{ 21, 1, { 0x1E, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } },
	/* Error in second id byte */
	{ 21, 1, { 0x1F, 0x8A, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } },
	/* Method not deflate */
	{ 21, 1, { 0x1F, 0x8B, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } },
	/* Reserved flag bit set */
	{ 21, 1, { 0x1F, 0x8B, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } },
	/* Header CRC16 error */
	{ 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 } },
	/* Header CRC16 exceeds input size */
	{ 19, 1, { 0x1F, 0x8B, 0x08, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x00, 0x2E } },
	/* Filename exceeds input size */
	{ 19, 1, { 0x1F, 0x8B, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 } },
	/* Comment exceeds input size */
	{ 19, 1, { 0x1F, 0x8B, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39 } },
	/* Extra data exceeds input size */
	{ 19, 1, { 0x1F, 0x8B, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x08, 0x00, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37 } },
	/* Not enough room for trailer after comment */
	{ 19, 1, { 0x1F, 0x8B, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x00 } },

	/* Decompressed size does not match size in trailer */
	{ 21, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x02, 0x00, 0x00, 0x00 } },
	/* CRC32 checksum does not match value in trailer */
	{ 21, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x63, 0x00, 0x00, 0x8D, 0xEF, 0x01, 0xD2, 0x01, 0x00, 0x00, 0x00 } },

	/* Decompression error (bad block type) */
	{ 21, 1, { 0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B, 0x67, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00 } }
};

/* tinflate */

TEST inflate_padding(void)
{
	/* Empty buffer, fixed, 6 bits of padding in the second byte set to 1 */
	static const unsigned char data[] = {
		0x03, 0xFC
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST inflate_empty_no_literals(void)
{
	/* Empty buffer, dynamic with 256 as only literal/length code
	 *
	 * You could argue that since the RFC only has an exception allowing
	 * one symbol for the distance tree, the literal/length tree should
	 * be complete. However gzip allows this.
	 *
	 * See also: https://github.com/madler/zlib/issues/75
	 */
	static const unsigned char data[] = {
		0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xFF,
		0x6B, 0x01, 0x00
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST inflate_huffman_only(void)
{
	/* 256 zero bytes compressed using Huffman only (no match or distance codes) */
	static const unsigned char data[] = {
		0x05, 0xCA, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF,
		0xD5, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x02
	};
	unsigned char out[256];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	PASS();
}

TEST inflate_rle(void)
{
	/* 256 zero bytes compressed using RLE (only one distance code) */
	static const unsigned char data[] = {
		0xE5, 0xC0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC,
		0xA9, 0x07, 0x39, 0x73, 0x01
	};
	unsigned char out[256];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	PASS();
}

TEST inflate_max_matchlen(void)
{
	/* 259 zero bytes compressed using literal/length code 285 (len 258) */
	static const unsigned char data[] = {
		0xED, 0xCC, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC,
		0xA9, 0x17, 0xB9, 0x00, 0x2C
	};
	unsigned char out[259];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	PASS();
}

TEST inflate_max_matchlen_alt(void)
{
	/* 259 zero bytes compressed using literal/length code 284 + 31 (len 258)
	 *
	 * Technically, this is outside the range specified in the RFC, but
	 * gzip allows it.
	 *
	 * See also: https://github.com/madler/zlib/issues/75
	 */
	static const unsigned char data[] = {
		0xE5, 0xCC, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80, 0xA0, 0xFC,
		0xA9, 0x07, 0xB9, 0x00, 0xFC, 0x05
	};
	unsigned char out[259];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	PASS();
}

TEST inflate_max_matchdist(void)
{
	/* A match of length 3 with a distance of 32768 */
	static const unsigned char data[] = {
		0xED, 0xDD, 0x01, 0x01, 0x00, 0x00, 0x08, 0x02, 0x20, 0xED,
		0xFF, 0xE8, 0xFA, 0x11, 0x1C, 0x61, 0x9A, 0xF7, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0,
		0xFE, 0xFF, 0x05
	};
	unsigned char out[32771];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	ASSERT(out[0] == 2 && out[1] == 1 && out[2] == 0);

	for (i = 3; i < ARRAY_SIZE(out) - 3; ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	ASSERT(out[ARRAY_SIZE(out) - 3] == 2);
	ASSERT(out[ARRAY_SIZE(out) - 2] == 1);
	ASSERT(out[ARRAY_SIZE(out) - 1] == 0);

	PASS();
}

TEST inflate_code_length_codes(void)
{
	/* 4 zero bytes compressed, code length codes include codes 16, 17, and 18 */
	static const unsigned char data[] = {
		0x0D, 0xC3, 0x37, 0x01, 0x00, 0x00, 0x00, 0x80, 0x20, 0xFA,
		0x77, 0x1E, 0xCA, 0x61, 0x01
	};
	unsigned char out[4];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	PASS();
}

TEST inflate_max_codelen(void)
{
	/* Use all codeword lengths including 15 */
	static const unsigned char data[] = {
		0x05, 0xEA, 0x01, 0x82, 0x24, 0x49, 0x92, 0x24, 0x49, 0x02,
		0x12, 0x8B, 0x9A, 0x47, 0x56, 0xCF, 0xDE, 0xFF, 0x9F, 0x7B,
		0x0F, 0xD0, 0xEE, 0x7D, 0xBF, 0xBF, 0x7F, 0xFF, 0xFD, 0xEF,
		0xFF, 0xFE, 0xDF, 0xFF, 0xF7, 0xFF, 0xFB, 0xFF, 0x03
	};
	unsigned char out[15];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i] != i) {
			FAIL();
		}
	}

	PASS();
}

/* Test tinf_uncompress on random data */
TEST inflate_random(void)
{
	unsigned char data[256];
	unsigned int len;

	for (len = 1; len < ARRAY_SIZE(data); ++len) {
		unsigned int dlen = ARRAY_SIZE(buffer);
		size_t i;

		for (i = 0; i < len; ++i) {
			data[i] = (unsigned char) rand();
		}

		/* Make sure btype is valid */
		if ((data[0] & 0x06) == 0x06) {
			data[0] &= (rand() > RAND_MAX / 2) ? ~0x02 : ~0x04;
		}

		tinf_uncompress(buffer, &dlen, data, len);
	}

	PASS();
}

/* Test tinf_uncompress on compressed data with errors */
TEST inflate_error_case(const void *closure)
{
	const struct packed_data *pd = (const struct packed_data *) closure;
	int res;

	unsigned int size = pd->depacked_size;
	res = tinf_uncompress(buffer, &size, pd->data, pd->src_size);

	ASSERT(res != TINF_OK);

	PASS();
}

SUITE(tinflate)
{
	char suffix[32];
	size_t i;

	RUN_TEST(inflate_padding);
	RUN_TEST(inflate_empty_no_literals);
	RUN_TEST(inflate_huffman_only);
	RUN_TEST(inflate_rle);
	RUN_TEST(inflate_max_matchlen);
	RUN_TEST(inflate_max_matchlen_alt);
	RUN_TEST(inflate_max_matchdist);
	RUN_TEST(inflate_code_length_codes);
	RUN_TEST(inflate_max_codelen);

	RUN_TEST(inflate_random);

	for (i = 0; i < ARRAY_SIZE(inflate_errors); ++i) {
		sprintf(suffix, "%d", (int) i);
		greatest_set_test_suffix(suffix);
		RUN_TEST1(inflate_error_case, &inflate_errors[i]);
	}
}

/* tinfzlib */

TEST zlib_empty_raw(void)
{
	/* Empty buffer, uncompressed */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00,
		0x01
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_zlib_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST zlib_empty_fixed(void)
{
	/* Empty buffer, fixed Huffman */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_zlib_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST zlib_empty_dynamic(void)
{
	/* Empty buffer, dynamic Huffman */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x10, 0xFF, 0xD5, 0x08, 0x00, 0x00, 0x00, 0x01
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_zlib_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST zlib_onebyte_raw(void)
{
	/* One byte 00, uncompressed */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x01, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x00, 0x01,
		0x00, 0x01
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST zlib_onebyte_fixed(void)
{
	/* One byte 00, fixed Huffman */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x63, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST zlib_onebyte_dynamic(void)
{
	/* One byte 00, dynamic Huffman */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x10, 0xFF, 0xD5, 0x10, 0x00, 0x01, 0x00, 0x01
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST zlib_zeroes(void)
{
	/* 256 zero bytes, to test unrolling in Adler-32 */
	static const unsigned char data[] = {
		0x78, 0x9C, 0x63, 0x60, 0x18, 0xD9, 0x00, 0x00, 0x01, 0x00,
		0x00, 0x01
	};
	unsigned char out[256];
	unsigned int dlen = ARRAY_SIZE(out);
	int res;
	size_t i;

	memset(out, 0xFF, ARRAY_SIZE(out));

	res = tinf_zlib_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == ARRAY_SIZE(out));

	for (i = 0; i < ARRAY_SIZE(out); ++i) {
		if (out[i]) {
			FAIL();
		}
	}

	PASS();
}

/* Test tinf_zlib_uncompress on compressed data with errors */
TEST zlib_error_case(const void *closure)
{
	const struct packed_data *pd = (const struct packed_data *) closure;
	int res;

	unsigned int size = pd->depacked_size;
	res = tinf_zlib_uncompress(buffer, &size, pd->data, pd->src_size);

	ASSERT(res != TINF_OK);

	PASS();
}

SUITE(tinfzlib)
{
	char suffix[32];
	size_t i;

	RUN_TEST(zlib_empty_raw);
	RUN_TEST(zlib_empty_fixed);
	RUN_TEST(zlib_empty_dynamic);

	RUN_TEST(zlib_onebyte_raw);
	RUN_TEST(zlib_onebyte_fixed);
	RUN_TEST(zlib_onebyte_dynamic);
	RUN_TEST(zlib_zeroes);

	for (i = 0; i < ARRAY_SIZE(zlib_errors); ++i) {
		sprintf(suffix, "%d", (int) i);
		greatest_set_test_suffix(suffix);
		RUN_TEST1(zlib_error_case, &zlib_errors[i]);
	}
}

/* tinfgzip */

TEST gzip_empty_raw(void)
{
	/* Empty buffer, uncompressed */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x01, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_gzip_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST gzip_empty_fixed(void)
{
	/* Empty buffer, fixed Huffman */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_gzip_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST gzip_empty_dynamic(void)
{
	/* Empty buffer, dynamic Huffman */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF,
		0xD5, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
	};
	unsigned int dlen = 0;
	int res;

	res = tinf_gzip_uncompress((void *) robuffer, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 0);

	PASS();
}

TEST gzip_onebyte_raw(void)
{
	/* One byte 00, uncompressed */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x01, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2,
		0x01, 0x00, 0x00, 0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST gzip_onebyte_fixed(void)
{
	/* One byte 00, fixed Huffman */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x63, 0x00, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00,
		0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST gzip_onebyte_dynamic(void)
{
	/* One byte 00, dynamic Huffman */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x05, 0xC1, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xFF,
		0xD5, 0x10, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST gzip_fhcrc(void)
{
	/* One byte 00, uncompressed, fhcrc */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x17, 0x9D, 0x01, 0x01, 0x00, 0xFE, 0xFF, 0x00, 0x8D, 0xEF,
		0x02, 0xD2, 0x01, 0x00, 0x00, 0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST gzip_fextra(void)
{
	/* One byte 00, uncompressed, fextra */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x04, 0x00, 0x64, 0x61, 0x74, 0x61, 0x01, 0x01, 0x00, 0xFE,
		0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST gzip_fname(void)
{
	/* One byte 00, uncompressed, fname */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x66, 0x6F, 0x6F, 0x2E, 0x63, 0x00, 0x01, 0x01, 0x00, 0xFE,
		0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

TEST gzip_fcomment(void)
{
	/* One byte 00, uncompressed, fcomment */
	static const unsigned char data[] = {
		0x1F, 0x8B, 0x08, 0x10, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B,
		0x68, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0x01, 0x01, 0x00, 0xFE,
		0xFF, 0x00, 0x8D, 0xEF, 0x02, 0xD2, 0x01, 0x00, 0x00, 0x00
	};
	unsigned char out[] = { 0xFF };
	unsigned int dlen = 1;
	int res;

	res = tinf_gzip_uncompress(out, &dlen, data, ARRAY_SIZE(data));

	ASSERT(res == TINF_OK && dlen == 1 && out[0] == 0);

	PASS();
}

/* Test tinf_gzip_uncompress on compressed data with errors */
TEST gzip_error_case(const void *closure)
{
	const struct packed_data *pd = (const struct packed_data *) closure;
	int res;

	unsigned int size = pd->depacked_size;
	res = tinf_gzip_uncompress(buffer, &size, pd->data, pd->src_size);

	ASSERT(res != TINF_OK);

	PASS();
}

SUITE(tinfgzip)
{
	char suffix[32];
	size_t i;

	RUN_TEST(gzip_empty_raw);
	RUN_TEST(gzip_empty_fixed);
	RUN_TEST(gzip_empty_dynamic);

	RUN_TEST(gzip_onebyte_raw);
	RUN_TEST(gzip_onebyte_fixed);
	RUN_TEST(gzip_onebyte_dynamic);

	RUN_TEST(gzip_fhcrc);
	RUN_TEST(gzip_fextra);
	RUN_TEST(gzip_fname);
	RUN_TEST(gzip_fcomment);

	for (i = 0; i < ARRAY_SIZE(gzip_errors); ++i) {
		sprintf(suffix, "%d", (int) i);
		greatest_set_test_suffix(suffix);
		RUN_TEST1(gzip_error_case, &gzip_errors[i]);
	}
}

GREATEST_MAIN_DEFS();

int main(int argc, char *argv[])
{
	GREATEST_MAIN_BEGIN();

	srand(time(NULL));

	tinf_init();

	RUN_SUITE(tinflate);
	RUN_SUITE(tinfzlib);
	RUN_SUITE(tinfgzip);

	GREATEST_MAIN_END();
}


================================================
FILE: tools/gengztest.py
================================================
#!/usr/bin/env python3

# Copyright (c) 2014-2019 Joergen Ibsen
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

"""
Gzip test file generator.

Generates gzip test files with specified fields in the header.
"""

import argparse
import struct
import zlib
import textwrap

def write_gzip(f, args):
    """Write gzip data to file f."""

    # gzip header
    data = bytearray.fromhex('1f 8b 08 00 00 00 00 00 02 0b')

    flags = 0

    if args.s:
        flags |= 2

    if args.extra:
        flags |= 4
        edata = args.extra.encode('ascii')
        data.extend(struct.pack('<H', len(edata)))
        data.extend(edata)

    if args.filename:
        flags |= 8
        data.extend(args.filename.encode('ascii'))
        data.extend(b'\x00')

    if args.comment:
        flags |= 16
        data.extend(args.comment.encode('ascii'))
        data.extend(b'\x00')

    data[3] = flags

    if args.s:
        # write low two bytes of CRC32 of header up to here
        data.extend(struct.pack('<H', zlib.crc32(data) & 0xffff))

    if args.data == 'empty':
        if args.method == 'raw':
            # empty buffer, uncompressed
            data.extend(bytes.fromhex('01 00 00 ff ff'))
        elif args.method == 'fixed':
            # empty buffer, fixed Huffman
            data.extend(bytes.fromhex('03 00'))
        elif args.method == 'dynamic':
            # empty buffer, dynamic Huffman
            data.extend(bytes.fromhex('05 c1 81 00 00 00 00 00 10 ff d5 08'))
        # CRC32 of empty buffer
        data.extend(struct.pack('<I', 0))
        # ISIZE 0
        data.extend(struct.pack('<I', 0))
    elif args.data == 'byte00':
        if args.method == 'raw':
            # one byte 00, uncompressed
            data.extend(bytes.fromhex('01 01 00 fe ff 00'))
        elif args.method == 'fixed':
            # one byte 00, fixed Huffman
            data.extend(bytes.fromhex('63 00 00'))
        elif args.method == 'dynamic':
            # one byte 00, dynamic Huffman
            data.extend(bytes.fromhex('05 c1 81 00 00 00 00 00 10 ff d5 10'))
        # CRC32 of one byte 00
        data.extend(struct.pack('<I', zlib.crc32(b'\x00')))
        # ISIZE 1
        data.extend(struct.pack('<I', 1))

    if args.i:
        s = textwrap.fill(', '.join('0x{:02X}'.format(b) for b in data))
        f.write(s.encode('utf-8'))
    else:
        f.write(data)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='gzip test file generator.')
    parser.add_argument('-f', '--filename', type=str, help='original filename')
    parser.add_argument('-c', '--comment', type=str, help='file comment')
    parser.add_argument('-e', '--extra', type=str, help='extra data')
    parser.add_argument('-d', '--data', type=str,
                        choices=['empty', 'byte00'], default='empty',
                        help='compressed data')
    parser.add_argument('-m', '--method', type=str,
                        choices=['raw', 'fixed', 'dynamic'], default='fixed',
                        help='compression method')
    parser.add_argument('-s', action='store_true', help='add header CRC16')
    parser.add_argument('-i', action='store_true', help='generate include file')
    parser.add_argument('outfile', type=argparse.FileType('wb'), help='output file')
    args = parser.parse_args()

    write_gzip(args.outfile, args)


================================================
FILE: tools/genzlibtest.py
================================================
#!/usr/bin/env python3

# Copyright (c) 2014-2019 Joergen Ibsen
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

"""
zlib test file generator.

Generates zlib test files with specified fields in the header.
"""

import argparse
import struct
import zlib
import textwrap

def write_zlib(f, args):
    """Write zlib data to file f."""

    # zlib header
    data = bytearray.fromhex('00 00')

    cmf = 8
    flg = 0

    if args.window_size:
        cmf |= args.window_size << 4

    if args.level:
        flg = args.level << 6

    if args.preset_dict:
        flg |= 1 << 5
        # Write Adler-32 of preset dictionary
        data.extend(struct.pack('>I', args.preset_dict))

    flg |= 31 - ((256 * cmf + flg) % 31)

    data[0] = cmf
    data[1] = flg

    if args.data == 'empty':
        if args.method == 'raw':
            # empty buffer, uncompressed
            data.extend(bytes.fromhex('01 00 00 ff ff'))
        elif args.method == 'fixed':
            # empty buffer, fixed Huffman
            data.extend(bytes.fromhex('03 00'))
        elif args.method == 'dynamic':
            # empty buffer, dynamic Huffman
            data.extend(bytes.fromhex('05 c1 81 00 00 00 00 00 10 ff d5 08'))
        # Adler-32 of empty buffer
        data.extend(struct.pack('>I', 1))
    elif args.data == 'byte00':
        if args.method == 'raw':
            # one byte 00, uncompressed
            data.extend(bytes.fromhex('01 01 00 fe ff 00'))
        elif args.method == 'fixed':
            # one byte 00, fixed Huffman
            data.extend(bytes.fromhex('63 00 00'))
        elif args.method == 'dynamic':
            # one byte 00, dynamic Huffman
            data.extend(bytes.fromhex('05 c1 81 00 00 00 00 00 10 ff d5 10'))
        # Adler-32 of one byte 00
        data.extend(struct.pack('>I', zlib.adler32(b'\x00')))

    if args.i:
        s = textwrap.fill(', '.join('0x{:02X}'.format(b) for b in data))
        f.write(s.encode('utf-8'))
    else:
        f.write(data)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='zlib test file generator.')
    parser.add_argument('-d', '--data', type=str,
                        choices=['empty', 'byte00'], default='empty',
                        help='compressed data')
    parser.add_argument('-m', '--method', type=str,
                        choices=['raw', 'fixed', 'dynamic'], default='fixed',
                        help='compression method')
    parser.add_argument('-l', '--level', type=int,
                        choices=range(0, 4), default=2,
                        help='compression level')
    parser.add_argument('-w', '--window_size', type=int,
                        choices=range(0, 8), default=7,
                        help='window size')
    parser.add_argument('-p', '--preset_dict', type=int,
                        help='preset dictionary Adler-32')
    parser.add_argument('-i', action='store_true', help='generate include file')
    parser.add_argument('outfile', type=argparse.FileType('wb'), help='output file')
    args = parser.parse_args()

    write_zlib(args.outfile, args)


================================================
FILE: tools/mkzdata.c
================================================
/*
 * mkzdata - generate deflate compressed data testcases
 *
 * Copyright (c) 2014-2019 Joergen Ibsen
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "tinf.h"

#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

struct lsb_bitwriter {
	unsigned char *next_out;
	uint32_t tag;
	int bitcount;
};

static void
lbw_init(struct lsb_bitwriter *lbw, unsigned char *dst)
{
	lbw->next_out = dst;
	lbw->tag = 0;
	lbw->bitcount = 0;
}

static unsigned char*
lbw_finalize(struct lsb_bitwriter *lbw)
{
	/* Write bytes until no bits left in tag */
	while (lbw->bitcount > 0) {
		*lbw->next_out++ = lbw->tag;
		lbw->tag >>= 8;
		lbw->bitcount -= 8;
	}

	return lbw->next_out;
}

static void
lbw_flush(struct lsb_bitwriter *lbw, int num) {
	assert(num >= 0 && num <= 32);

	/* Write bytes until at least num bits free */
	while (lbw->bitcount > 32 - num) {
		*lbw->next_out++ = lbw->tag;
		lbw->tag >>= 8;
		lbw->bitcount -= 8;
	}

	assert(lbw->bitcount >= 0);
}

static void
lbw_putbits_no_flush(struct lsb_bitwriter *lbw, uint32_t bits, int num) {
	assert(num >= 0 && num <= 32 - lbw->bitcount);
	assert((bits & (~0ULL << num)) == 0);

	/* Add bits to tag */
	lbw->tag |= bits << lbw->bitcount;
	lbw->bitcount += num;
}

static void
lbw_putbits(struct lsb_bitwriter *lbw, uint32_t bits, int num) {
	lbw_flush(lbw, num);
	lbw_putbits_no_flush(lbw, bits, num);
}

static void
lbw_putbits_rev(struct lsb_bitwriter *lbw, uint32_t bits, int num) {
	lbw_flush(lbw, num);
	while (num-- > 0) {
		lbw_putbits_no_flush(lbw, (bits >> num) & 1, 1);
	}
}

// 256 00 bytes compressed with Z_RLE (one distance code)
void
write_256_rle(struct lsb_bitwriter *lbw)
{
	// bfinal
	lbw_putbits(lbw, 1, 1);

	// btype
	lbw_putbits(lbw, 2, 2);

	// hlit
	lbw_putbits(lbw, 28, 5);

	// hdist
	lbw_putbits(lbw, 0, 5);

	// hclen
	lbw_putbits(lbw, 14, 4);

	lbw_putbits(lbw, 0, 3); // 16
	lbw_putbits(lbw, 0, 3); // 17
	lbw_putbits(lbw, 1, 3); // 18
	lbw_putbits(lbw, 0, 3); // 0
	lbw_putbits(lbw, 0, 3); // 8
	lbw_putbits(lbw, 0, 3); // 7
	lbw_putbits(lbw, 0, 3); // 9
	lbw_putbits(lbw, 0, 3); // 6
	lbw_putbits(lbw, 0, 3); // 10
	lbw_putbits(lbw, 0, 3); // 5
	lbw_putbits(lbw, 0, 3); // 11
	lbw_putbits(lbw, 0, 3); // 4
	lbw_putbits(lbw, 0, 3); // 12
	lbw_putbits(lbw, 0, 3); // 3
	lbw_putbits(lbw, 0, 3); // 13
	lbw_putbits(lbw, 2, 3); // 2
	lbw_putbits(lbw, 0, 3); // 14
	lbw_putbits(lbw, 2, 3); // 1

	// code lengths for literal/length
	lbw_putbits_rev(lbw, 2, 2); // 0 has len 1

	lbw_putbits_rev(lbw, 0, 1); // repeat len 0 for 138 times
	lbw_putbits(lbw, 127, 7);

	lbw_putbits_rev(lbw, 0, 1); // repeat len 0 for 117 times
	lbw_putbits(lbw, 106, 7);

	lbw_putbits_rev(lbw, 3, 2); // 256 has len 2

	lbw_putbits_rev(lbw, 0, 1); // repeat len 0 for 27 times
	lbw_putbits(lbw, 16, 7);

	lbw_putbits_rev(lbw, 3, 2); // 284 has len 2

	// code lengths for distance
	lbw_putbits_rev(lbw, 2, 2); // 1 has len 1

	// compressed data
	lbw_putbits_rev(lbw, 0, 1); // 00 byte

	lbw_putbits_rev(lbw, 3, 2); // match len 255
	lbw_putbits(lbw, 28, 5);

	lbw_putbits_rev(lbw, 0, 1); // distance 1

	// end of block
	lbw_putbits_rev(lbw, 2, 2); // 256 = EOB
}

// 256 00 bytes compressed with Z_HUFFMAN_ONLY (no distance codes)
void
write_256_huffman(struct lsb_bitwriter *lbw)
{
	// bfinal
	lbw_putbits(lbw, 1, 1);

	// btype
	lbw_putbits(lbw, 2, 2);

	// hlit
	lbw_putbits(lbw, 0, 5);

	// hdist
	lbw_putbits(lbw, 10, 5);

	// hclen
	lbw_putbits(lbw, 14, 4);

	lbw_putbits(lbw, 0, 3); // 16
	lbw_putbits(lbw, 0, 3); // 17
	lbw_putbits(lbw, 1, 3); // 18
	lbw_putbits(lbw, 0, 3); // 0
	lbw_putbits(lbw, 0, 3); // 8
	lbw_putbits(lbw, 0, 3); // 7
	lbw_putbits(lbw, 0, 3); // 9
	lbw_putbits(lbw, 0, 3); // 6
	lbw_putbits(lbw, 0, 3); // 10
	lbw_putbits(lbw, 0, 3); // 5
	lbw_putbits(lbw, 0, 3); // 11
	lbw_putbits(lbw, 0, 3); // 4
	lbw_putbits(lbw, 0, 3); // 12
	lbw_putbits(lbw, 0, 3); // 3
	lbw_putbits(lbw, 0, 3); // 13
	lbw_putbits(lbw, 0, 3); // 2
	lbw_putbits(lbw, 0, 3); // 14
	lbw_putbits(lbw, 1, 3); // 1

	// code lengths for literal/length
	lbw_putbits_rev(lbw, 0, 1); // 0 has len 1

	lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 138 times
	lbw_putbits(lbw, 127, 7);

	lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 117 times
	lbw_putbits(lbw, 106, 7);

	lbw_putbits_rev(lbw, 0, 1); // 256 has len 1

	// code lengths for distance
	lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 11 times
	lbw_putbits(lbw, 0, 7);

	// compressed data
	for (int i = 0; i < 256; ++i) {
		lbw_putbits_rev(lbw, 0, 1); // 00 byte
	}

	// end of block
	lbw_putbits_rev(lbw, 1, 1); // 256 = EOB
}

// empty with no literal symbols and no distance codes (only 256 has len 1)
void
write_no_lit(struct lsb_bitwriter *lbw)
{
	// bfinal
	lbw_putbits(lbw, 1, 1);

	// btype
	lbw_putbits(lbw, 2, 2);

	// hlit
	lbw_putbits(lbw, 0, 5);

	// hdist
	lbw_putbits(lbw, 10, 5);

	// hclen
	lbw_putbits(lbw, 14, 4);

	lbw_putbits(lbw, 0, 3); // 16
	lbw_putbits(lbw, 0, 3); // 17
	lbw_putbits(lbw, 1, 3); // 18
	lbw_putbits(lbw, 0, 3); // 0
	lbw_putbits(lbw, 0, 3); // 8
	lbw_putbits(lbw, 0, 3); // 7
	lbw_putbits(lbw, 0, 3); // 9
	lbw_putbits(lbw, 0, 3); // 6
	lbw_putbits(lbw, 0, 3); // 10
	lbw_putbits(lbw, 0, 3); // 5
	lbw_putbits(lbw, 0, 3); // 11
	lbw_putbits(lbw, 0, 3); // 4
	lbw_putbits(lbw, 0, 3); // 12
	lbw_putbits(lbw, 0, 3); // 3
	lbw_putbits(lbw, 0, 3); // 13
	lbw_putbits(lbw, 0, 3); // 2
	lbw_putbits(lbw, 0, 3); // 14
	lbw_putbits(lbw, 1, 3); // 1

	// code lengths for literal/length
	lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 138 times
	lbw_putbits(lbw, 127, 7);

	lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 118 times
	lbw_putbits(lbw, 107, 7);

	lbw_putbits_rev(lbw, 0, 1); // 256 has len 1

	// code lengths for distance
	lbw_putbits_rev(lbw, 1, 1); // repeat len 0 for 11 times
	lbw_putbits(lbw, 0, 7);

	// no compressed data

	// end of block
	lbw_putbits_rev(lbw, 0, 1); // 256 = EOB
}

// copy with max distance 32768
void
write_max_dist(struct lsb_bitwriter *lbw)
{
	// bfinal
	lbw_putbits(lbw, 1, 1);

	// btype
	lbw_putbits(lbw, 2, 2);

	// hlit
	lbw_putbits(lbw, 286 - 257, 5);

	// hdist
	lbw_putbits(lbw, 30 - 1, 5);

	// hclen
	lbw_putbits(lbw, 14, 4);

	lbw_putbits(lbw, 0, 3); // 16
	lbw_putbits(lbw, 0, 3); // 17
	lbw_putbits(lbw, 2, 3); // 18
	lbw_putbits(lbw, 0, 3); // 0
	lbw_putbits(lbw, 0, 3); // 8
	lbw_putbits(lbw, 0, 3); // 7
	lbw_putbits(lbw, 0, 3); // 9
	lbw_putbits(lbw, 0, 3); // 6
	lbw_putbits(lbw, 0, 3); // 10
	lbw_putbits(lbw, 0, 3); // 5
	lbw_putbits(lbw, 0, 3); // 11
	lbw_putbits(lbw, 2, 3); // 4
	lbw_putbits(lbw, 0, 3); // 12
	lbw_putbits(lbw, 2, 3); // 3
	lbw_putbits(lbw, 0, 3); // 13
	lbw_putbits(lbw, 0, 3); // 2
	lbw_putbits(lbw, 0, 3); // 14
	lbw_putbits(lbw, 2, 3); // 1

	// code lengths for literal/length
	lbw_putbits_rev(lbw, 1, 2); // 0 has len 3
	lbw_putbits_rev(lbw, 1, 2); // 1 has len 3
	lbw_putbits_rev(lbw, 2, 2); // 2 has len 4

	lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 138 times
	lbw_putbits(lbw, 127, 7);

	lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 115 times
	lbw_putbits(lbw, 104, 7);

	lbw_putbits_rev(lbw, 2, 2); // 256 has len 4
	lbw_putbits_rev(lbw, 2, 2); // 257 has len 4

	lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 26 times
	lbw_putbits(lbw, 15, 7);

	lbw_putbits_rev(lbw, 2, 2); // 284 has len 4

	lbw_putbits_rev(lbw, 0, 2); // 285 has len 1

	// code lengths for distance
	lbw_putbits_rev(lbw, 0, 2); // 0 has len 1

	lbw_putbits_rev(lbw, 3, 2); // repeat len 0 for 28 times
	lbw_putbits(lbw, 17, 7);

	lbw_putbits_rev(lbw, 0, 2); // 29 has len 1

	// no compressed data
	lbw_putbits_rev(lbw, 12, 4); // literal 02
	lbw_putbits_rev(lbw, 5, 3); // literal 01
	lbw_putbits_rev(lbw, 4, 3); // literal 00

	lbw_putbits_rev(lbw, 15, 4); // 284 = copy len 257
	lbw_putbits(lbw, 30, 5);

	lbw_putbits_rev(lbw, 0, 1); // distance 1

	for (int i = 0; i < 126; ++i) {
		lbw_putbits_rev(lbw, 0, 1); // 285 = copy len 258

		lbw_putbits_rev(lbw, 0, 1); // distance 1
	}

	lbw_putbits_rev(lbw, 14, 4); // 257 = copy len 3

	lbw_putbits_rev(lbw, 1, 1); // distance 32768
	lbw_putbits(lbw, 8191, 13);

	// end of block
	lbw_putbits_rev(lbw, 13, 4); // 256 = EOB
}

// Use length 15 codeword
void
write_max_codelen(struct lsb_bitwriter *lbw)
{
	// bfinal
	lbw_putbits(lbw, 1, 1);

	// btype
	lbw_putbits(lbw, 2, 2);

	// hlit
	lbw_putbits(lbw, 0, 5);

	// hdist
	lbw_putbits(lbw, 10, 5);

	// hclen
	lbw_putbits(lbw, 15, 4);

	lbw_putbits(lbw, 0, 3); // 16
	lbw_putbits(lbw, 0, 3); // 17
	lbw_putbits(lbw, 4, 3); // 18
	lbw_putbits(lbw, 0, 3); // 0
	lbw_putbits(lbw, 4, 3); // 8
	lbw_putbits(lbw, 4, 3); // 7
	lbw_putbits(lbw, 4, 3); // 9
	lbw_putbits(lbw, 4, 3); // 6
	lbw_putbits(lbw, 4, 3); // 10
	lbw_putbits(lbw, 4, 3); // 5
	lbw_putbits(lbw, 4, 3); // 11
	lbw_putbits(lbw, 4, 3); // 4
	lbw_putbits(lbw, 4, 3); // 12
	lbw_putbits(lbw, 4, 3); // 3
	lbw_putbits(lbw, 4, 3); // 13
	lbw_putbits(lbw, 4, 3); // 2
	lbw_putbits(lbw, 4, 3); // 14
	lbw_putbits(lbw, 4, 3); // 1
	lbw_putbits(lbw, 4, 3); // 15

	// code lengths for literal/length
	lbw_putbits_rev(lbw, 0, 4); // 0 has len 1
	lbw_putbits_rev(lbw, 1, 4); // 1 has len 2
	lbw_putbits_rev(lbw, 2, 4); // 2 has len 3
	lbw_putbits_rev(lbw, 3, 4); // 3 has len 4
	lbw_putbits_rev(lbw, 4, 4); // 4 has len 5
	lbw_putbits_rev(lbw, 5, 4); // 5 has len 6
	lbw_putbits_rev(lbw, 6, 4); // 6 has len 7
	lbw_putbits_rev(lbw, 7, 4); // 7 has len 8
	lbw_putbits_rev(lbw, 8, 4); // 8 has len 9
	lbw_putbits_rev(lbw, 9, 4); // 9 has len 10
	lbw_putbits_rev(lbw, 10, 4); // 10 has len 11
	lbw_putbits_rev(lbw, 11, 4); // 11 has len 12
	lbw_putbits_rev(lbw, 12, 4); // 12 has len 13
	lbw_putbits_rev(lbw, 13, 4); // 13 has len 14
	lbw_putbits_rev(lbw, 14, 4); // 14 has len 15

	lbw_putbits_rev(lbw, 15, 4); // repeat len 0 for 138 times
	lbw_putbits(lbw, 127, 7);

	lbw_putbits_rev(lbw, 15, 4); // repeat len 0 for 103 times
	lbw_putbits(lbw, 92, 7);

	lbw_putbits_rev(lbw, 14, 4); // 256 has len 15

	// code lengths for distance
	lbw_putbits_rev(lbw, 15, 4); // repeat len 0 for 11 times
	lbw_putbits(lbw, 0, 7);

	// compressed data
	lbw_putbits_rev(lbw, 0, 1); // literal 0
	lbw_putbits_rev(lbw, 2, 2); // literal 1
	lbw_putbits_rev(lbw, 6, 3); // literal 2
	lbw_putbits_rev(lbw, 14, 4); // literal 3
	lbw_putbits_rev(lbw, 30, 5); // literal 4
	lbw_putbits_rev(lbw, 62, 6); // literal 5
	lbw_putbits_rev(lbw, 126, 7); // literal 6
	lbw_putbits_rev(lbw, 254, 8); // literal 7
	lbw_putbits_rev(lbw, 510, 9); // literal 8
	lbw_putbits_rev(lbw, 1022, 10); // literal 9
	lbw_putbits_rev(lbw, 2046, 11); // literal 10
	lbw_putbits_rev(lbw, 4094, 12); // literal 11
	lbw_putbits_rev(lbw, 8190, 13); // literal 12
	lbw_putbits_rev(lbw, 16382, 14); // literal 13
	lbw_putbits_rev(lbw, 32766, 15); // literal 14

	// end of block
	lbw_putbits_rev(lbw, 32767, 15); // 256 = EOB
}

unsigned char buffer[64 * 1024];

int
main(int argc, char *argv[])
{
	if (argc > 2) {
		fputs("syntax: mkzdata FILE\n", stderr);
		return EXIT_FAILURE;
	}

	const unsigned char org_data[1024] = {0};

	unsigned char data[4096];

	struct lsb_bitwriter lbw;

	lbw_init(&lbw, &data[0]);

	write_max_codelen(&lbw);

	uint32_t size = lbw_finalize(&lbw) - &data[0];

	for (int i = 0; i < size; ++i) {
		if (i > 0) {
			fputs(", ", stdout);
		}
		printf("0x%02X", data[i]);
	}
	printf("\n");

	if (argc > 1) {
		FILE *fout = fopen(argv[1], "wb");

		const unsigned char gzip_header[10] = {
			0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0B
		};

		fwrite(gzip_header, 1, sizeof(gzip_header), fout);

		fwrite(data, 1, size, fout);

		unsigned int dsize = sizeof(buffer);
		int res = tinf_uncompress(buffer, &dsize, data, size);

		if (res != TINF_OK) {
			fputs("mkzdata: decompression error\n", stderr);
			return EXIT_FAILURE;
		}

		// Note: only works on little-endian
		uint32_t crc = tinf_crc32(&buffer[0], dsize);
		fwrite(&crc, sizeof(crc), 1, fout);
		uint32_t org_size = dsize;
		fwrite(&org_size, sizeof(org_size), 1, fout);

		fclose(fout);
	}

	return 0;
}
Download .txt
gitextract_cflkwvkt/

├── .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
Download .txt
SYMBOL INDEX (136 symbols across 12 files)

FILE: examples/tgunzip/tgunzip.c
  function read_le32 (line 32) | static unsigned int read_le32(const unsigned char *p)
  function printf_error (line 40) | static void printf_error(const char *fmt, ...)
  function main (line 53) | int main(int argc, char *argv[])

FILE: src/adler32.c
  function tinf_adler32 (line 36) | unsigned int tinf_adler32(const void *data, unsigned int length)

FILE: src/crc32.c
  function tinf_crc32 (line 40) | unsigned int tinf_crc32(const void *data, unsigned int length)

FILE: src/tinf.h
  type tinf_error_code (line 51) | typedef enum {

FILE: src/tinfgzip.c
  type tinf_gzip_flag (line 28) | typedef enum {
  function read_le16 (line 36) | static unsigned int read_le16(const unsigned char *p)
  function read_le32 (line 42) | static unsigned int read_le32(const unsigned char *p)
  function tinf_gzip_uncompress (line 50) | int tinf_gzip_uncompress(void *dest, unsigned int *destLen,

FILE: src/tinflate.c
  type tinf_tree (line 37) | struct tinf_tree {
  type tinf_data (line 43) | struct tinf_data {
  function read_le16 (line 60) | static unsigned int read_le16(const unsigned char *p)
  function tinf_build_fixed_trees (line 67) | static void tinf_build_fixed_trees(struct tinf_tree *lt, struct tinf_tre...
  function tinf_build_tree (line 110) | static int tinf_build_tree(struct tinf_tree *t, const unsigned char *len...
  function tinf_refill (line 178) | static void tinf_refill(struct tinf_data *d, int num)
  function tinf_getbits_no_refill (line 196) | static unsigned int tinf_getbits_no_refill(struct tinf_data *d, int num)
  function tinf_getbits (line 213) | static unsigned int tinf_getbits(struct tinf_data *d, int num)
  function tinf_getbits_base (line 220) | static unsigned int tinf_getbits_base(struct tinf_data *d, int num, int ...
  function tinf_decode_symbol (line 226) | static int tinf_decode_symbol(struct tinf_data *d, const struct tinf_tre...
  function tinf_decode_trees (line 263) | static int tinf_decode_trees(struct tinf_data *d, struct tinf_tree *lt,
  function tinf_inflate_block_data (line 390) | static int tinf_inflate_block_data(struct tinf_data *d, struct tinf_tree...
  function tinf_inflate_uncompressed_block (line 483) | static int tinf_inflate_uncompressed_block(struct tinf_data *d)
  function tinf_inflate_fixed_block (line 525) | static int tinf_inflate_fixed_block(struct tinf_data *d)
  function tinf_inflate_dynamic_block (line 535) | static int tinf_inflate_dynamic_block(struct tinf_data *d)
  function tinf_init (line 551) | void tinf_init(void)
  function tinf_uncompress (line 557) | int tinf_uncompress(void *dest, unsigned int *destLen,
  function LLVMFuzzerTestOneInput (line 628) | extern int

FILE: src/tinfzlib.c
  function read_be32 (line 28) | static unsigned int read_be32(const unsigned char *p)
  function tinf_zlib_uncompress (line 36) | int tinf_zlib_uncompress(void *dest, unsigned int *destLen,

FILE: test/greatest.h
  function TEST (line 45) | TEST foo_should_foo(void) {
  function setup_cb (line 49) | static void setup_cb(void *data) {
  function teardown_cb (line 53) | static void teardown_cb(void *data) {
  function SUITE (line 57) | SUITE(suite) {
  function run_tests (line 71) | int run_tests(void) {
  function main (line 86) | int main(int argc, char **argv) {
  type greatest_suite_info (line 161) | typedef struct greatest_suite_info {
  type greatest_type_info (line 196) | typedef struct greatest_type_info {
  type greatest_memory_cmp_env (line 201) | typedef struct greatest_memory_cmp_env {
  type greatest_flag_t (line 211) | typedef enum {
  type greatest_prng (line 218) | struct greatest_prng {
  type greatest_run_info (line 232) | typedef struct greatest_run_info {
  type greatest_report_t (line 287) | struct greatest_report_t {
  type greatest_report_t (line 329) | struct greatest_report_t
  type greatest_test_res (line 364) | typedef enum greatest_test_res {
  function greatest_buffer_test_name (line 727) | static void greatest_buffer_test_name(const char *name) {               \
  function greatest_test_pre (line 740) | int greatest_test_pre(const char *name) {                               \
  function greatest_do_pass (line 777) | static void greatest_do_pass(void) {                                    \
  function greatest_do_fail (line 788) | static void greatest_do_fail(void) {                                    \
  function greatest_do_skip (line 808) | static void greatest_do_skip(void) {                                    \
  function greatest_test_post (line 819) | void greatest_test_post(int res) {                                      \
  function report_suite (line 848) | static void report_suite(void) {                                        \
  function update_counts_and_reset_suite (line 863) | static void update_counts_and_reset_suite(void) {                       \
  function greatest_suite_pre (line 876) | static int greatest_suite_pre(const char *suite_name) {                 \
  function greatest_suite_post (line 893) | static void greatest_suite_post(void) {                                 \
  function greatest_run_suite (line 898) | static void greatest_run_suite(greatest_suite_cb *suite_cb,             \
  function greatest_do_assert_equal_t (line 906) | int greatest_do_assert_equal_t(const void *expd, const void *got,       \
  function greatest_usage (line 923) | static void greatest_usage(const char *name) {                          \
  function greatest_parse_options (line 938) | static void greatest_parse_options(int argc, char **argv) {             \
  function greatest_all_passed (line 981) | int greatest_all_passed(void) { return (greatest_info.failed == 0); }
  function greatest_set_test_filter (line 983) | void greatest_set_test_filter(const char *filter) {                     \
  function greatest_set_test_exclude (line 987) | void greatest_set_test_exclude(const char *filter) {                    \
  function greatest_set_suite_filter (line 991) | void greatest_set_suite_filter(const char *filter) {                    \
  function greatest_set_exact_name_match (line 995) | void greatest_set_exact_name_match(void) {                              \
  function greatest_stop_at_first_fail (line 999) | void greatest_stop_at_first_fail(void) {                                \
  function greatest_abort_on_fail (line 1003) | void greatest_abort_on_fail(void) {                                     \
  function greatest_list_only (line 1007) | void greatest_list_only(void) {                                         \
  function greatest_get_report (line 1011) | void greatest_get_report(struct greatest_report_t *report) {            \
  function greatest_get_verbosity (line 1020) | unsigned int greatest_get_verbosity(void) {                             \
  function greatest_set_verbosity (line 1024) | void greatest_set_verbosity(unsigned int verbosity) {                   \
  function greatest_set_flag (line 1028) | void greatest_set_flag(greatest_flag_t flag) {                          \
  function greatest_set_test_suffix (line 1032) | void greatest_set_test_suffix(const char *suffix) {                     \
  function GREATEST_SET_SETUP_CB (line 1036) | void GREATEST_SET_SETUP_CB(greatest_setup_cb *cb, void *udata) {        \
  function GREATEST_SET_TEARDOWN_CB (line 1041) | void GREATEST_SET_TEARDOWN_CB(greatest_teardown_cb *cb, void *udata) {  \
  function greatest_string_equal_cb (line 1046) | static int greatest_string_equal_cb(const void *expd, const void *got,  \
  function greatest_string_printf_cb (line 1054) | static int greatest_string_printf_cb(const void *t, void *udata) {      \
  function greatest_memory_equal_cb (line 1063) | static int greatest_memory_equal_cb(const void *expd, const void *got,  \
  function greatest_memory_printf_cb (line 1070) | static int greatest_memory_printf_cb(const void *t, void *udata) {      \
  function greatest_prng_init_first_pass (line 1104) | void greatest_prng_init_first_pass(int id) {                            \
  function greatest_prng_init_second_pass (line 1109) | int greatest_prng_init_second_pass(int id, unsigned long seed) {        \
  function greatest_prng_step (line 1134) | void greatest_prng_step(int id) {                                       \
  function GREATEST_INIT (line 1141) | void GREATEST_INIT(void) {                                              \
  function GREATEST_PRINT_REPORT (line 1157) | void GREATEST_PRINT_REPORT(void) {                                      \

FILE: test/test_tinf.c
  type packed_data (line 42) | struct packed_data {
  type packed_data (line 48) | struct packed_data
  type packed_data (line 118) | struct packed_data
  type packed_data (line 139) | struct packed_data
  function TEST (line 176) | TEST inflate_padding(void)
  function TEST (line 192) | TEST inflate_empty_no_literals(void)
  function TEST (line 216) | TEST inflate_huffman_only(void)
  function TEST (line 246) | TEST inflate_rle(void)
  function TEST (line 273) | TEST inflate_max_matchlen(void)
  function TEST (line 300) | TEST inflate_max_matchlen_alt(void)
  function TEST (line 333) | TEST inflate_max_matchdist(void)
  function TEST (line 370) | TEST inflate_code_length_codes(void)
  function TEST (line 397) | TEST inflate_max_codelen(void)
  function TEST (line 427) | TEST inflate_random(void)
  function TEST (line 452) | TEST inflate_error_case(const void *closure)
  function SUITE (line 465) | SUITE(tinflate)
  function TEST (line 491) | TEST zlib_empty_raw(void)
  function TEST (line 508) | TEST zlib_empty_fixed(void)
  function TEST (line 524) | TEST zlib_empty_dynamic(void)
  function TEST (line 541) | TEST zlib_onebyte_raw(void)
  function TEST (line 559) | TEST zlib_onebyte_fixed(void)
  function TEST (line 576) | TEST zlib_onebyte_dynamic(void)
  function TEST (line 594) | TEST zlib_zeroes(void)
  function TEST (line 622) | TEST zlib_error_case(const void *closure)
  function SUITE (line 635) | SUITE(tinfzlib)
  function TEST (line 658) | TEST gzip_empty_raw(void)
  function TEST (line 676) | TEST gzip_empty_fixed(void)
  function TEST (line 693) | TEST gzip_empty_dynamic(void)
  function TEST (line 711) | TEST gzip_onebyte_raw(void)
  function TEST (line 730) | TEST gzip_onebyte_fixed(void)
  function TEST (line 749) | TEST gzip_onebyte_dynamic(void)
  function TEST (line 768) | TEST gzip_fhcrc(void)
  function TEST (line 787) | TEST gzip_fextra(void)
  function TEST (line 806) | TEST gzip_fname(void)
  function TEST (line 825) | TEST gzip_fcomment(void)
  function TEST (line 845) | TEST gzip_error_case(const void *closure)
  function SUITE (line 858) | SUITE(tinfgzip)
  function main (line 885) | int main(int argc, char *argv[])

FILE: tools/gengztest.py
  function write_gzip (line 34) | def write_gzip(f, args):

FILE: tools/genzlibtest.py
  function write_zlib (line 34) | def write_zlib(f, args):

FILE: tools/mkzdata.c
  type lsb_bitwriter (line 32) | struct lsb_bitwriter {
  function lbw_init (line 38) | static void
  type lsb_bitwriter (line 47) | struct lsb_bitwriter
  function lbw_flush (line 59) | static void
  function lbw_putbits_no_flush (line 73) | static void
  function lbw_putbits (line 83) | static void
  function lbw_putbits_rev (line 89) | static void
  function write_256_rle (line 98) | void
  function write_256_huffman (line 167) | void
  function write_no_lit (line 229) | void
  function write_max_dist (line 286) | void
  function write_max_codelen (line 378) | void
  function main (line 468) | int
Condensed preview — 18 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (166K chars).
[
  {
    "path": ".editorconfig",
    "chars": 201,
    "preview": "root = true\n\n[*]\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[Makefile*]\nindent_style = tab\n\n[*.{c,h}]\n"
  },
  {
    "path": ".github/workflows/tinf-ci-workflow.yaml",
    "chars": 2045,
    "preview": "name: tinf CI\n\non: [push, pull_request]\n\njobs:\n  windows:\n    name: Windows ${{ matrix.config.name }}\n    runs-on: windo"
  },
  {
    "path": ".gitignore",
    "chars": 62,
    "preview": "*.o\n*.obj\n\n*.a\n*.lib\n\n*.so\n*.so.*\n*.dll\n\n*.exe\n\n/build/\n/doc/\n"
  },
  {
    "path": "CMakeLists.txt",
    "chars": 2036,
    "preview": "cmake_minimum_required(VERSION 3.16)\n\nproject(tinf C)\n\ninclude(CheckCCompilerFlag)\ninclude(CTest)\n\n# Check if tinf is th"
  },
  {
    "path": "LICENSE",
    "chars": 903,
    "preview": "The zlib License (Zlib)\n\nCopyright (c) 2003-2019 Joergen Ibsen\n\nThis software is provided 'as-is', without any express o"
  },
  {
    "path": "README.md",
    "chars": 3772,
    "preview": "\ntinf - tiny inflate library\n===========================\n\nVersion 1.2.1\n\nCopyright (c) 2003-2019 Joergen Ibsen\n\n<http://"
  },
  {
    "path": "examples/tgunzip/tgunzip.c",
    "chars": 3351,
    "preview": "/*\n * tgunzip - gzip decompressor example\n *\n * Copyright (c) 2003-2019 Joergen Ibsen\n *\n * This software is provided 'a"
  },
  {
    "path": "src/adler32.c",
    "chars": 2087,
    "preview": "/*\n * Adler-32 checksum\n *\n * Copyright (c) 2003-2019 Joergen Ibsen\n *\n * This software is provided 'as-is', without any"
  },
  {
    "path": "src/crc32.c",
    "chars": 1737,
    "preview": "/*\n * CRC32 checksum\n *\n * Copyright (c) 1998-2019 Joergen Ibsen\n *\n * This software is provided 'as-is', without any ex"
  },
  {
    "path": "src/tinf.h",
    "chars": 4634,
    "preview": "/*\n * tinf - tiny inflate library (inflate, gzip, zlib)\n *\n * Copyright (c) 2003-2019 Joergen Ibsen\n *\n * This software "
  },
  {
    "path": "src/tinfgzip.c",
    "chars": 3737,
    "preview": "/*\n * tinfgzip - tiny gzip decompressor\n *\n * Copyright (c) 2003-2019 Joergen Ibsen\n *\n * This software is provided 'as-"
  },
  {
    "path": "src/tinflate.c",
    "chars": 14466,
    "preview": "/*\n * tinflate - tiny inflate\n *\n * Copyright (c) 2003-2019 Joergen Ibsen\n *\n * This software is provided 'as-is', witho"
  },
  {
    "path": "src/tinfzlib.c",
    "chars": 2405,
    "preview": "/*\n * tinfzlib - tiny zlib decompressor\n *\n * Copyright (c) 2003-2019 Joergen Ibsen\n *\n * This software is provided 'as-"
  },
  {
    "path": "test/greatest.h",
    "chars": 68870,
    "preview": "/*\n * Copyright (c) 2011-2021 Scott Vokes <vokes.s@gmail.com>\n *\n * Permission to use, copy, modify, and/or distribute t"
  },
  {
    "path": "test/test_tinf.c",
    "chars": 25202,
    "preview": "/*\n * tinf unit test\n *\n * Copyright (c) 2014-2022 Joergen Ibsen\n *\n * This software is provided 'as-is', without any ex"
  },
  {
    "path": "tools/gengztest.py",
    "chars": 4371,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (c) 2014-2019 Joergen Ibsen\n#\n# Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "tools/genzlibtest.py",
    "chars": 4117,
    "preview": "#!/usr/bin/env python3\n\n# Copyright (c) 2014-2019 Joergen Ibsen\n#\n# Permission is hereby granted, free of charge, to any"
  },
  {
    "path": "tools/mkzdata.c",
    "chars": 12993,
    "preview": "/*\n * mkzdata - generate deflate compressed data testcases\n *\n * Copyright (c) 2014-2019 Joergen Ibsen\n *\n * Permission "
  }
]

About this extraction

This page contains the full source code of the jibsen/tinf GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 18 files (153.3 KB), approximately 44.6k tokens, and a symbol index with 136 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!