asset compression

This commit is contained in:
Jorijn van der Graaf 2026-05-11 18:37:30 +02:00
commit 30a283c1b3
57 changed files with 13237 additions and 8 deletions

View file

@ -0,0 +1,540 @@
/*
* libdeflate.h - public header for libdeflate
*/
#ifndef LIBDEFLATE_H
#define LIBDEFLATE_H
#ifdef __cplusplus
extern "C" {
#endif
#define LIBDEFLATE_VERSION_MAJOR 1
#define LIBDEFLATE_VERSION_MINOR 8
#define LIBDEFLATE_VERSION_STRING "1.8"
#include <stddef.h>
#include <stdint.h>
/*
* On Windows, if you want to link to the DLL version of libdeflate, then
* #define LIBDEFLATE_DLL. Note that the calling convention is "stdcall".
*/
#ifdef LIBDEFLATE_DLL
# ifdef BUILDING_LIBDEFLATE
# define LIBDEFLATEEXPORT LIBEXPORT
# elif defined(_WIN32) || defined(__CYGWIN__)
# define LIBDEFLATEEXPORT __declspec(dllimport)
# endif
#endif
#ifndef LIBDEFLATEEXPORT
# define LIBDEFLATEEXPORT
#endif
#if defined(_WIN32) && !defined(_WIN64)
# define LIBDEFLATEAPI_ABI __stdcall
#else
# define LIBDEFLATEAPI_ABI
#endif
#if defined(BUILDING_LIBDEFLATE) && defined(__GNUC__) && \
defined(_WIN32) && !defined(_WIN64)
/*
* On 32-bit Windows, gcc assumes 16-byte stack alignment but MSVC only 4.
* Realign the stack when entering libdeflate to avoid crashing in SSE/AVX
* code when called from an MSVC-compiled application.
*/
# define LIBDEFLATEAPI_STACKALIGN __attribute__((force_align_arg_pointer))
#else
# define LIBDEFLATEAPI_STACKALIGN
#endif
#define LIBDEFLATEAPI LIBDEFLATEAPI_ABI LIBDEFLATEAPI_STACKALIGN
/* ========================================================================== */
/* Compression */
/* ========================================================================== */
struct libdeflate_compressor;
/*
* libdeflate_alloc_compressor() allocates a new compressor that supports
* DEFLATE, zlib, and gzip compression. 'compression_level' is the compression
* level on a zlib-like scale but with a higher maximum value (1 = fastest, 6 =
* medium/default, 9 = slow, 12 = slowest). Level 0 is also supported and means
* "no compression", specifically "create a valid stream, but only emit
* uncompressed blocks" (this will expand the data slightly).
*
* The return value is a pointer to the new compressor, or NULL if out of memory
* or if the compression level is invalid (i.e. outside the range [0, 12]).
*
* Note: for compression, the sliding window size is defined at compilation time
* to 32768, the largest size permissible in the DEFLATE format. It cannot be
* changed at runtime.
*
* A single compressor is not safe to use by multiple threads concurrently.
* However, different threads may use different compressors concurrently.
*/
LIBDEFLATEEXPORT struct libdeflate_compressor * LIBDEFLATEAPI
libdeflate_alloc_compressor(int compression_level);
/*
* libdeflate_deflate_compress() performs raw DEFLATE compression on a buffer of
* data. The function attempts to compress 'in_nbytes' bytes of data located at
* 'in' and write the results to 'out', which has space for 'out_nbytes_avail'
* bytes. The return value is the compressed size in bytes, or 0 if the data
* could not be compressed to 'out_nbytes_avail' bytes or fewer.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_deflate_compress(struct libdeflate_compressor *compressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail);
/*
* libdeflate_deflate_compress_bound() returns a worst-case upper bound on the
* number of bytes of compressed data that may be produced by compressing any
* buffer of length less than or equal to 'in_nbytes' using
* libdeflate_deflate_compress() with the specified compressor. Mathematically,
* this bound will necessarily be a number greater than or equal to 'in_nbytes'.
* It may be an overestimate of the true upper bound. The return value is
* guaranteed to be the same for all invocations with the same compressor and
* same 'in_nbytes'.
*
* As a special case, 'compressor' may be NULL. This causes the bound to be
* taken across *any* libdeflate_compressor that could ever be allocated with
* this build of the library, with any options.
*
* Note that this function is not necessary in many applications. With
* block-based compression, it is usually preferable to separately store the
* uncompressed size of each block and to store any blocks that did not compress
* to less than their original size uncompressed. In that scenario, there is no
* need to know the worst-case compressed size, since the maximum number of
* bytes of compressed data that may be used would always be one less than the
* input length. You can just pass a buffer of that size to
* libdeflate_deflate_compress() and store the data uncompressed if
* libdeflate_deflate_compress() returns 0, indicating that the compressed data
* did not fit into the provided output buffer.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_deflate_compress_bound(struct libdeflate_compressor *compressor,
size_t in_nbytes);
/*
* Like libdeflate_deflate_compress(), but stores the data in the zlib wrapper
* format.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_zlib_compress(struct libdeflate_compressor *compressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail);
/*
* Like libdeflate_deflate_compress_bound(), but assumes the data will be
* compressed with libdeflate_zlib_compress() rather than with
* libdeflate_deflate_compress().
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_zlib_compress_bound(struct libdeflate_compressor *compressor,
size_t in_nbytes);
/*
* Like libdeflate_deflate_compress(), but stores the data in the gzip wrapper
* format.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_gzip_compress(struct libdeflate_compressor *compressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail);
/*
* Like libdeflate_deflate_compress_bound(), but assumes the data will be
* compressed with libdeflate_gzip_compress() rather than with
* libdeflate_deflate_compress().
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_gzip_compress_bound(struct libdeflate_compressor *compressor,
size_t in_nbytes);
/*
* libdeflate_free_compressor() frees a compressor that was allocated with
* libdeflate_alloc_compressor(). If a NULL pointer is passed in, no action is
* taken.
*/
LIBDEFLATEEXPORT void LIBDEFLATEAPI
libdeflate_free_compressor(struct libdeflate_compressor *compressor);
/* ========================================================================== */
/* Decompression */
/* ========================================================================== */
struct libdeflate_decompressor;
/*
* libdeflate_alloc_decompressor() allocates a new decompressor that can be used
* for DEFLATE, zlib, and gzip decompression. The return value is a pointer to
* the new decompressor, or NULL if out of memory.
*
* This function takes no parameters, and the returned decompressor is valid for
* decompressing data that was compressed at any compression level and with any
* sliding window size.
*
* A single decompressor is not safe to use by multiple threads concurrently.
* However, different threads may use different decompressors concurrently.
*/
LIBDEFLATEEXPORT struct libdeflate_decompressor * LIBDEFLATEAPI
libdeflate_alloc_decompressor(void);
/*
* Result of a call to libdeflate_deflate_decompress(),
* libdeflate_zlib_decompress(), or libdeflate_gzip_decompress().
*/
enum libdeflate_result {
/* Decompression was successful. */
LIBDEFLATE_SUCCESS = 0,
/* Decompressed failed because the compressed data was invalid, corrupt,
* or otherwise unsupported. */
LIBDEFLATE_BAD_DATA = 1,
/* A NULL 'actual_out_nbytes_ret' was provided, but the data would have
* decompressed to fewer than 'out_nbytes_avail' bytes. */
LIBDEFLATE_SHORT_OUTPUT = 2,
/* The data would have decompressed to more than 'out_nbytes_avail'
* bytes. */
LIBDEFLATE_INSUFFICIENT_SPACE = 3,
};
/*
* libdeflate_deflate_decompress() decompresses the DEFLATE-compressed stream
* from the buffer 'in' with compressed size up to 'in_nbytes' bytes. The
* uncompressed data is written to 'out', a buffer with size 'out_nbytes_avail'
* bytes. If decompression succeeds, then 0 (LIBDEFLATE_SUCCESS) is returned.
* Otherwise, a nonzero result code such as LIBDEFLATE_BAD_DATA is returned. If
* a nonzero result code is returned, then the contents of the output buffer are
* undefined.
*
* Decompression stops at the end of the DEFLATE stream (as indicated by the
* BFINAL flag), even if it is actually shorter than 'in_nbytes' bytes.
*
* libdeflate_deflate_decompress() can be used in cases where the actual
* uncompressed size is known (recommended) or unknown (not recommended):
*
* - If the actual uncompressed size is known, then pass the actual
* uncompressed size as 'out_nbytes_avail' and pass NULL for
* 'actual_out_nbytes_ret'. This makes libdeflate_deflate_decompress() fail
* with LIBDEFLATE_SHORT_OUTPUT if the data decompressed to fewer than the
* specified number of bytes.
*
* - If the actual uncompressed size is unknown, then provide a non-NULL
* 'actual_out_nbytes_ret' and provide a buffer with some size
* 'out_nbytes_avail' that you think is large enough to hold all the
* uncompressed data. In this case, if the data decompresses to less than
* or equal to 'out_nbytes_avail' bytes, then
* libdeflate_deflate_decompress() will write the actual uncompressed size
* to *actual_out_nbytes_ret and return 0 (LIBDEFLATE_SUCCESS). Otherwise,
* it will return LIBDEFLATE_INSUFFICIENT_SPACE if the provided buffer was
* not large enough but no other problems were encountered, or another
* nonzero result code if decompression failed for another reason.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_deflate_decompress(struct libdeflate_decompressor *decompressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail,
size_t *actual_out_nbytes_ret);
/*
* Like libdeflate_deflate_decompress(), but adds the 'actual_in_nbytes_ret'
* argument. If decompression succeeds and 'actual_in_nbytes_ret' is not NULL,
* then the actual compressed size of the DEFLATE stream (aligned to the next
* byte boundary) is written to *actual_in_nbytes_ret.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_deflate_decompress_ex(struct libdeflate_decompressor *decompressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail,
size_t *actual_in_nbytes_ret,
size_t *actual_out_nbytes_ret);
/*
* Like libdeflate_deflate_decompress(), but assumes the zlib wrapper format
* instead of raw DEFLATE.
*
* Decompression will stop at the end of the zlib stream, even if it is shorter
* than 'in_nbytes'. If you need to know exactly where the zlib stream ended,
* use libdeflate_zlib_decompress_ex().
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_zlib_decompress(struct libdeflate_decompressor *decompressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail,
size_t *actual_out_nbytes_ret);
/*
* Like libdeflate_zlib_decompress(), but adds the 'actual_in_nbytes_ret'
* argument. If 'actual_in_nbytes_ret' is not NULL and the decompression
* succeeds (indicating that the first zlib-compressed stream in the input
* buffer was decompressed), then the actual number of input bytes consumed is
* written to *actual_in_nbytes_ret.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_zlib_decompress_ex(struct libdeflate_decompressor *decompressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail,
size_t *actual_in_nbytes_ret,
size_t *actual_out_nbytes_ret);
/*
* Like libdeflate_deflate_decompress(), but assumes the gzip wrapper format
* instead of raw DEFLATE.
*
* If multiple gzip-compressed members are concatenated, then only the first
* will be decompressed. Use libdeflate_gzip_decompress_ex() if you need
* multi-member support.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_gzip_decompress(struct libdeflate_decompressor *decompressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail,
size_t *actual_out_nbytes_ret);
/*
* Like libdeflate_gzip_decompress(), but adds the 'actual_in_nbytes_ret'
* argument. If 'actual_in_nbytes_ret' is not NULL and the decompression
* succeeds (indicating that the first gzip-compressed member in the input
* buffer was decompressed), then the actual number of input bytes consumed is
* written to *actual_in_nbytes_ret.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_gzip_decompress_ex(struct libdeflate_decompressor *decompressor,
const void *in, size_t in_nbytes,
void *out, size_t out_nbytes_avail,
size_t *actual_in_nbytes_ret,
size_t *actual_out_nbytes_ret);
/*
* libdeflate_free_decompressor() frees a decompressor that was allocated with
* libdeflate_alloc_decompressor(). If a NULL pointer is passed in, no action
* is taken.
*/
LIBDEFLATEEXPORT void LIBDEFLATEAPI
libdeflate_free_decompressor(struct libdeflate_decompressor *decompressor);
/* ========================================================================== */
/* Checksums */
/* ========================================================================== */
/*
* libdeflate_adler32() updates a running Adler-32 checksum with 'len' bytes of
* data and returns the updated checksum. When starting a new checksum, the
* required initial value for 'adler' is 1. This value is also returned when
* 'buffer' is specified as NULL.
*/
LIBDEFLATEEXPORT uint32_t LIBDEFLATEAPI
libdeflate_adler32(uint32_t adler, const void *buffer, size_t len);
/*
* libdeflate_crc32() updates a running CRC-32 checksum with 'len' bytes of data
* and returns the updated checksum. When starting a new checksum, the required
* initial value for 'crc' is 0. This value is also returned when 'buffer' is
* specified as NULL.
*/
LIBDEFLATEEXPORT uint32_t LIBDEFLATEAPI
libdeflate_crc32(uint32_t crc, const void *buffer, size_t len);
/* ========================================================================== */
/* Custom memory allocator */
/* ========================================================================== */
/*
* Install a custom memory allocator which libdeflate will use for all memory
* allocations. 'malloc_func' is a function that must behave like malloc(), and
* 'free_func' is a function that must behave like free().
*
* There must not be any libdeflate_compressor or libdeflate_decompressor
* structures in existence when calling this function.
*/
LIBDEFLATEEXPORT void LIBDEFLATEAPI
libdeflate_set_memory_allocator(void *(*malloc_func)(size_t),
void (*free_func)(void *));
/* ========================================================================== */
/* NVIDIA GDEFLATE-related API */
/* ========================================================================== */
/* ========================================================================== */
/* Compression */
/* ========================================================================== */
struct libdeflate_gdeflate_compressor;
struct libdeflate_gdeflate_out_page {
/* Buffer for compressed GDEFLATE page data. */
void *data;
/* Buffer size in bytes. If compression succeeded this field will
* contain the size of compressed GDEFLATE page.
*/
size_t nbytes;
};
struct libdeflate_gdeflate_in_page {
/* Compressed GDEFLATE page data. */
const void* data;
/* Size in bytes of compressed GDEFLATE page. */
size_t nbytes;
};
/*
* libdeflate_alloc_gdeflate_compressor() allocates a new compressor that
* supports GDEFLATE compression. 'compression_level' is the compression
* level on a zlib-like scale but with a higher maximum value (1 = fastest, 6 =
* medium/default, 9 = slow, 12 = slowest). Level 0 is also supported and means
* "no compression", specifically "create a valid stream, but only emit
* uncompressed blocks" (this will expand the data slightly).
*
* The return value is a pointer to the new compressor, or NULL if out of memory
* or if the compression level is invalid (i.e. outside the range [0, 12]).
*
* Note: for compression, the sliding window size is defined at compilation time
* to 65536, the largest size permissible in the GDEFLATE format. It cannot be
* changed at runtime.
*
* A single compressor is not safe to use by multiple threads concurrently.
* However, different threads may use different compressors concurrently.
*/
LIBDEFLATEEXPORT struct libdeflate_gdeflate_compressor * LIBDEFLATEAPI
libdeflate_alloc_gdeflate_compressor(int compression_level);
/*
* libdeflate_gdeflate_compress() performs raw GDEFLATE compression on a buffer
* of data. The function attempts to compress 'in_nbytes' bytes of data located
* at 'in' and writes page results to 'out_pages', which has preallocated 'data'
* with 'nbytes' space for each page. To determine the number of pages
* 'out_npages' the input data will be split into and the upper bound on
* compressed data use the libdeflate_gdeflate_compress_bound() function. The
* return value is the compressed size in bytes, or 0 if the data could not be
* compressed. If compression succeeded the size of each compressed page will
* be written to 'nbytes' field of 'out_pages'.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_gdeflate_compress(struct libdeflate_gdeflate_compressor *compressor,
const void *in, size_t in_nbytes,
struct libdeflate_gdeflate_out_page *out_pages,
size_t out_npages);
/*
* libdeflate_gdeflate_compress_ex() performs raw GDEFLATE compression on
* set of pages. The function attempts to compress 'npages' from 'in_pages'
* and writes page results to 'out_pages', which has preallocated 'data'
* with 'nbytes' space for each page. To determine the number of pages
* 'out_npages' the input data will be split into and the upper bound on
* compressed data use the libdeflate_gdeflate_compress_bound() function. The
* return value is the number of processed pages. If compression succeeded
* the size of each compressed page will be written to 'nbytes' field of 'out_pages'.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_gdeflate_compress_ex(struct libdeflate_gdeflate_compressor *compressor,
const struct libdeflate_gdeflate_in_page* in_pages,
struct libdeflate_gdeflate_out_page* out_pages, size_t npages);
/*
* libdeflate_gdeflate_compress_bound() returns a worst-case upper bound on the
* number of bytes of compressed data that may be produced by compressing any
* buffer of length less than or equal to 'in_nbytes' using
* libdeflate_gdeflate_compress() with the specified compressor. Mathematically,
* this bound will necessarily be a number greater than or equal to 'in_nbytes'.
* It may be an overestimate of the true upper bound. The return value is
* guaranteed to be the same for all invocations with the same compressor and
* same 'in_nbytes'. The 'out_npages' will contain the number of GDEFLATE pages
* the input data will be split into. This number should be used to preallocate
* the page array for libdeflate_gdeflate_compress(). The upper bound on the
* number of compressed data in a page can be found by dividing the function
* result by the 'out_npages' value.
*
* As a special case, 'compressor' may be NULL. This causes the bound to be
* taken across *any* libdeflate_compressor that could ever be allocated with
* this build of the library, with any options.
*/
LIBDEFLATEEXPORT size_t LIBDEFLATEAPI
libdeflate_gdeflate_compress_bound(struct libdeflate_gdeflate_compressor *comp,
size_t in_nbytes, size_t *out_npages);
/*
* libdeflate_free_gdeflate_compressor() frees a compressor that was allocated
* with libdeflate_alloc_gdeflate_compressor(). If a NULL pointer is passed in,
* no action is taken.
*/
LIBDEFLATEEXPORT void LIBDEFLATEAPI
libdeflate_free_gdeflate_compressor(struct libdeflate_gdeflate_compressor *comp);
/* ========================================================================== */
/* Decompression */
/* ========================================================================== */
struct libdeflate_gdeflate_decompressor;
/*
* libdeflate_alloc_gdeflate_decompressor() allocates a new decompressor that
* can be used for GDEFLATE decompression. The return value is a pointer to
* the new decompressor, or NULL if out of memory.
*
* This function takes no parameters, and the returned decompressor is valid for
* decompressing data that was compressed at any compression level and with any
* sliding window size.
*
* A single decompressor is not safe to use by multiple threads concurrently.
* However, different threads may use different decompressors concurrently.
*/
LIBDEFLATEEXPORT struct libdeflate_gdeflate_decompressor * LIBDEFLATEAPI
libdeflate_alloc_gdeflate_decompressor(void);
/*
* libdeflate_gdeflate_decompress() decompresses the GDEFLATE-compressed pages
* from the 'in_pages' array with 'in_npages' members. The uncompressed data is
* written to 'out', a buffer with size 'out_nbytes_avail' bytes.
* If decompression succeeds, then 0 (LIBDEFLATE_SUCCESS) is returned.
* Otherwise, a nonzero result code such as LIBDEFLATE_BAD_DATA is returned. If
* a nonzero result code is returned, then the contents of the output buffer are
* undefined.
*
* libdeflate_gdeflate_decompress() can be used only in cases where the actual
* uncompressed size is known.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_gdeflate_decompress(struct libdeflate_gdeflate_decompressor *decomp,
struct libdeflate_gdeflate_in_page *in_pages,
size_t in_npages, void *out,
size_t out_nbytes_avail,
size_t *actual_out_nbytes_ret);
/*
* libdeflate_gdeflate_decompress_ex() decompresses the GDEFLATE-compressed pages
* from the 'in_pages' array with 'npages' members. The uncompressed data is
* written to 'out_pages'.
* If decompression succeeds, then 0 (LIBDEFLATE_SUCCESS) is returned.
* Otherwise, a nonzero result code such as LIBDEFLATE_BAD_DATA is returned. If
* a nonzero result code is returned, then the contents of the output buffer are
* undefined.
*
* libdeflate_gdeflate_decompress_ex() can be used only in cases where the actual
* uncompressed size is known.
*/
LIBDEFLATEEXPORT enum libdeflate_result LIBDEFLATEAPI
libdeflate_gdeflate_decompress_ex(struct libdeflate_gdeflate_decompressor *decomp,
struct libdeflate_gdeflate_in_page *in_pages,
struct libdeflate_gdeflate_out_page* out_pages, size_t npages);
/*
* libdeflate_free_gdeflate_decompressor() frees a decompressor that was
* allocated with libdeflate_alloc_gdeflate_decompressor(). If a NULL pointer
* is passed in, no action is taken.
*/
LIBDEFLATEEXPORT void LIBDEFLATEAPI
libdeflate_free_gdeflate_decompressor(struct libdeflate_gdeflate_decompressor *decomp);
#ifdef __cplusplus
}
#endif
#endif /* LIBDEFLATE_H */