jpayne@69: /* jpayne@69: * libdeflate.h - public header for libdeflate jpayne@69: */ jpayne@69: jpayne@69: #ifndef LIBDEFLATE_H jpayne@69: #define LIBDEFLATE_H jpayne@69: jpayne@69: #include jpayne@69: #include jpayne@69: jpayne@69: #ifdef __cplusplus jpayne@69: extern "C" { jpayne@69: #endif jpayne@69: jpayne@69: #define LIBDEFLATE_VERSION_MAJOR 1 jpayne@69: #define LIBDEFLATE_VERSION_MINOR 17 jpayne@69: #define LIBDEFLATE_VERSION_STRING "1.17" jpayne@69: jpayne@69: /* jpayne@69: * Users of libdeflate.dll on Windows can define LIBDEFLATE_DLL to cause jpayne@69: * __declspec(dllimport) to be used. This should be done when it's easy to do. jpayne@69: * Otherwise it's fine to skip it, since it is a very minor performance jpayne@69: * optimization that is irrelevant for most use cases of libdeflate. jpayne@69: */ jpayne@69: #ifndef LIBDEFLATEAPI jpayne@69: # if defined(LIBDEFLATE_DLL) && (defined(_WIN32) || defined(__CYGWIN__)) jpayne@69: # define LIBDEFLATEAPI __declspec(dllimport) jpayne@69: # else jpayne@69: # define LIBDEFLATEAPI jpayne@69: # endif jpayne@69: #endif jpayne@69: jpayne@69: /* ========================================================================== */ jpayne@69: /* Compression */ jpayne@69: /* ========================================================================== */ jpayne@69: jpayne@69: struct libdeflate_compressor; jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_alloc_compressor() allocates a new compressor that supports jpayne@69: * DEFLATE, zlib, and gzip compression. 'compression_level' is the compression jpayne@69: * level on a zlib-like scale but with a higher maximum value (1 = fastest, 6 = jpayne@69: * medium/default, 9 = slow, 12 = slowest). Level 0 is also supported and means jpayne@69: * "no compression", specifically "create a valid stream, but only emit jpayne@69: * uncompressed blocks" (this will expand the data slightly). jpayne@69: * jpayne@69: * The return value is a pointer to the new compressor, or NULL if out of memory jpayne@69: * or if the compression level is invalid (i.e. outside the range [0, 12]). jpayne@69: * jpayne@69: * Note: for compression, the sliding window size is defined at compilation time jpayne@69: * to 32768, the largest size permissible in the DEFLATE format. It cannot be jpayne@69: * changed at runtime. jpayne@69: * jpayne@69: * A single compressor is not safe to use by multiple threads concurrently. jpayne@69: * However, different threads may use different compressors concurrently. jpayne@69: */ jpayne@69: LIBDEFLATEAPI struct libdeflate_compressor * jpayne@69: libdeflate_alloc_compressor(int compression_level); jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_deflate_compress() performs raw DEFLATE compression on a buffer of jpayne@69: * data. It attempts to compress 'in_nbytes' bytes of data located at 'in' and jpayne@69: * write the result to 'out', which has space for 'out_nbytes_avail' bytes. The jpayne@69: * return value is the compressed size in bytes, or 0 if the data could not be jpayne@69: * compressed to 'out_nbytes_avail' bytes or fewer (but see note below). jpayne@69: * jpayne@69: * If compression is successful, then the output data is guaranteed to be a jpayne@69: * valid DEFLATE stream that decompresses to the input data. No other jpayne@69: * guarantees are made about the output data. Notably, different versions of jpayne@69: * libdeflate can produce different compressed data for the same uncompressed jpayne@69: * data, even at the same compression level. Do ***NOT*** do things like jpayne@69: * writing tests that compare compressed data to a golden output, as this can jpayne@69: * break when libdeflate is updated. (This property isn't specific to jpayne@69: * libdeflate; the same is true for zlib and other compression libraries too.) jpayne@69: * jpayne@69: * Note: due to a performance optimization, libdeflate_deflate_compress() jpayne@69: * currently needs a small amount of slack space at the end of the output jpayne@69: * buffer. As a result, it can't actually report compressed sizes very close to jpayne@69: * 'out_nbytes_avail'. This doesn't matter in real-world use cases, and jpayne@69: * libdeflate_deflate_compress_bound() already includes the slack space. jpayne@69: * However, it does mean that testing code that redundantly compresses data jpayne@69: * using an exact-sized output buffer won't work as might be expected: jpayne@69: * jpayne@69: * out_nbytes = libdeflate_deflate_compress(c, in, in_nbytes, out, jpayne@69: * libdeflate_deflate_compress_bound(in_nbytes)); jpayne@69: * // The following assertion will fail. jpayne@69: * assert(libdeflate_deflate_compress(c, in, in_nbytes, out, out_nbytes) != 0); jpayne@69: * jpayne@69: * To avoid this, either don't write tests like the above, or make sure to jpayne@69: * include at least 9 bytes of slack space in 'out_nbytes_avail'. jpayne@69: */ jpayne@69: LIBDEFLATEAPI size_t jpayne@69: libdeflate_deflate_compress(struct libdeflate_compressor *compressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail); jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_deflate_compress_bound() returns a worst-case upper bound on the jpayne@69: * number of bytes of compressed data that may be produced by compressing any jpayne@69: * buffer of length less than or equal to 'in_nbytes' using jpayne@69: * libdeflate_deflate_compress() with the specified compressor. This bound will jpayne@69: * necessarily be a number greater than or equal to 'in_nbytes'. It may be an jpayne@69: * overestimate of the true upper bound. The return value is guaranteed to be jpayne@69: * the same for all invocations with the same compressor and same 'in_nbytes'. jpayne@69: * jpayne@69: * As a special case, 'compressor' may be NULL. This causes the bound to be jpayne@69: * taken across *any* libdeflate_compressor that could ever be allocated with jpayne@69: * this build of the library, with any options. jpayne@69: * jpayne@69: * Note that this function is not necessary in many applications. With jpayne@69: * block-based compression, it is usually preferable to separately store the jpayne@69: * uncompressed size of each block and to store any blocks that did not compress jpayne@69: * to less than their original size uncompressed. In that scenario, there is no jpayne@69: * need to know the worst-case compressed size, since the maximum number of jpayne@69: * bytes of compressed data that may be used would always be one less than the jpayne@69: * input length. You can just pass a buffer of that size to jpayne@69: * libdeflate_deflate_compress() and store the data uncompressed if jpayne@69: * libdeflate_deflate_compress() returns 0, indicating that the compressed data jpayne@69: * did not fit into the provided output buffer. jpayne@69: */ jpayne@69: LIBDEFLATEAPI size_t jpayne@69: libdeflate_deflate_compress_bound(struct libdeflate_compressor *compressor, jpayne@69: size_t in_nbytes); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_compress(), but uses the zlib wrapper format instead jpayne@69: * of raw DEFLATE. jpayne@69: */ jpayne@69: LIBDEFLATEAPI size_t jpayne@69: libdeflate_zlib_compress(struct libdeflate_compressor *compressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_compress_bound(), but assumes the data will be jpayne@69: * compressed with libdeflate_zlib_compress() rather than with jpayne@69: * libdeflate_deflate_compress(). jpayne@69: */ jpayne@69: LIBDEFLATEAPI size_t jpayne@69: libdeflate_zlib_compress_bound(struct libdeflate_compressor *compressor, jpayne@69: size_t in_nbytes); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_compress(), but uses the gzip wrapper format instead jpayne@69: * of raw DEFLATE. jpayne@69: */ jpayne@69: LIBDEFLATEAPI size_t jpayne@69: libdeflate_gzip_compress(struct libdeflate_compressor *compressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_compress_bound(), but assumes the data will be jpayne@69: * compressed with libdeflate_gzip_compress() rather than with jpayne@69: * libdeflate_deflate_compress(). jpayne@69: */ jpayne@69: LIBDEFLATEAPI size_t jpayne@69: libdeflate_gzip_compress_bound(struct libdeflate_compressor *compressor, jpayne@69: size_t in_nbytes); jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_free_compressor() frees a compressor that was allocated with jpayne@69: * libdeflate_alloc_compressor(). If a NULL pointer is passed in, no action is jpayne@69: * taken. jpayne@69: */ jpayne@69: LIBDEFLATEAPI void jpayne@69: libdeflate_free_compressor(struct libdeflate_compressor *compressor); jpayne@69: jpayne@69: /* ========================================================================== */ jpayne@69: /* Decompression */ jpayne@69: /* ========================================================================== */ jpayne@69: jpayne@69: struct libdeflate_decompressor; jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_alloc_decompressor() allocates a new decompressor that can be used jpayne@69: * for DEFLATE, zlib, and gzip decompression. The return value is a pointer to jpayne@69: * the new decompressor, or NULL if out of memory. jpayne@69: * jpayne@69: * This function takes no parameters, and the returned decompressor is valid for jpayne@69: * decompressing data that was compressed at any compression level and with any jpayne@69: * sliding window size. jpayne@69: * jpayne@69: * A single decompressor is not safe to use by multiple threads concurrently. jpayne@69: * However, different threads may use different decompressors concurrently. jpayne@69: */ jpayne@69: LIBDEFLATEAPI struct libdeflate_decompressor * jpayne@69: libdeflate_alloc_decompressor(void); jpayne@69: jpayne@69: /* jpayne@69: * Result of a call to libdeflate_deflate_decompress(), jpayne@69: * libdeflate_zlib_decompress(), or libdeflate_gzip_decompress(). jpayne@69: */ jpayne@69: enum libdeflate_result { jpayne@69: /* Decompression was successful. */ jpayne@69: LIBDEFLATE_SUCCESS = 0, jpayne@69: jpayne@69: /* Decompression failed because the compressed data was invalid, jpayne@69: * corrupt, or otherwise unsupported. */ jpayne@69: LIBDEFLATE_BAD_DATA = 1, jpayne@69: jpayne@69: /* A NULL 'actual_out_nbytes_ret' was provided, but the data would have jpayne@69: * decompressed to fewer than 'out_nbytes_avail' bytes. */ jpayne@69: LIBDEFLATE_SHORT_OUTPUT = 2, jpayne@69: jpayne@69: /* The data would have decompressed to more than 'out_nbytes_avail' jpayne@69: * bytes. */ jpayne@69: LIBDEFLATE_INSUFFICIENT_SPACE = 3, jpayne@69: }; jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_deflate_decompress() decompresses a DEFLATE stream from the buffer jpayne@69: * 'in' with compressed size up to 'in_nbytes' bytes. The uncompressed data is jpayne@69: * written to 'out', a buffer with size 'out_nbytes_avail' bytes. If jpayne@69: * decompression succeeds, then 0 (LIBDEFLATE_SUCCESS) is returned. Otherwise, jpayne@69: * a nonzero result code such as LIBDEFLATE_BAD_DATA is returned, and the jpayne@69: * contents of the output buffer are undefined. jpayne@69: * jpayne@69: * Decompression stops at the end of the DEFLATE stream (as indicated by the jpayne@69: * BFINAL flag), even if it is actually shorter than 'in_nbytes' bytes. jpayne@69: * jpayne@69: * libdeflate_deflate_decompress() can be used in cases where the actual jpayne@69: * uncompressed size is known (recommended) or unknown (not recommended): jpayne@69: * jpayne@69: * - If the actual uncompressed size is known, then pass the actual jpayne@69: * uncompressed size as 'out_nbytes_avail' and pass NULL for jpayne@69: * 'actual_out_nbytes_ret'. This makes libdeflate_deflate_decompress() fail jpayne@69: * with LIBDEFLATE_SHORT_OUTPUT if the data decompressed to fewer than the jpayne@69: * specified number of bytes. jpayne@69: * jpayne@69: * - If the actual uncompressed size is unknown, then provide a non-NULL jpayne@69: * 'actual_out_nbytes_ret' and provide a buffer with some size jpayne@69: * 'out_nbytes_avail' that you think is large enough to hold all the jpayne@69: * uncompressed data. In this case, if the data decompresses to less than jpayne@69: * or equal to 'out_nbytes_avail' bytes, then jpayne@69: * libdeflate_deflate_decompress() will write the actual uncompressed size jpayne@69: * to *actual_out_nbytes_ret and return 0 (LIBDEFLATE_SUCCESS). Otherwise, jpayne@69: * it will return LIBDEFLATE_INSUFFICIENT_SPACE if the provided buffer was jpayne@69: * not large enough but no other problems were encountered, or another jpayne@69: * nonzero result code if decompression failed for another reason. jpayne@69: */ jpayne@69: LIBDEFLATEAPI enum libdeflate_result jpayne@69: libdeflate_deflate_decompress(struct libdeflate_decompressor *decompressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail, jpayne@69: size_t *actual_out_nbytes_ret); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_decompress(), but adds the 'actual_in_nbytes_ret' jpayne@69: * argument. If decompression succeeds and 'actual_in_nbytes_ret' is not NULL, jpayne@69: * then the actual compressed size of the DEFLATE stream (aligned to the next jpayne@69: * byte boundary) is written to *actual_in_nbytes_ret. jpayne@69: */ jpayne@69: LIBDEFLATEAPI enum libdeflate_result jpayne@69: libdeflate_deflate_decompress_ex(struct libdeflate_decompressor *decompressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail, jpayne@69: size_t *actual_in_nbytes_ret, jpayne@69: size_t *actual_out_nbytes_ret); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_decompress(), but assumes the zlib wrapper format jpayne@69: * instead of raw DEFLATE. jpayne@69: * jpayne@69: * Decompression will stop at the end of the zlib stream, even if it is shorter jpayne@69: * than 'in_nbytes'. If you need to know exactly where the zlib stream ended, jpayne@69: * use libdeflate_zlib_decompress_ex(). jpayne@69: */ jpayne@69: LIBDEFLATEAPI enum libdeflate_result jpayne@69: libdeflate_zlib_decompress(struct libdeflate_decompressor *decompressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail, jpayne@69: size_t *actual_out_nbytes_ret); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_zlib_decompress(), but adds the 'actual_in_nbytes_ret' jpayne@69: * argument. If 'actual_in_nbytes_ret' is not NULL and the decompression jpayne@69: * succeeds (indicating that the first zlib-compressed stream in the input jpayne@69: * buffer was decompressed), then the actual number of input bytes consumed is jpayne@69: * written to *actual_in_nbytes_ret. jpayne@69: */ jpayne@69: LIBDEFLATEAPI enum libdeflate_result jpayne@69: libdeflate_zlib_decompress_ex(struct libdeflate_decompressor *decompressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail, jpayne@69: size_t *actual_in_nbytes_ret, jpayne@69: size_t *actual_out_nbytes_ret); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_deflate_decompress(), but assumes the gzip wrapper format jpayne@69: * instead of raw DEFLATE. jpayne@69: * jpayne@69: * If multiple gzip-compressed members are concatenated, then only the first jpayne@69: * will be decompressed. Use libdeflate_gzip_decompress_ex() if you need jpayne@69: * multi-member support. jpayne@69: */ jpayne@69: LIBDEFLATEAPI enum libdeflate_result jpayne@69: libdeflate_gzip_decompress(struct libdeflate_decompressor *decompressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail, jpayne@69: size_t *actual_out_nbytes_ret); jpayne@69: jpayne@69: /* jpayne@69: * Like libdeflate_gzip_decompress(), but adds the 'actual_in_nbytes_ret' jpayne@69: * argument. If 'actual_in_nbytes_ret' is not NULL and the decompression jpayne@69: * succeeds (indicating that the first gzip-compressed member in the input jpayne@69: * buffer was decompressed), then the actual number of input bytes consumed is jpayne@69: * written to *actual_in_nbytes_ret. jpayne@69: */ jpayne@69: LIBDEFLATEAPI enum libdeflate_result jpayne@69: libdeflate_gzip_decompress_ex(struct libdeflate_decompressor *decompressor, jpayne@69: const void *in, size_t in_nbytes, jpayne@69: void *out, size_t out_nbytes_avail, jpayne@69: size_t *actual_in_nbytes_ret, jpayne@69: size_t *actual_out_nbytes_ret); jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_free_decompressor() frees a decompressor that was allocated with jpayne@69: * libdeflate_alloc_decompressor(). If a NULL pointer is passed in, no action jpayne@69: * is taken. jpayne@69: */ jpayne@69: LIBDEFLATEAPI void jpayne@69: libdeflate_free_decompressor(struct libdeflate_decompressor *decompressor); jpayne@69: jpayne@69: /* ========================================================================== */ jpayne@69: /* Checksums */ jpayne@69: /* ========================================================================== */ jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_adler32() updates a running Adler-32 checksum with 'len' bytes of jpayne@69: * data and returns the updated checksum. When starting a new checksum, the jpayne@69: * required initial value for 'adler' is 1. This value is also returned when jpayne@69: * 'buffer' is specified as NULL. jpayne@69: */ jpayne@69: LIBDEFLATEAPI uint32_t jpayne@69: libdeflate_adler32(uint32_t adler, const void *buffer, size_t len); jpayne@69: jpayne@69: jpayne@69: /* jpayne@69: * libdeflate_crc32() updates a running CRC-32 checksum with 'len' bytes of data jpayne@69: * and returns the updated checksum. When starting a new checksum, the required jpayne@69: * initial value for 'crc' is 0. This value is also returned when 'buffer' is jpayne@69: * specified as NULL. jpayne@69: */ jpayne@69: LIBDEFLATEAPI uint32_t jpayne@69: libdeflate_crc32(uint32_t crc, const void *buffer, size_t len); jpayne@69: jpayne@69: /* ========================================================================== */ jpayne@69: /* Custom memory allocator */ jpayne@69: /* ========================================================================== */ jpayne@69: jpayne@69: /* jpayne@69: * Install a custom memory allocator which libdeflate will use for all memory jpayne@69: * allocations. 'malloc_func' is a function that must behave like malloc(), and jpayne@69: * 'free_func' is a function that must behave like free(). jpayne@69: * jpayne@69: * There must not be any libdeflate_compressor or libdeflate_decompressor jpayne@69: * structures in existence when calling this function. jpayne@69: */ jpayne@69: LIBDEFLATEAPI void jpayne@69: libdeflate_set_memory_allocator(void *(*malloc_func)(size_t), jpayne@69: void (*free_func)(void *)); jpayne@69: jpayne@69: #ifdef __cplusplus jpayne@69: } jpayne@69: #endif jpayne@69: jpayne@69: #endif /* LIBDEFLATE_H */