Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
Copyright 2026 Roberto A. Foglietta (RFC-1952)
Copyright 2013-2014 RAD Game Tools and Valve Software
Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC

Expand Down
20 changes: 11 additions & 9 deletions amalgamate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,26 +8,29 @@ OUTPUT_PREFIX=_build/amalgamation

cmake -H. -B_build -DAMALGAMATE_SOURCES=ON -G"Unix Makefiles"

if [ "${SKIPTESTS:-0}" != "1" ]; then

echo "int main() { return 0; }" > main.c
echo "Test compile with GCC..."
gcc -pedantic -Wall -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out
${CCPREFIX}gcc -pedantic -Wall -Wno-unused-function -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out
echo "Test compile with GCC ANSI..."
gcc -ansi -pedantic -Wall -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out
if command -v clang
then
echo "Test compile with clang..."
clang -Wall -Wpedantic -fsanitize=unsigned-integer-overflow -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out
${CCPREFIX}gcc -ansi -pedantic -Wall -Wno-unused-function -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out
if command -v clang; then
echo "Test compile with clang..."
clang -Wall -Wno-unused-function -Wpedantic -fsanitize=unsigned-integer-overflow -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out
fi
for def in MINIZ_NO_STDIO MINIZ_NO_TIME MINIZ_NO_DEFLATE_APIS MINIZ_NO_INFLATE_APIS MINIZ_NO_ARCHIVE_APIS MINIZ_NO_ARCHIVE_WRITING_APIS MINIZ_NO_ZLIB_APIS MINIZ_NO_ZLIB_COMPATIBLE_NAMES MINIZ_NO_MALLOC
do
echo "Test compile with GCC and define $def..."
gcc -ansi -pedantic -Wall -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out -D${def}
${CCPREFIX}gcc -ansi -pedantic -Wall -Wno-unused-function -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out -D${def}
done
echo "Test compile with GCC and MINIZ_USE_UNALIGNED_LOADS_AND_STORES=1..."
gcc -ansi -pedantic -Wall -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out -DMINIZ_USE_UNALIGNED_LOADS_AND_STORES=1
${CCPREFIX}gcc -ansi -pedantic -Wall -Wno-unused-function -I$OUTPUT_PREFIX main.c $OUTPUT_PREFIX/miniz.c -o test.out -DMINIZ_USE_UNALIGNED_LOADS_AND_STORES=1
rm test.out
rm main.c

fi # SKIP TESTS WHEN AREN'T USEFUL

cp $OUTPUT_PREFIX/miniz.* amalgamation/
cp ChangeLog.md amalgamation/
cp LICENSE amalgamation/
Expand All @@ -54,4 +57,3 @@ cd ..

echo "Amalgamation created."


14 changes: 12 additions & 2 deletions miniz.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)

if (!pStream)
return MZ_STREAM_ERROR;
if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
/* RAF: RFC 1952 */
if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS)
&& (window_bits != MZ_DEFAULT_WINDOW_BITS + 16) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
return MZ_PARAM_ERROR;

pStream->data_type = 0;
Expand Down Expand Up @@ -373,7 +375,9 @@ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
inflate_state *pDecomp;
if (!pStream)
return MZ_STREAM_ERROR;
if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))
/* RAF: RFC 1952 */
if ((window_bits != MZ_DEFAULT_WINDOW_BITS)
&& (window_bits != MZ_DEFAULT_WINDOW_BITS + 16) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))
return MZ_PARAM_ERROR;

pStream->data_type = 0;
Expand Down Expand Up @@ -451,7 +455,13 @@ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)

pState = (inflate_state *)pStream->state;
if (pState->m_window_bits > 0)
{
/* RAF: RFC 1952 */
if (pState->m_window_bits > 15)
decomp_flags |= TINFL_FLAG_PARSE_GZIP_HEADER;
else
decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
}
orig_avail_in = pStream->avail_in;

first_call = pState->m_first_call;
Expand Down
10 changes: 8 additions & 2 deletions miniz.h
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,10 @@ extern "C"
/* mz_deflateInit2() is like mz_deflate(), except with more control: */
/* Additional parameters: */
/* method must be MZ_DEFLATED */
/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */
/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer),
-MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer), or MZ_DEFAULT_WINDOW_BITS+16 (gzip header/CRC-32 footer)
//RAF: RFC 1952
*/
/* mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */
MINIZ_EXPORT int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);

Expand Down Expand Up @@ -413,7 +416,10 @@ extern "C"
MINIZ_EXPORT int mz_inflateInit(mz_streamp pStream);

/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */
/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */
/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer),
-MZ_DEFAULT_WINDOW_BITS (raw deflate) or MZ_DEFAULT_WINDOW_BITS+16 (gzip header/footer).
//RAF: RFC 1952
*/
MINIZ_EXPORT int mz_inflateInit2(mz_streamp pStream, int window_bits);

/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_inflateEnd() followed by mz_inflateInit()/mz_inflateInit2(). */
Expand Down
54 changes: 50 additions & 4 deletions miniz_tdef.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,7 +618,21 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
*d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);

if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
/* RAF: RFC 1952 */
if ((d->m_flags & TDEFL_WRITE_GZIP_HEADER) && (!d->m_block_index))
{
TDEFL_PUT_BITS(0x1f, 8);
TDEFL_PUT_BITS(0x8b, 8);
TDEFL_PUT_BITS(8, 8);
TDEFL_PUT_BITS(0, 8);
TDEFL_PUT_BITS(0, 8);
TDEFL_PUT_BITS(0, 8);
TDEFL_PUT_BITS(0, 8);
TDEFL_PUT_BITS(0, 8);
TDEFL_PUT_BITS(0, 8);
TDEFL_PUT_BITS(255, 8);
}
else if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
{
const mz_uint8 cmf = 0x78;
mz_uint8 flg, flevel = 3;
Expand Down Expand Up @@ -690,7 +704,24 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
{
TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
}
if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER)
/* RAF: RFC 1952 */
if (d->m_flags & TDEFL_WRITE_GZIP_HEADER)
{
mz_uint i;
mz_uint32 c = d->m_crc32;
for (i = 0; i < 4; i++)
{
TDEFL_PUT_BITS(c & 0xFF, 8);
c >>= 8;
}
c = d->m_total_uncomp_size;
for (i = 0; i < 4; i++)
{
TDEFL_PUT_BITS(c & 0xFF, 8);
c >>= 8;
}
}
else if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER)
{
mz_uint i, a = d->m_adler32;
for (i = 0; i < 4; i++)
Expand Down Expand Up @@ -1314,6 +1345,13 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe

if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
/* RAF: RFC 1952 */
if ((d->m_flags & TDEFL_WRITE_GZIP_HEADER) && (pIn_buf))
{
size_t n = d->m_pSrc - (const mz_uint8 *)pIn_buf;
d->m_crc32 = (mz_uint32)mz_crc32(d->m_crc32, (const mz_uint8 *)pIn_buf, n);
d->m_total_uncomp_size += (mz_uint32)n;
}

if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
{
Expand Down Expand Up @@ -1357,7 +1395,9 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe
d->m_pOutput_buf_end = d->m_output_buf;
d->m_prev_return_status = TDEFL_STATUS_OKAY;
d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
d->m_adler32 = 1;
d->m_adler32 = (flags & TDEFL_WRITE_GZIP_HEADER) ? 0 : 1; /* RAF: RFC 1952 */
d->m_crc32 = 0; /* RAF: RFC 1952 */
d->m_total_uncomp_size = 0; /* RAF: RFC 1952 */
d->m_pIn_buf = NULL;
d->m_pOut_buf = NULL;
d->m_pIn_buf_size = NULL;
Expand All @@ -1380,7 +1420,7 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe

mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
{
return d->m_adler32;
return (d->m_flags & TDEFL_WRITE_GZIP_HEADER) ? d->m_crc32 : d->m_adler32; /* RAF: RFC 1952 */
}

mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
Expand Down Expand Up @@ -1462,8 +1502,14 @@ static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahe
mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
{
mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
/* RAF: RFC 1952 */
if (window_bits > 0)
{
if (window_bits > 15)
comp_flags |= TDEFL_WRITE_GZIP_HEADER;
else
comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
}

if (!level)
comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
Expand Down
10 changes: 7 additions & 3 deletions miniz_tdef.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ extern "C"
TDEFL_RLE_MATCHES = 0x10000,
TDEFL_FILTER_MATCHES = 0x20000,
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000,
TDEFL_WRITE_GZIP_HEADER = 0x100000
/* RAF: RFC 1952 */
};

/* High level compression functions: */
Expand Down Expand Up @@ -140,7 +142,7 @@ enum
void *m_pPut_buf_user;
mz_uint m_flags, m_max_probes[2];
int m_greedy_parsing;
mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
mz_uint m_adler32, m_crc32, m_total_uncomp_size, m_lookahead_pos, m_lookahead_size, m_dict_size; /* RAF: RFC 1952 */
mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
Expand Down Expand Up @@ -180,7 +182,9 @@ enum

/* Create tdefl_compress() flags given zlib-style compression parameters. */
/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */
/* window_bits may be -15 (raw deflate) or 15 (zlib) */
/* window_bits may be -15 (raw deflate), 15 (zlib), or 31 (gzip)
//RAF: RFC 1952
*/
/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */
MINIZ_EXPORT mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);

Expand Down
104 changes: 104 additions & 0 deletions miniz_tinfl.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,74 @@ extern "C"

bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
r->m_z_adler32 = r->m_check_adler32 = 1;
r->m_check_crc32 = 0; /* RAF: RFC 1952 */

if (decomp_flags & TINFL_FLAG_PARSE_GZIP_HEADER)
{
/* RAF: RFC 1952 */
mz_uint8 flg;
/* ID1 */
TINFL_GET_BYTE(60, r->m_zhdr0);
if (r->m_zhdr0 != 0x1f)
{
TINFL_CR_RETURN_FOREVER(61, TINFL_STATUS_FAILED);
}
/* ID2 */
TINFL_GET_BYTE(62, r->m_zhdr1);
if (r->m_zhdr1 != 0x8b)
{
TINFL_CR_RETURN_FOREVER(63, TINFL_STATUS_FAILED);
}
/* CM (must be 8 for deflate) */
TINFL_GET_BYTE(64, r->m_zhdr0);
if (r->m_zhdr0 != 8)
{
TINFL_CR_RETURN_FOREVER(65, TINFL_STATUS_FAILED);
}
/* FLG */
TINFL_GET_BYTE(66, flg);
/* MTIME (4 bytes) */
TINFL_GET_BYTE(67, r->m_zhdr0);
TINFL_GET_BYTE(68, r->m_zhdr0);
TINFL_GET_BYTE(69, r->m_zhdr0);
TINFL_GET_BYTE(70, r->m_zhdr0);
/* XFL */
TINFL_GET_BYTE(71, r->m_zhdr0);
/* OS */
TINFL_GET_BYTE(72, r->m_zhdr0);
/* FEXTRA */
if (flg & 4)
{
mz_uint16 xlen;
TINFL_GET_BYTE(73, r->m_zhdr0); xlen = r->m_zhdr0;
TINFL_GET_BYTE(74, r->m_zhdr1); xlen |= ((mz_uint16)r->m_zhdr1 << 8);
while (xlen--)
{
TINFL_GET_BYTE(75, r->m_zhdr0);
}
}
/* FNAME */
if (flg & 8)
{
do {
TINFL_GET_BYTE(76, r->m_zhdr0);
} while (r->m_zhdr0);
}
/* FCOMMENT */
if (flg & 16)
{
do {
TINFL_GET_BYTE(77, r->m_zhdr0);
} while (r->m_zhdr0);
}
/* FHCRC */
if (flg & 2)
{
TINFL_GET_BYTE(78, r->m_zhdr0);
TINFL_GET_BYTE(79, r->m_zhdr0);
}
}
else
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
{
TINFL_GET_BYTE(1, r->m_zhdr0);
Expand Down Expand Up @@ -599,6 +667,9 @@ extern "C"
}
} while (!(r->m_final & 1));

/* dist_from_out_buf_start must reflect the true total output size for gzip ISIZE verification. */
dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; /* RAF: RFC 1952 */

/* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */
/* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */
TINFL_SKIP_BITS(32, num_bits & 7);
Expand All @@ -610,6 +681,29 @@ extern "C"
bit_buf &= ~(~(tinfl_bit_buf_t)0 << num_bits);
MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */

if (decomp_flags & TINFL_FLAG_PARSE_GZIP_HEADER)
{
/* RAF: RFC 1952 */
mz_uint i;
mz_uint32 crc32 = 0, isize = 0;
/* CRC32 (little-endian) */
for (i = 0; i < 4; ++i)
{
mz_uint s;
TINFL_GET_BYTE(81, s);
crc32 |= ((mz_uint32)s << (i * 8));
}
/* ISIZE (little-endian) */
for (i = 0; i < 4; ++i)
{
mz_uint s;
TINFL_GET_BYTE(82, s);
isize |= ((mz_uint32)s << (i * 8));
}
r->m_z_adler32 = crc32;
counter = isize;
}
else
if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
{
for (counter = 0; counter < 4; ++counter)
Expand Down Expand Up @@ -646,6 +740,16 @@ extern "C"
r->m_dist_from_out_buf_start = dist_from_out_buf_start;
*pIn_buf_size = pIn_buf_cur - pIn_buf_next;
*pOut_buf_size = pOut_buf_cur - pOut_buf_next;
if ((decomp_flags & TINFL_FLAG_PARSE_GZIP_HEADER) && (status >= 0))
{
/* RAF: RFC 1952 */
const mz_uint8 *ptr = pOut_buf_next;
size_t buf_len = *pOut_buf_size;
r->m_check_crc32 = (mz_uint32)mz_crc32(r->m_check_crc32, ptr, buf_len);
if ((status == TINFL_STATUS_DONE) && ((r->m_check_crc32 != r->m_z_adler32) || ((mz_uint32)r->m_dist_from_out_buf_start != r->m_counter)))
status = TINFL_STATUS_ADLER32_MISMATCH;
}
else
if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
{
const mz_uint8 *ptr = pOut_buf_next;
Expand Down
7 changes: 5 additions & 2 deletions miniz_tinfl.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ extern "C"
/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */
/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */
/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */
/* TINFL_FLAG_PARSE_GZIP_HEADER: If set, the input has a valid gzip header and ends with a CRC-32 checksum and ISIZE (it's a valid gzip stream per RFC 1952). */
enum
{
TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
TINFL_FLAG_HAS_MORE_INPUT = 2,
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
TINFL_FLAG_COMPUTE_ADLER32 = 8
TINFL_FLAG_COMPUTE_ADLER32 = 8,
TINFL_FLAG_PARSE_GZIP_HEADER = 16 /* RAF: RFC 1952 */
};

/* High level decompression functions: */
Expand Down Expand Up @@ -130,7 +132,8 @@ typedef mz_uint32 tinfl_bit_buf_t;

struct tinfl_decompressor_tag
{
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32,
m_check_crc32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; /* RAF: RFC 1952 */
tinfl_bit_buf_t m_bit_buf;
size_t m_dist_from_out_buf_start;
mz_int16 m_look_up[TINFL_MAX_HUFF_TABLES][TINFL_FAST_LOOKUP_SIZE];
Expand Down
Loading