2016-02-02 06:36:39 +01:00
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
See " unlicense " statement at the end of this file .
Rich Geldreich < richgel99 @ gmail . com > , last updated Oct . 13 , 2013
Implements RFC 1950 : http : //www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
Most API ' s defined in miniz . c are optional . For example , to disable the archive related functions just define
MINIZ_NO_ARCHIVE_APIS , or to get rid of all stdio usage define MINIZ_NO_STDIO ( see the list below for more macros ) .
* Change History
10 / 13 / 13 v1 .15 r4 - Interim bugfix release while I work on the next major release with Zip64 support ( almost there ! ) :
- Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug ( thanks kahmyong . moon @ hp . com ) which could cause locate files to not find files . This bug
would only have occured in earlier versions if you explicitly used this flag , OR if you used mz_zip_extract_archive_file_to_heap ( ) or mz_zip_add_mem_to_archive_file_in_place ( )
( which used this flag ) . If you can ' t switch to v1 .15 but want to fix this bug , just remove the uses of this flag from both helper funcs ( and of course don ' t use the flag ) .
- Bugfix in mz_zip_reader_extract_to_mem_no_alloc ( ) from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size
- Fixing mz_zip_reader_extract_ * ( ) funcs so they don ' t try to extract compressed data from directory entries , to account for weird zipfiles which contain zero - size compressed data on dir entries .
Hopefully this fix won ' t cause any issues on weird zip archives , because it assumes the low 16 - bits of zip external attributes are DOS attributes ( which I believe they always are in practice ) .
- Fixing mz_zip_reader_is_file_a_directory ( ) so it doesn ' t check the internal attributes , just the filename and external attributes
- mz_zip_reader_init_file ( ) - missing MZ_FCLOSE ( ) call if the seek failed
- Added cmake support for Linux builds which builds all the examples , tested with clang v3 .3 and gcc v4 .6 .
- Clang fix for tdefl_write_image_to_png_file_in_memory ( ) from toffaletti
- Merged MZ_FORCEINLINE fix from hdeanclark
- Fix < time . h > include before config # ifdef , thanks emil . brink
- Added tdefl_write_image_to_png_file_in_memory_ex ( ) : supports Y flipping ( super useful for OpenGL apps ) , and explicit control over the compression level ( so you can
set it to 1 for real - time compression ) .
- Merged in some compiler fixes from paulharris ' s github repro .
- Retested this build under Windows ( VS 2010 , including static analysis ) , tcc 0.9 .26 , gcc v4 .6 and clang v3 .3 .
- Added example6 . c , which dumps an image of the mandelbrot set to a PNG file .
- Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more .
- In r3 : Bugfix to mz_zip_writer_add_file ( ) found during merge : Fix possible src file fclose ( ) leak if alignment bytes + local header file write faiiled
- In r4 : Minor bugfix to mz_zip_writer_add_from_zip_reader ( ) : Was pushing the wrong central dir header offset , appears harmless in this release , but it became a problem in the zip64 branch
5 / 20 / 12 v1 .14 - MinGW32 / 64 GCC 4.6 .1 compiler fixes : added MZ_FORCEINLINE , # include < time . h > ( thanks fermtect ) .
5 / 19 / 12 v1 .13 - From jason @ cornsyrup . org and kelwert @ mtu . edu - Fix mz_crc32 ( ) so it doesn ' t compute the wrong CRC - 32 ' s when mz_ulong is 64 - bit .
- Temporarily / locally slammed in " typedef unsigned long mz_ulong " and re - ran a randomized regression test on ~ 500 k files .
- Eliminated a bunch of warnings when compiling with GCC 32 - bit / 64.
- Ran all examples , miniz . c , and tinfl . c through MSVC 2008 ' s / analyze ( static analysis ) option and fixed all warnings ( except for the silly
" Use of the comma-operator in a tested expression.. " analysis warning , which I purposely use to work around a MSVC compiler warning ) .
- Created 32 - bit and 64 - bit Codeblocks projects / workspace . Built and tested Linux executables . The codeblocks workspace is compatible with Linux + Win32 / x64 .
- Added miniz_tester solution / project , which is a useful little app derived from LZHAM ' s tester app that I use as part of the regression test .
- Ran miniz . c and tinfl . c through another series of regression testing on ~ 500 , 000 files and archives .
- Modified example5 . c so it purposely disables a bunch of high - level functionality ( MINIZ_NO_STDIO , etc . ) . ( Thanks to corysama for the MINIZ_NO_STDIO bug report . )
- Fix ftell ( ) usage in examples so they exit with an error on files which are too large ( a limitation of the examples , not miniz itself ) .
4 / 12 / 12 v1 .12 - More comments , added low - level example5 . c , fixed a couple minor level_and_flags issues in the archive API ' s .
level_and_flags can now be set to MZ_DEFAULT_COMPRESSION . Thanks to Bruce Dawson < bruced @ valvesoftware . com > for the feedback / bug report .
5 / 28 / 11 v1 .11 - Added statement from unlicense . org
5 / 27 / 11 v1 .10 - Substantial compressor optimizations :
- Level 1 is now ~ 4 x faster than before . The L1 compressor ' s throughput now varies between 70 - 110 MB / sec . on a
- Core i7 ( actual throughput varies depending on the type of data , and x64 vs . x86 ) .
- Improved baseline L2 - L9 compression perf . Also , greatly improved compression perf . issues on some file types .
- Refactored the compression code for better readability and maintainability .
- Added level 10 compression level ( L10 has slightly better ratio than level 9 , but could have a potentially large
drop in throughput on some files ) .
5 / 15 / 11 v1 .09 - Initial stable release .
* Low - level Deflate / Inflate implementation notes :
Compression : Use the " tdefl " API ' s . The compressor supports raw , static , and dynamic blocks , lazy or
greedy parsing , match length filtering , RLE - only , and Huffman - only streams . It performs and compresses
approximately as well as zlib .
Decompression : Use the " tinfl " API ' s . The entire decompressor is implemented as a single function
coroutine : see tinfl_decompress ( ) . It supports decompression into a 32 KB ( or larger power of 2 ) wrapping buffer , or into a memory
block large enough to hold the entire file .
The low - level tdefl / tinfl API ' s do not make any use of dynamic memory allocation .
* zlib - style API notes :
miniz . c implements a fairly large subset of zlib . There ' s enough functionality present for it to be a drop - in
zlib replacement in many apps :
The z_stream struct , optional memory allocation callbacks
deflateInit / deflateInit2 / deflate / deflateReset / deflateEnd / deflateBound
inflateInit / inflateInit2 / inflate / inflateEnd
compress , compress2 , compressBound , uncompress
CRC - 32 , Adler - 32 - Using modern , minimal code size , CPU cache friendly routines .
Supports raw deflate streams or standard zlib streams with adler - 32 checking .
Limitations :
The callback API ' s are not implemented yet . No support for gzip headers or zlib static dictionaries .
I ' ve tried to closely emulate zlib ' s various flavors of stream flushing and return status codes , but
there are no guarantees that miniz . c pulls this off perfectly .
* PNG writing : See the tdefl_write_image_to_png_file_in_memory ( ) function , originally written by
Alex Evans . Supports 1 - 4 bytes / pixel images .
* ZIP archive API notes :
The ZIP archive API ' s where designed with simplicity and efficiency in mind , with just enough abstraction to
get the job done with minimal fuss . There are simple API ' s to retrieve file information , read files from
existing archives , create new archives , append new files to existing archives , or clone archive data from
one archive to another . It supports archives located in memory or the heap , on disk ( using stdio . h ) ,
or you can specify custom file read / write callbacks .
- Archive reading : Just call this function to read a single file from a disk archive :
void * mz_zip_extract_archive_file_to_heap ( const char * pZip_filename , const char * pArchive_name ,
size_t * pSize , mz_uint zip_flags ) ;
For more complex cases , use the " mz_zip_reader " functions . Upon opening an archive , the entire central
directory is located and read as - is into memory , and subsequent file access only occurs when reading individual files .
- Archives file scanning : The simple way is to use this function to scan a loaded archive for a specific file :
int mz_zip_reader_locate_file ( mz_zip_archive * pZip , const char * pName , const char * pComment , mz_uint flags ) ;
The locate operation can optionally check file comments too , which ( as one example ) can be used to identify
multiple versions of the same file in an archive . This function uses a simple linear search through the central
directory , so it ' s not very fast .
Alternately , you can iterate through all the files in an archive ( using mz_zip_reader_get_num_files ( ) ) and
retrieve detailed info on each file by calling mz_zip_reader_file_stat ( ) .
- Archive creation : Use the " mz_zip_writer " functions . The ZIP writer immediately writes compressed file data
to disk and builds an exact image of the central directory in memory . The central directory image is written
all at once at the end of the archive file when the archive is finalized .
The archive writer can optionally align each file ' s local header and file data to any power of 2 alignment ,
which can be useful when the archive will be read from optical media . Also , the writer supports placing
arbitrary data blobs at the very beginning of ZIP archives . Archives written using either feature are still
readable by any ZIP tool .
- Archive appending : The simple way to add a single file to an archive is to call this function :
mz_bool mz_zip_add_mem_to_archive_file_in_place ( const char * pZip_filename , const char * pArchive_name ,
const void * pBuf , size_t buf_size , const void * pComment , mz_uint16 comment_size , mz_uint level_and_flags ) ;
The archive will be created if it doesn ' t already exist , otherwise it ' ll be appended to .
Note the appending is done in - place and is not an atomic operation , so if something goes wrong
during the operation it ' s possible the archive could be left without a central directory ( although the local
file headers and file data will be fine , so the archive will be recoverable ) .
For more complex archive modification scenarios :
1. The safest way is to use a mz_zip_reader to read the existing archive , cloning only those bits you want to
preserve into a new archive using using the mz_zip_writer_add_from_zip_reader ( ) function ( which compiles the
compressed file data as - is ) . When you ' re done , delete the old archive and rename the newly written archive , and
you ' re done . This is safe but requires a bunch of temporary disk space or heap memory .
2. Or , you can convert an mz_zip_reader in - place to an mz_zip_writer using mz_zip_writer_init_from_reader ( ) ,
append new files as needed , then finalize the archive which will write an updated central directory to the
original archive . ( This is basically what mz_zip_add_mem_to_archive_file_in_place ( ) does . ) There ' s a
possibility that the archive ' s central directory could be lost with this method if anything goes wrong , though .
- ZIP archive support limitations :
No zip64 or spanning support . Extraction functions can only handle unencrypted , stored or deflated files .
Requires streams capable of seeking .
* This is a header file library , like stb_image . c . To get only a header file , either cut and paste the
below header , or create miniz . h , # define MINIZ_HEADER_FILE_ONLY , and then include miniz . c from it .
* Important : For best perf . be sure to customize the below macros for your target platform :
# define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
# define MINIZ_LITTLE_ENDIAN 1
# define MINIZ_HAS_64BIT_REGISTERS 1
* On platforms using glibc , Be sure to " #define _LARGEFILE64_SOURCE 1 " before including miniz . c to ensure miniz
uses the 64 - bit variants : fopen64 ( ) , stat64 ( ) , etc . Otherwise you won ' t be able to process large files
( i . e . 32 - bit stat ( ) fails for me on files > 0x7FFFFFFF bytes ) .
*/
# ifndef MINIZ_HEADER_INCLUDED
# define MINIZ_HEADER_INCLUDED
# include <stdlib.h>
// Defines to completely disable specific portions of miniz.c:
// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl.
// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O.
# define MINIZ_NO_STDIO
// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or
// get/set file times, and the C run-time funcs that get/set times won't be called.
// The current downside is the times written to your archives will be from 1979.
# define MINIZ_NO_TIME
// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
# define MINIZ_NO_ARCHIVE_APIS
// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's.
# define MINIZ_NO_ARCHIVE_WRITING_APIS
// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's.
//#define MINIZ_NO_ZLIB_APIS
// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib.
# define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
//#define MINIZ_NO_MALLOC
# if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux
# define MINIZ_NO_TIME
# endif
# if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
# include <time.h>
# endif
# if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
# define MINIZ_X86_OR_X64_CPU 1
# endif
# if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
# define MINIZ_LITTLE_ENDIAN 1
# endif
# if MINIZ_X86_OR_X64_CPU
// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses.
# define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
# endif
# if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions).
# define MINIZ_HAS_64BIT_REGISTERS 1
# endif
// ------------------- zlib-style API Definitions.
// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
typedef unsigned long mz_ulong ;
// Compression strategies.
enum { MZ_DEFAULT_STRATEGY = 0 , MZ_FILTERED = 1 , MZ_HUFFMAN_ONLY = 2 , MZ_RLE = 3 , MZ_FIXED = 4 } ;
// Method
# define MZ_DEFLATED 8
# ifndef MINIZ_NO_ZLIB_APIS
// Heap allocation callbacks.
// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long.
typedef void * ( * mz_alloc_func ) ( void * opaque , size_t items , size_t size ) ;
typedef void ( * mz_free_func ) ( void * opaque , void * address ) ;
typedef void * ( * mz_realloc_func ) ( void * opaque , void * address , size_t items , size_t size ) ;
# define MZ_VERSION "9.1.15"
# define MZ_VERNUM 0x91F0
# define MZ_VER_MAJOR 9
# define MZ_VER_MINOR 1
# define MZ_VER_REVISION 15
# define MZ_VER_SUBREVISION 0
// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs).
enum { MZ_NO_FLUSH = 0 , MZ_PARTIAL_FLUSH = 1 , MZ_SYNC_FLUSH = 2 , MZ_FULL_FLUSH = 3 , MZ_FINISH = 4 , MZ_BLOCK = 5 } ;
// Return status codes. MZ_PARAM_ERROR is non-standard.
enum { MZ_OK = 0 , MZ_STREAM_END = 1 , MZ_NEED_DICT = 2 , MZ_ERRNO = - 1 , MZ_STREAM_ERROR = - 2 , MZ_DATA_ERROR = - 3 , MZ_MEM_ERROR = - 4 , MZ_BUF_ERROR = - 5 , MZ_VERSION_ERROR = - 6 , MZ_PARAM_ERROR = - 10000 } ;
// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
enum { MZ_NO_COMPRESSION = 0 , MZ_BEST_SPEED = 1 , MZ_BEST_COMPRESSION = 9 , MZ_UBER_COMPRESSION = 10 , MZ_DEFAULT_LEVEL = 6 , MZ_DEFAULT_COMPRESSION = - 1 } ;
// Window bits
# define MZ_DEFAULT_WINDOW_BITS 15
struct mz_internal_state ;
// Compression/decompression stream struct.
typedef struct mz_stream_s
{
const unsigned char * next_in ; // pointer to next byte to read
unsigned int avail_in ; // number of bytes available at next_in
mz_ulong total_in ; // total number of bytes consumed so far
unsigned char * next_out ; // pointer to next byte to write
unsigned int avail_out ; // number of bytes that can be written to next_out
mz_ulong total_out ; // total number of bytes produced so far
char * msg ; // error msg (unused)
struct mz_internal_state * state ; // internal state, allocated by zalloc/zfree
mz_alloc_func zalloc ; // optional heap allocation function (defaults to malloc)
mz_free_func zfree ; // optional heap free function (defaults to free)
void * opaque ; // heap alloc function user pointer
int data_type ; // data_type (unused)
mz_ulong reserved ; // not used
} mz_stream ;
typedef mz_stream * mz_streamp ;
// mz_deflateInit() initializes a compressor with default options:
// Parameters:
// pStream must point to an initialized mz_stream struct.
// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio.
// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
// Return values:
// MZ_OK on success.
// MZ_STREAM_ERROR if the stream is bogus.
// MZ_PARAM_ERROR if the input parameters are bogus.
// MZ_MEM_ERROR on out of memory.
static int mz_deflateInit ( mz_streamp pStream , int level ) ;
// 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)
// mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
static int mz_deflateInit2 ( mz_streamp pStream , int level , int method , int window_bits , int mem_level , int strategy ) ;
// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible.
// Parameters:
// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH.
// Return values:
// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full).
// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore.
// MZ_STREAM_ERROR if the stream is bogus.
// MZ_PARAM_ERROR if one of the parameters is invalid.
// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.)
static int mz_deflate ( mz_streamp pStream , int flush ) ;
// mz_deflateEnd() deinitializes a compressor:
// Return values:
// MZ_OK on success.
// MZ_STREAM_ERROR if the stream is bogus.
static int mz_deflateEnd ( mz_streamp pStream ) ;
// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH.
static mz_ulong mz_deflateBound ( mz_streamp pStream , mz_ulong source_len ) ;
// Single-call compression functions mz_compress() and mz_compress2():
// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure.
static int mz_compress ( unsigned char * pDest , mz_ulong * pDest_len , const unsigned char * pSource , mz_ulong source_len ) ;
static int mz_compress2 ( unsigned char * pDest , mz_ulong * pDest_len , const unsigned char * pSource , mz_ulong source_len , int level ) ;
// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress().
static mz_ulong mz_compressBound ( mz_ulong source_len ) ;
// Returns a string description of the specified error code, or NULL if the error code is invalid.
static const char * mz_error ( int err ) ;
# endif // MINIZ_NO_ZLIB_APIS
// ------------------- Types and macros
typedef unsigned char mz_uint8 ;
typedef signed short mz_int16 ;
typedef unsigned short mz_uint16 ;
typedef unsigned int mz_uint32 ;
typedef unsigned int mz_uint ;
typedef long long mz_int64 ;
typedef unsigned long long mz_uint64 ;
typedef int mz_bool ;
# define MZ_FALSE (0)
# define MZ_TRUE (1)
// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message.
# ifdef _MSC_VER
# define MZ_MACRO_END while (0, 0)
# else
# define MZ_MACRO_END while (0)
# endif
// ------------------- ZIP archive reading/writing
# ifndef MINIZ_NO_ARCHIVE_APIS
enum
{
MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024 ,
MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260 ,
MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
} ;
typedef struct
{
mz_uint32 m_file_index ;
mz_uint32 m_central_dir_ofs ;
mz_uint16 m_version_made_by ;
mz_uint16 m_version_needed ;
mz_uint16 m_bit_flag ;
mz_uint16 m_method ;
# ifndef MINIZ_NO_TIME
time_t m_time ;
# endif
mz_uint32 m_crc32 ;
mz_uint64 m_comp_size ;
mz_uint64 m_uncomp_size ;
mz_uint16 m_internal_attr ;
mz_uint32 m_external_attr ;
mz_uint64 m_local_header_ofs ;
mz_uint32 m_comment_size ;
char m_filename [ MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE ] ;
char m_comment [ MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE ] ;
} mz_zip_archive_file_stat ;
typedef size_t ( * mz_file_read_func ) ( void * pOpaque , mz_uint64 file_ofs , void * pBuf , size_t n ) ;
typedef size_t ( * mz_file_write_func ) ( void * pOpaque , mz_uint64 file_ofs , const void * pBuf , size_t n ) ;
struct mz_zip_internal_state_tag ;
typedef struct mz_zip_internal_state_tag mz_zip_internal_state ;
typedef enum
{
MZ_ZIP_MODE_INVALID = 0 ,
MZ_ZIP_MODE_READING = 1 ,
MZ_ZIP_MODE_WRITING = 2 ,
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
} mz_zip_mode ;
typedef struct mz_zip_archive_tag
{
mz_uint64 m_archive_size ;
mz_uint64 m_central_directory_file_ofs ;
mz_uint m_total_files ;
mz_zip_mode m_zip_mode ;
mz_uint m_file_offset_alignment ;
mz_alloc_func m_pAlloc ;
mz_free_func m_pFree ;
mz_realloc_func m_pRealloc ;
void * m_pAlloc_opaque ;
mz_file_read_func m_pRead ;
mz_file_write_func m_pWrite ;
void * m_pIO_opaque ;
mz_zip_internal_state * m_pState ;
} mz_zip_archive ;
typedef enum
{
MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100 ,
MZ_ZIP_FLAG_IGNORE_PATH = 0x0200 ,
MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400 ,
MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
} mz_zip_flags ;
// ZIP archive reading
// Inits a ZIP archive reader.
// These functions read and validate the archive's central directory.
static mz_bool mz_zip_reader_init ( mz_zip_archive * pZip , mz_uint64 size , mz_uint32 flags ) ;
static mz_bool mz_zip_reader_init_mem ( mz_zip_archive * pZip , const void * pMem , size_t size , mz_uint32 flags ) ;
# ifndef MINIZ_NO_STDIO
static mz_bool mz_zip_reader_init_file ( mz_zip_archive * pZip , const char * pFilename , mz_uint32 flags ) ;
# endif
// Returns the total number of files in the archive.
static mz_uint mz_zip_reader_get_num_files ( mz_zip_archive * pZip ) ;
// Returns detailed information about an archive file entry.
static mz_bool mz_zip_reader_file_stat ( mz_zip_archive * pZip , mz_uint file_index , mz_zip_archive_file_stat * pStat ) ;
// Determines if an archive file entry is a directory entry.
static mz_bool mz_zip_reader_is_file_a_directory ( mz_zip_archive * pZip , mz_uint file_index ) ;
static mz_bool mz_zip_reader_is_file_encrypted ( mz_zip_archive * pZip , mz_uint file_index ) ;
// Retrieves the filename of an archive file entry.
// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename.
static mz_uint mz_zip_reader_get_filename ( mz_zip_archive * pZip , mz_uint file_index , char * pFilename , mz_uint filename_buf_size ) ;
// Attempts to locates a file in the archive's central directory.
// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
// Returns -1 if the file cannot be found.
static int mz_zip_reader_locate_file ( mz_zip_archive * pZip , const char * pName , const char * pComment , mz_uint flags ) ;
// Extracts a archive file to a memory buffer using no memory allocation.
static mz_bool mz_zip_reader_extract_to_mem_no_alloc ( mz_zip_archive * pZip , mz_uint file_index , void * pBuf , size_t buf_size , mz_uint flags , void * pUser_read_buf , size_t user_read_buf_size ) ;
static mz_bool mz_zip_reader_extract_file_to_mem_no_alloc ( mz_zip_archive * pZip , const char * pFilename , void * pBuf , size_t buf_size , mz_uint flags , void * pUser_read_buf , size_t user_read_buf_size ) ;
// Extracts a archive file to a memory buffer.
static mz_bool mz_zip_reader_extract_to_mem ( mz_zip_archive * pZip , mz_uint file_index , void * pBuf , size_t buf_size , mz_uint flags ) ;
static mz_bool mz_zip_reader_extract_file_to_mem ( mz_zip_archive * pZip , const char * pFilename , void * pBuf , size_t buf_size , mz_uint flags ) ;
// Extracts a archive file to a dynamically allocated heap buffer.
static void * mz_zip_reader_extract_to_heap ( mz_zip_archive * pZip , mz_uint file_index , size_t * pSize , mz_uint flags ) ;
static void * mz_zip_reader_extract_file_to_heap ( mz_zip_archive * pZip , const char * pFilename , size_t * pSize , mz_uint flags ) ;
// Extracts a archive file using a callback function to output the file's data.
static mz_bool mz_zip_reader_extract_to_callback ( mz_zip_archive * pZip , mz_uint file_index , mz_file_write_func pCallback , void * pOpaque , mz_uint flags ) ;
static mz_bool mz_zip_reader_extract_file_to_callback ( mz_zip_archive * pZip , const char * pFilename , mz_file_write_func pCallback , void * pOpaque , mz_uint flags ) ;
# ifndef MINIZ_NO_STDIO
// Extracts a archive file to a disk file and sets its last accessed and modified times.
// This function only extracts files, not archive directory records.
static mz_bool mz_zip_reader_extract_to_file ( mz_zip_archive * pZip , mz_uint file_index , const char * pDst_filename , mz_uint flags ) ;
static mz_bool mz_zip_reader_extract_file_to_file ( mz_zip_archive * pZip , const char * pArchive_filename , const char * pDst_filename , mz_uint flags ) ;
# endif
// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used.
static mz_bool mz_zip_reader_end ( mz_zip_archive * pZip ) ;
// ZIP archive writing
# ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
// Inits a ZIP archive writer.
static mz_bool mz_zip_writer_init ( mz_zip_archive * pZip , mz_uint64 existing_size ) ;
static mz_bool mz_zip_writer_init_heap ( mz_zip_archive * pZip , size_t size_to_reserve_at_beginning , size_t initial_allocation_size ) ;
# ifndef MINIZ_NO_STDIO
static mz_bool mz_zip_writer_init_file ( mz_zip_archive * pZip , const char * pFilename , mz_uint64 size_to_reserve_at_beginning ) ;
# endif
// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive.
// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called.
// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it).
// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL.
// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before
// the archive is finalized the file's central directory will be hosed.
static mz_bool mz_zip_writer_init_from_reader ( mz_zip_archive * pZip , const char * pFilename ) ;
// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive.
// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer.
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
static mz_bool mz_zip_writer_add_mem ( mz_zip_archive * pZip , const char * pArchive_name , const void * pBuf , size_t buf_size , mz_uint level_and_flags ) ;
static mz_bool mz_zip_writer_add_mem_ex ( mz_zip_archive * pZip , const char * pArchive_name , const void * pBuf , size_t buf_size , const void * pComment , mz_uint16 comment_size , mz_uint level_and_flags , mz_uint64 uncomp_size , mz_uint32 uncomp_crc32 ) ;
# ifndef MINIZ_NO_STDIO
// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive.
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
static mz_bool mz_zip_writer_add_file ( mz_zip_archive * pZip , const char * pArchive_name , const char * pSrc_filename , const void * pComment , mz_uint16 comment_size , mz_uint level_and_flags ) ;
# endif
// Adds a file to an archive by fully cloning the data from another archive.
// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields.
static mz_bool mz_zip_writer_add_from_zip_reader ( mz_zip_archive * pZip , mz_zip_archive * pSource_zip , mz_uint file_index ) ;
// Finalizes the archive by writing the central directory records followed by the end of central directory record.
// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end().
// An archive must be manually finalized by calling this function for it to be valid.
static mz_bool mz_zip_writer_finalize_archive ( mz_zip_archive * pZip ) ;
static mz_bool mz_zip_writer_finalize_heap_archive ( mz_zip_archive * pZip , void * * pBuf , size_t * pSize ) ;
// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used.
// Note for the archive to be valid, it must have been finalized before ending.
static mz_bool mz_zip_writer_end ( mz_zip_archive * pZip ) ;
// Misc. high-level helper functions:
// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive.
// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
static mz_bool mz_zip_add_mem_to_archive_file_in_place ( const char * pZip_filename , const char * pArchive_name , const void * pBuf , size_t buf_size , const void * pComment , mz_uint16 comment_size , mz_uint level_and_flags ) ;
// Reads a single file from an archive into a heap block.
// Returns NULL on failure.
static void * mz_zip_extract_archive_file_to_heap ( const char * pZip_filename , const char * pArchive_name , size_t * pSize , mz_uint zip_flags ) ;
# endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
# endif // #ifndef MINIZ_NO_ARCHIVE_APIS
// ------------------- Low-level Compression API Definitions
// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently).
# define TDEFL_LESS_MEMORY 1
// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search):
// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression).
enum
{
TDEFL_HUFFMAN_ONLY = 0 , TDEFL_DEFAULT_MAX_PROBES = 128 , TDEFL_MAX_PROBES_MASK = 0xFFF
} ;
// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing.
// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory).
// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK).
enum
{
TDEFL_GREEDY_PARSING_FLAG = 0x04000 ,
TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000 ,
TDEFL_RLE_MATCHES = 0x10000 ,
TDEFL_FILTER_MATCHES = 0x20000 ,
TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000 ,
TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
} ;
// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
typedef mz_bool ( * tdefl_put_buf_func_ptr ) ( const void * pBuf , int len , void * pUser ) ;
enum { TDEFL_MAX_HUFF_TABLES = 3 , TDEFL_MAX_HUFF_SYMBOLS_0 = 288 , TDEFL_MAX_HUFF_SYMBOLS_1 = 32 , TDEFL_MAX_HUFF_SYMBOLS_2 = 19 , TDEFL_LZ_DICT_SIZE = 32768 , TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1 , TDEFL_MIN_MATCH_LEN = 3 , TDEFL_MAX_MATCH_LEN = 258 } ;
// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes).
# if TDEFL_LESS_MEMORY
enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024 , TDEFL_OUT_BUF_SIZE = ( TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10 , TDEFL_MAX_HUFF_SYMBOLS = 288 , TDEFL_LZ_HASH_BITS = 12 , TDEFL_LEVEL1_HASH_SIZE_MASK = 4095 , TDEFL_LZ_HASH_SHIFT = ( TDEFL_LZ_HASH_BITS + 2 ) / 3 , TDEFL_LZ_HASH_SIZE = 1 < < TDEFL_LZ_HASH_BITS } ;
# else
enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024 , TDEFL_OUT_BUF_SIZE = ( TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10 , TDEFL_MAX_HUFF_SYMBOLS = 288 , TDEFL_LZ_HASH_BITS = 15 , TDEFL_LEVEL1_HASH_SIZE_MASK = 4095 , TDEFL_LZ_HASH_SHIFT = ( TDEFL_LZ_HASH_BITS + 2 ) / 3 , TDEFL_LZ_HASH_SIZE = 1 < < TDEFL_LZ_HASH_BITS } ;
# endif
// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions.
typedef enum
{
TDEFL_STATUS_BAD_PARAM = - 2 ,
TDEFL_STATUS_PUT_BUF_FAILED = - 1 ,
TDEFL_STATUS_OKAY = 0 ,
TDEFL_STATUS_DONE = 1 ,
} tdefl_status ;
// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
typedef enum
{
TDEFL_NO_FLUSH = 0 ,
TDEFL_SYNC_FLUSH = 2 ,
TDEFL_FULL_FLUSH = 3 ,
TDEFL_FINISH = 4
} tdefl_flush ;
// tdefl's compression state structure.
typedef struct
{
tdefl_put_buf_func_ptr m_pPut_buf_func ;
void * m_pPut_buf_user ;
mz_uint m_flags , m_max_probes [ 2 ] ;
int m_greedy_parsing ;
mz_uint m_lookahead_pos , m_lookahead_size , m_dict_size ;
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 ;
tdefl_status m_prev_return_status ;
const void * m_pIn_buf ;
void * m_pOut_buf ;
size_t * m_pIn_buf_size , * m_pOut_buf_size ;
tdefl_flush m_flush ;
const mz_uint8 * m_pSrc ;
size_t m_src_buf_left , m_out_buf_ofs ;
mz_uint8 m_dict [ TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1 ] ;
mz_uint16 m_huff_count [ TDEFL_MAX_HUFF_TABLES ] [ TDEFL_MAX_HUFF_SYMBOLS ] ;
mz_uint16 m_huff_codes [ TDEFL_MAX_HUFF_TABLES ] [ TDEFL_MAX_HUFF_SYMBOLS ] ;
mz_uint8 m_huff_code_sizes [ TDEFL_MAX_HUFF_TABLES ] [ TDEFL_MAX_HUFF_SYMBOLS ] ;
mz_uint8 m_lz_code_buf [ TDEFL_LZ_CODE_BUF_SIZE ] ;
mz_uint16 m_next [ TDEFL_LZ_DICT_SIZE ] ;
mz_uint16 m_hash [ TDEFL_LZ_HASH_SIZE ] ;
mz_uint8 m_output_buf [ TDEFL_OUT_BUF_SIZE ] ;
} tdefl_compressor ;
// Initializes the compressor.
// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory.
// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression.
// If pBut_buf_func is NULL the user should always call the tdefl_compress() API.
// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
static tdefl_status tdefl_init ( tdefl_compressor * d , tdefl_put_buf_func_ptr pPut_buf_func , void * pPut_buf_user , int flags ) ;
// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible.
static tdefl_status tdefl_compress ( tdefl_compressor * d , const void * pIn_buf , size_t * pIn_buf_size , void * pOut_buf , size_t * pOut_buf_size , tdefl_flush flush ) ;
// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros.
# ifndef MINIZ_NO_ZLIB_APIS
// 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)
// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED
static mz_uint tdefl_create_comp_flags_from_zip_params ( int level , int window_bits , int strategy ) ;
# endif // #ifndef MINIZ_NO_ZLIB_APIS
# ifdef __cplusplus
}
# endif
# endif // MINIZ_HEADER_INCLUDED
// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
# ifndef MINIZ_HEADER_FILE_ONLY
typedef unsigned char mz_validate_uint16 [ sizeof ( mz_uint16 ) = = 2 ? 1 : - 1 ] ;
typedef unsigned char mz_validate_uint32 [ sizeof ( mz_uint32 ) = = 4 ? 1 : - 1 ] ;
typedef unsigned char mz_validate_uint64 [ sizeof ( mz_uint64 ) = = 8 ? 1 : - 1 ] ;
# include <string.h>
# include <assert.h>
# define MZ_ASSERT(x) assert(x)
# ifdef MINIZ_NO_MALLOC
# define MZ_MALLOC(x) NULL
# define MZ_FREE(x) (void)x, ((void)0)
# define MZ_REALLOC(p, x) NULL
# else
# define MZ_MALLOC(x) malloc(x)
# define MZ_FREE(x) free(x)
# define MZ_REALLOC(p, x) realloc(p, x)
# endif
# define MZ_MAX(a,b) (((a)>(b))?(a):(b))
# define MZ_MIN(a,b) (((a)<(b))?(a):(b))
# define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
# if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
# define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
# define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
# else
# define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
# define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
# endif
# ifdef _MSC_VER
# define MZ_FORCEINLINE __forceinline
# elif defined(__GNUC__)
# define MZ_FORCEINLINE inline __attribute__((__always_inline__))
# else
# define MZ_FORCEINLINE inline
# endif
# ifdef __cplusplus
extern " C " {
# endif
// ------------------- zlib-style API's
# ifndef MINIZ_NO_ZLIB_APIS
static void * def_alloc_func ( void * opaque , size_t items , size_t size ) { ( void ) opaque , ( void ) items , ( void ) size ; return MZ_MALLOC ( items * size ) ; }
static void def_free_func ( void * opaque , void * address ) { ( void ) opaque , ( void ) address ; MZ_FREE ( address ) ; }
int mz_deflateInit ( mz_streamp pStream , int level )
{
return mz_deflateInit2 ( pStream , level , MZ_DEFLATED , MZ_DEFAULT_WINDOW_BITS , 9 , MZ_DEFAULT_STRATEGY ) ;
}
int mz_deflateInit2 ( mz_streamp pStream , int level , int method , int window_bits , int mem_level , int strategy )
{
tdefl_compressor * pComp ;
mz_uint comp_flags = tdefl_create_comp_flags_from_zip_params ( level , window_bits , strategy ) ;
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 ) ) ) return MZ_PARAM_ERROR ;
pStream - > data_type = 0 ;
pStream - > msg = NULL ;
pStream - > reserved = 0 ;
pStream - > total_in = 0 ;
pStream - > total_out = 0 ;
if ( ! pStream - > zalloc ) pStream - > zalloc = def_alloc_func ;
if ( ! pStream - > zfree ) pStream - > zfree = def_free_func ;
pComp = ( tdefl_compressor * ) pStream - > zalloc ( pStream - > opaque , 1 , sizeof ( tdefl_compressor ) ) ;
if ( ! pComp )
return MZ_MEM_ERROR ;
pStream - > state = ( struct mz_internal_state * ) pComp ;
if ( tdefl_init ( pComp , NULL , NULL , comp_flags ) ! = TDEFL_STATUS_OKAY )
{
mz_deflateEnd ( pStream ) ;
return MZ_PARAM_ERROR ;
}
return MZ_OK ;
}
int mz_deflate ( mz_streamp pStream , int flush )
{
size_t in_bytes , out_bytes ;
mz_ulong orig_total_in , orig_total_out ;
int mz_status = MZ_OK ;
if ( ( ! pStream ) | | ( ! pStream - > state ) | | ( flush < 0 ) | | ( flush > MZ_FINISH ) | | ( ! pStream - > next_out ) ) return MZ_STREAM_ERROR ;
if ( ! pStream - > avail_out ) return MZ_BUF_ERROR ;
if ( flush = = MZ_PARTIAL_FLUSH ) flush = MZ_SYNC_FLUSH ;
if ( ( ( tdefl_compressor * ) pStream - > state ) - > m_prev_return_status = = TDEFL_STATUS_DONE )
return ( flush = = MZ_FINISH ) ? MZ_STREAM_END : MZ_BUF_ERROR ;
orig_total_in = pStream - > total_in ; orig_total_out = pStream - > total_out ;
for ( ; ; )
{
tdefl_status defl_status ;
in_bytes = pStream - > avail_in ; out_bytes = pStream - > avail_out ;
defl_status = tdefl_compress ( ( tdefl_compressor * ) pStream - > state , pStream - > next_in , & in_bytes , pStream - > next_out , & out_bytes , ( tdefl_flush ) flush ) ;
pStream - > next_in + = ( mz_uint ) in_bytes ; pStream - > avail_in - = ( mz_uint ) in_bytes ;
pStream - > total_in + = ( mz_uint ) in_bytes ;
pStream - > next_out + = ( mz_uint ) out_bytes ; pStream - > avail_out - = ( mz_uint ) out_bytes ;
pStream - > total_out + = ( mz_uint ) out_bytes ;
if ( defl_status < 0 )
{
mz_status = MZ_STREAM_ERROR ;
break ;
}
else if ( defl_status = = TDEFL_STATUS_DONE )
{
mz_status = MZ_STREAM_END ;
break ;
}
else if ( ! pStream - > avail_out )
break ;
else if ( ( ! pStream - > avail_in ) & & ( flush ! = MZ_FINISH ) )
{
if ( ( flush ) | | ( pStream - > total_in ! = orig_total_in ) | | ( pStream - > total_out ! = orig_total_out ) )
break ;
return MZ_BUF_ERROR ; // Can't make forward progress without some input.
}
}
return mz_status ;
}
int mz_deflateEnd ( mz_streamp pStream )
{
if ( ! pStream ) return MZ_STREAM_ERROR ;
if ( pStream - > state )
{
pStream - > zfree ( pStream - > opaque , pStream - > state ) ;
pStream - > state = NULL ;
}
return MZ_OK ;
}
mz_ulong mz_deflateBound ( mz_streamp pStream , mz_ulong source_len )
{
( void ) pStream ;
// This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.)
return MZ_MAX ( 128 + ( source_len * 110 ) / 100 , 128 + source_len + ( ( source_len / ( 31 * 1024 ) ) + 1 ) * 5 ) ;
}
int mz_compress2 ( unsigned char * pDest , mz_ulong * pDest_len , const unsigned char * pSource , mz_ulong source_len , int level )
{
int status ;
mz_stream stream ;
memset ( & stream , 0 , sizeof ( stream ) ) ;
// In case mz_ulong is 64-bits (argh I hate longs).
if ( ( source_len | * pDest_len ) > 0xFFFFFFFFU ) return MZ_PARAM_ERROR ;
stream . next_in = pSource ;
stream . avail_in = ( mz_uint32 ) source_len ;
stream . next_out = pDest ;
stream . avail_out = ( mz_uint32 ) * pDest_len ;
status = mz_deflateInit ( & stream , level ) ;
if ( status ! = MZ_OK ) return status ;
status = mz_deflate ( & stream , MZ_FINISH ) ;
if ( status ! = MZ_STREAM_END )
{
mz_deflateEnd ( & stream ) ;
return ( status = = MZ_OK ) ? MZ_BUF_ERROR : status ;
}
* pDest_len = stream . total_out ;
return mz_deflateEnd ( & stream ) ;
}
__attribute__ ( ( __unused__ ) ) int mz_compress ( unsigned char * pDest , mz_ulong * pDest_len , const unsigned char * pSource , mz_ulong source_len )
{
return mz_compress2 ( pDest , pDest_len , pSource , source_len , MZ_DEFAULT_COMPRESSION ) ;
}
__attribute__ ( ( __unused__ ) ) mz_ulong mz_compressBound ( mz_ulong source_len )
{
return mz_deflateBound ( NULL , source_len ) ;
}
__attribute__ ( ( __unused__ ) ) const char * mz_error ( int err )
{
static struct { int m_err ; const char * m_pDesc ; } s_error_descs [ ] =
{
{ MZ_OK , " " } , { MZ_STREAM_END , " stream end " } , { MZ_NEED_DICT , " need dictionary " } , { MZ_ERRNO , " file error " } , { MZ_STREAM_ERROR , " stream error " } ,
{ MZ_DATA_ERROR , " data error " } , { MZ_MEM_ERROR , " out of memory " } , { MZ_BUF_ERROR , " buf error " } , { MZ_VERSION_ERROR , " version error " } , { MZ_PARAM_ERROR , " parameter error " }
} ;
mz_uint i ; for ( i = 0 ; i < sizeof ( s_error_descs ) / sizeof ( s_error_descs [ 0 ] ) ; + + i ) if ( s_error_descs [ i ] . m_err = = err ) return s_error_descs [ i ] . m_pDesc ;
return NULL ;
}
# endif //MINIZ_NO_ZLIB_APIS
// ------------------- Low-level Compression (independent from all decompression API's)
// Purposely making these tables static for faster init and thread safety.
static const mz_uint16 s_tdefl_len_sym [ 256 ] = {
257 , 258 , 259 , 260 , 261 , 262 , 263 , 264 , 265 , 265 , 266 , 266 , 267 , 267 , 268 , 268 , 269 , 269 , 269 , 269 , 270 , 270 , 270 , 270 , 271 , 271 , 271 , 271 , 272 , 272 , 272 , 272 ,
273 , 273 , 273 , 273 , 273 , 273 , 273 , 273 , 274 , 274 , 274 , 274 , 274 , 274 , 274 , 274 , 275 , 275 , 275 , 275 , 275 , 275 , 275 , 275 , 276 , 276 , 276 , 276 , 276 , 276 , 276 , 276 ,
277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 277 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 , 278 ,
279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 279 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 , 280 ,
281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 , 281 ,
282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 , 282 ,
283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 , 283 ,
284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 284 , 285 } ;
static const mz_uint8 s_tdefl_len_extra [ 256 ] = {
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 ,
4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 ,
5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 ,
5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 0 } ;
static const mz_uint8 s_tdefl_small_dist_sym [ 512 ] = {
0 , 1 , 2 , 3 , 4 , 4 , 5 , 5 , 6 , 6 , 6 , 6 , 7 , 7 , 7 , 7 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 8 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 9 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 11 , 11 , 11 , 11 , 11 , 11 ,
11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 13 ,
13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 ,
14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 ,
14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 14 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 ,
15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 15 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 ,
16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 ,
16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 ,
16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 ,
17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 ,
17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 ,
17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 , 17 } ;
static const mz_uint8 s_tdefl_small_dist_extra [ 512 ] = {
0 , 0 , 0 , 0 , 1 , 1 , 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 3 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 4 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 ,
5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 5 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 ,
6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 ,
6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 6 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 ,
7 , 7 , 7 , 7 , 7 , 7 , 7 , 7 } ;
static const mz_uint8 s_tdefl_large_dist_sym [ 128 ] = {
0 , 0 , 18 , 19 , 20 , 20 , 21 , 21 , 22 , 22 , 22 , 22 , 23 , 23 , 23 , 23 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 25 , 25 , 25 , 25 , 25 , 25 , 25 , 25 , 26 , 26 , 26 , 26 , 26 , 26 , 26 , 26 , 26 , 26 , 26 , 26 ,
26 , 26 , 26 , 26 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 27 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 ,
28 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 , 29 } ;
static const mz_uint8 s_tdefl_large_dist_extra [ 128 ] = {
0 , 0 , 8 , 8 , 9 , 9 , 9 , 9 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 10 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 11 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 ,
12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 12 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 ,
13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 , 13 } ;
// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values.
typedef struct { mz_uint16 m_key , m_sym_index ; } tdefl_sym_freq ;
static tdefl_sym_freq * tdefl_radix_sort_syms ( mz_uint num_syms , tdefl_sym_freq * pSyms0 , tdefl_sym_freq * pSyms1 )
{
mz_uint32 total_passes = 2 , pass_shift , pass , i , hist [ 256 * 2 ] ; tdefl_sym_freq * pCur_syms = pSyms0 , * pNew_syms = pSyms1 ; MZ_CLEAR_OBJ ( hist ) ;
for ( i = 0 ; i < num_syms ; i + + ) { mz_uint freq = pSyms0 [ i ] . m_key ; hist [ freq & 0xFF ] + + ; hist [ 256 + ( ( freq > > 8 ) & 0xFF ) ] + + ; }
while ( ( total_passes > 1 ) & & ( num_syms = = hist [ ( total_passes - 1 ) * 256 ] ) ) total_passes - - ;
for ( pass_shift = 0 , pass = 0 ; pass < total_passes ; pass + + , pass_shift + = 8 )
{
const mz_uint32 * pHist = & hist [ pass < < 8 ] ;
mz_uint offsets [ 256 ] , cur_ofs = 0 ;
for ( i = 0 ; i < 256 ; i + + ) { offsets [ i ] = cur_ofs ; cur_ofs + = pHist [ i ] ; }
for ( i = 0 ; i < num_syms ; i + + ) pNew_syms [ offsets [ ( pCur_syms [ i ] . m_key > > pass_shift ) & 0xFF ] + + ] = pCur_syms [ i ] ;
{ tdefl_sym_freq * t = pCur_syms ; pCur_syms = pNew_syms ; pNew_syms = t ; }
}
return pCur_syms ;
}
// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
static void tdefl_calculate_minimum_redundancy ( tdefl_sym_freq * A , int n )
{
int root , leaf , next , avbl , used , dpth ;
if ( n = = 0 ) return ; else if ( n = = 1 ) { A [ 0 ] . m_key = 1 ; return ; }
A [ 0 ] . m_key + = A [ 1 ] . m_key ; root = 0 ; leaf = 2 ;
for ( next = 1 ; next < n - 1 ; next + + )
{
if ( leaf > = n | | A [ root ] . m_key < A [ leaf ] . m_key ) { A [ next ] . m_key = A [ root ] . m_key ; A [ root + + ] . m_key = ( mz_uint16 ) next ; } else A [ next ] . m_key = A [ leaf + + ] . m_key ;
if ( leaf > = n | | ( root < next & & A [ root ] . m_key < A [ leaf ] . m_key ) ) { A [ next ] . m_key = ( mz_uint16 ) ( A [ next ] . m_key + A [ root ] . m_key ) ; A [ root + + ] . m_key = ( mz_uint16 ) next ; } else A [ next ] . m_key = ( mz_uint16 ) ( A [ next ] . m_key + A [ leaf + + ] . m_key ) ;
}
A [ n - 2 ] . m_key = 0 ; for ( next = n - 3 ; next > = 0 ; next - - ) A [ next ] . m_key = A [ A [ next ] . m_key ] . m_key + 1 ;
avbl = 1 ; used = dpth = 0 ; root = n - 2 ; next = n - 1 ;
while ( avbl > 0 )
{
while ( root > = 0 & & ( int ) A [ root ] . m_key = = dpth ) { used + + ; root - - ; }
while ( avbl > used ) { A [ next - - ] . m_key = ( mz_uint16 ) ( dpth ) ; avbl - - ; }
avbl = 2 * used ; dpth + + ; used = 0 ;
}
}
// Limits canonical Huffman code table's max code size.
enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 } ;
static void tdefl_huffman_enforce_max_code_size ( int * pNum_codes , int code_list_len , int max_code_size )
{
int i ; mz_uint32 total = 0 ; if ( code_list_len < = 1 ) return ;
for ( i = max_code_size + 1 ; i < = TDEFL_MAX_SUPPORTED_HUFF_CODESIZE ; i + + ) pNum_codes [ max_code_size ] + = pNum_codes [ i ] ;
for ( i = max_code_size ; i > 0 ; i - - ) total + = ( ( ( mz_uint32 ) pNum_codes [ i ] ) < < ( max_code_size - i ) ) ;
while ( total ! = ( 1UL < < max_code_size ) )
{
pNum_codes [ max_code_size ] - - ;
for ( i = max_code_size - 1 ; i > 0 ; i - - ) if ( pNum_codes [ i ] ) { pNum_codes [ i ] - - ; pNum_codes [ i + 1 ] + = 2 ; break ; }
total - - ;
}
}
static void tdefl_optimize_huffman_table ( tdefl_compressor * d , int table_num , int table_len , int code_size_limit , int static_table )
{
int i , j , l , num_codes [ 1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE ] ; mz_uint next_code [ TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1 ] ; MZ_CLEAR_OBJ ( num_codes ) ;
if ( static_table )
{
for ( i = 0 ; i < table_len ; i + + ) num_codes [ d - > m_huff_code_sizes [ table_num ] [ i ] ] + + ;
}
else
{
tdefl_sym_freq syms0 [ TDEFL_MAX_HUFF_SYMBOLS ] , syms1 [ TDEFL_MAX_HUFF_SYMBOLS ] , * pSyms ;
int num_used_syms = 0 ;
const mz_uint16 * pSym_count = & d - > m_huff_count [ table_num ] [ 0 ] ;
for ( i = 0 ; i < table_len ; i + + ) if ( pSym_count [ i ] ) { syms0 [ num_used_syms ] . m_key = ( mz_uint16 ) pSym_count [ i ] ; syms0 [ num_used_syms + + ] . m_sym_index = ( mz_uint16 ) i ; }
pSyms = tdefl_radix_sort_syms ( num_used_syms , syms0 , syms1 ) ; tdefl_calculate_minimum_redundancy ( pSyms , num_used_syms ) ;
for ( i = 0 ; i < num_used_syms ; i + + ) num_codes [ pSyms [ i ] . m_key ] + + ;
tdefl_huffman_enforce_max_code_size ( num_codes , num_used_syms , code_size_limit ) ;
MZ_CLEAR_OBJ ( d - > m_huff_code_sizes [ table_num ] ) ; MZ_CLEAR_OBJ ( d - > m_huff_codes [ table_num ] ) ;
for ( i = 1 , j = num_used_syms ; i < = code_size_limit ; i + + )
for ( l = num_codes [ i ] ; l > 0 ; l - - ) d - > m_huff_code_sizes [ table_num ] [ pSyms [ - - j ] . m_sym_index ] = ( mz_uint8 ) ( i ) ;
}
next_code [ 1 ] = 0 ; for ( j = 0 , i = 2 ; i < = code_size_limit ; i + + ) next_code [ i ] = j = ( ( j + num_codes [ i - 1 ] ) < < 1 ) ;
for ( i = 0 ; i < table_len ; i + + )
{
mz_uint rev_code = 0 , code , code_size ; if ( ( code_size = d - > m_huff_code_sizes [ table_num ] [ i ] ) = = 0 ) continue ;
code = next_code [ code_size ] + + ; for ( l = code_size ; l > 0 ; l - - , code > > = 1 ) rev_code = ( rev_code < < 1 ) | ( code & 1 ) ;
d - > m_huff_codes [ table_num ] [ i ] = ( mz_uint16 ) rev_code ;
}
}
# define TDEFL_PUT_BITS(b, l) do { \
mz_uint bits = b ; mz_uint len = l ; MZ_ASSERT ( bits < = ( ( 1U < < len ) - 1U ) ) ; \
d - > m_bit_buffer | = ( bits < < d - > m_bits_in ) ; d - > m_bits_in + = len ; \
while ( d - > m_bits_in > = 8 ) { \
if ( d - > m_pOutput_buf < d - > m_pOutput_buf_end ) \
* d - > m_pOutput_buf + + = ( mz_uint8 ) ( d - > m_bit_buffer ) ; \
d - > m_bit_buffer > > = 8 ; \
d - > m_bits_in - = 8 ; \
} \
} MZ_MACRO_END
# define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \
if ( rle_repeat_count < 3 ) { \
d - > m_huff_count [ 2 ] [ prev_code_size ] = ( mz_uint16 ) ( d - > m_huff_count [ 2 ] [ prev_code_size ] + rle_repeat_count ) ; \
while ( rle_repeat_count - - ) packed_code_sizes [ num_packed_code_sizes + + ] = prev_code_size ; \
} else { \
d - > m_huff_count [ 2 ] [ 16 ] = ( mz_uint16 ) ( d - > m_huff_count [ 2 ] [ 16 ] + 1 ) ; packed_code_sizes [ num_packed_code_sizes + + ] = 16 ; packed_code_sizes [ num_packed_code_sizes + + ] = ( mz_uint8 ) ( rle_repeat_count - 3 ) ; \
} rle_repeat_count = 0 ; } }
# define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \
if ( rle_z_count < 3 ) { \
d - > m_huff_count [ 2 ] [ 0 ] = ( mz_uint16 ) ( d - > m_huff_count [ 2 ] [ 0 ] + rle_z_count ) ; while ( rle_z_count - - ) packed_code_sizes [ num_packed_code_sizes + + ] = 0 ; \
} else if ( rle_z_count < = 10 ) { \
d - > m_huff_count [ 2 ] [ 17 ] = ( mz_uint16 ) ( d - > m_huff_count [ 2 ] [ 17 ] + 1 ) ; packed_code_sizes [ num_packed_code_sizes + + ] = 17 ; packed_code_sizes [ num_packed_code_sizes + + ] = ( mz_uint8 ) ( rle_z_count - 3 ) ; \
} else { \
d - > m_huff_count [ 2 ] [ 18 ] = ( mz_uint16 ) ( d - > m_huff_count [ 2 ] [ 18 ] + 1 ) ; packed_code_sizes [ num_packed_code_sizes + + ] = 18 ; packed_code_sizes [ num_packed_code_sizes + + ] = ( mz_uint8 ) ( rle_z_count - 11 ) ; \
} rle_z_count = 0 ; } }
static mz_uint8 s_tdefl_packed_code_size_syms_swizzle [ ] = { 16 , 17 , 18 , 0 , 8 , 7 , 9 , 6 , 10 , 5 , 11 , 4 , 12 , 3 , 13 , 2 , 14 , 1 , 15 } ;
static void tdefl_start_dynamic_block ( tdefl_compressor * d )
{
int num_lit_codes , num_dist_codes , num_bit_lengths ; mz_uint i , total_code_sizes_to_pack , num_packed_code_sizes , rle_z_count , rle_repeat_count , packed_code_sizes_index ;
mz_uint8 code_sizes_to_pack [ TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1 ] , packed_code_sizes [ TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1 ] , prev_code_size = 0xFF ;
d - > m_huff_count [ 0 ] [ 256 ] = 1 ;
tdefl_optimize_huffman_table ( d , 0 , TDEFL_MAX_HUFF_SYMBOLS_0 , 15 , MZ_FALSE ) ;
tdefl_optimize_huffman_table ( d , 1 , TDEFL_MAX_HUFF_SYMBOLS_1 , 15 , MZ_FALSE ) ;
for ( num_lit_codes = 286 ; num_lit_codes > 257 ; num_lit_codes - - ) if ( d - > m_huff_code_sizes [ 0 ] [ num_lit_codes - 1 ] ) break ;
for ( num_dist_codes = 30 ; num_dist_codes > 1 ; num_dist_codes - - ) if ( d - > m_huff_code_sizes [ 1 ] [ num_dist_codes - 1 ] ) break ;
memcpy ( code_sizes_to_pack , & d - > m_huff_code_sizes [ 0 ] [ 0 ] , num_lit_codes ) ;
memcpy ( code_sizes_to_pack + num_lit_codes , & d - > m_huff_code_sizes [ 1 ] [ 0 ] , num_dist_codes ) ;
total_code_sizes_to_pack = num_lit_codes + num_dist_codes ; num_packed_code_sizes = 0 ; rle_z_count = 0 ; rle_repeat_count = 0 ;
memset ( & d - > m_huff_count [ 2 ] [ 0 ] , 0 , sizeof ( d - > m_huff_count [ 2 ] [ 0 ] ) * TDEFL_MAX_HUFF_SYMBOLS_2 ) ;
for ( i = 0 ; i < total_code_sizes_to_pack ; i + + )
{
mz_uint8 code_size = code_sizes_to_pack [ i ] ;
if ( ! code_size )
{
TDEFL_RLE_PREV_CODE_SIZE ( ) ;
if ( + + rle_z_count = = 138 ) { TDEFL_RLE_ZERO_CODE_SIZE ( ) ; }
}
else
{
TDEFL_RLE_ZERO_CODE_SIZE ( ) ;
if ( code_size ! = prev_code_size )
{
TDEFL_RLE_PREV_CODE_SIZE ( ) ;
d - > m_huff_count [ 2 ] [ code_size ] = ( mz_uint16 ) ( d - > m_huff_count [ 2 ] [ code_size ] + 1 ) ; packed_code_sizes [ num_packed_code_sizes + + ] = code_size ;
}
else if ( + + rle_repeat_count = = 6 )
{
TDEFL_RLE_PREV_CODE_SIZE ( ) ;
}
}
prev_code_size = code_size ;
}
if ( rle_repeat_count ) { TDEFL_RLE_PREV_CODE_SIZE ( ) ; } else { TDEFL_RLE_ZERO_CODE_SIZE ( ) ; }
tdefl_optimize_huffman_table ( d , 2 , TDEFL_MAX_HUFF_SYMBOLS_2 , 7 , MZ_FALSE ) ;
TDEFL_PUT_BITS ( 2 , 2 ) ;
TDEFL_PUT_BITS ( num_lit_codes - 257 , 5 ) ;
TDEFL_PUT_BITS ( num_dist_codes - 1 , 5 ) ;
for ( num_bit_lengths = 18 ; num_bit_lengths > = 0 ; num_bit_lengths - - ) if ( d - > m_huff_code_sizes [ 2 ] [ s_tdefl_packed_code_size_syms_swizzle [ num_bit_lengths ] ] ) break ;
num_bit_lengths = MZ_MAX ( 4 , ( num_bit_lengths + 1 ) ) ; TDEFL_PUT_BITS ( num_bit_lengths - 4 , 4 ) ;
for ( i = 0 ; ( int ) i < num_bit_lengths ; i + + ) TDEFL_PUT_BITS ( d - > m_huff_code_sizes [ 2 ] [ s_tdefl_packed_code_size_syms_swizzle [ i ] ] , 3 ) ;
for ( packed_code_sizes_index = 0 ; packed_code_sizes_index < num_packed_code_sizes ; )
{
mz_uint code = packed_code_sizes [ packed_code_sizes_index + + ] ; MZ_ASSERT ( code < TDEFL_MAX_HUFF_SYMBOLS_2 ) ;
TDEFL_PUT_BITS ( d - > m_huff_codes [ 2 ] [ code ] , d - > m_huff_code_sizes [ 2 ] [ code ] ) ;
if ( code > = 16 ) TDEFL_PUT_BITS ( packed_code_sizes [ packed_code_sizes_index + + ] , " \02 \03 \07 " [ code - 16 ] ) ;
}
}
static void tdefl_start_static_block ( tdefl_compressor * d )
{
mz_uint i ;
mz_uint8 * p = & d - > m_huff_code_sizes [ 0 ] [ 0 ] ;
for ( i = 0 ; i < = 143 ; + + i ) * p + + = 8 ;
for ( ; i < = 255 ; + + i ) * p + + = 9 ;
for ( ; i < = 279 ; + + i ) * p + + = 7 ;
for ( ; i < = 287 ; + + i ) * p + + = 8 ;
memset ( d - > m_huff_code_sizes [ 1 ] , 5 , 32 ) ;
tdefl_optimize_huffman_table ( d , 0 , 288 , 15 , MZ_TRUE ) ;
tdefl_optimize_huffman_table ( d , 1 , 32 , 15 , MZ_TRUE ) ;
TDEFL_PUT_BITS ( 1 , 2 ) ;
}
static const mz_uint mz_bitmasks [ 17 ] = { 0x0000 , 0x0001 , 0x0003 , 0x0007 , 0x000F , 0x001F , 0x003F , 0x007F , 0x00FF , 0x01FF , 0x03FF , 0x07FF , 0x0FFF , 0x1FFF , 0x3FFF , 0x7FFF , 0xFFFF } ;
# if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
static mz_bool tdefl_compress_lz_codes ( tdefl_compressor * d )
{
mz_uint flags ;
mz_uint8 * pLZ_codes ;
mz_uint8 * pOutput_buf = d - > m_pOutput_buf ;
mz_uint8 * pLZ_code_buf_end = d - > m_pLZ_code_buf ;
mz_uint64 bit_buffer = d - > m_bit_buffer ;
mz_uint bits_in = d - > m_bits_in ;
# define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); }
flags = 1 ;
for ( pLZ_codes = d - > m_lz_code_buf ; pLZ_codes < pLZ_code_buf_end ; flags > > = 1 )
{
if ( flags = = 1 )
flags = * pLZ_codes + + | 0x100 ;
if ( flags & 1 )
{
mz_uint s0 , s1 , n0 , n1 , sym , num_extra_bits ;
mz_uint match_len = pLZ_codes [ 0 ] , match_dist = * ( const mz_uint16 * ) ( pLZ_codes + 1 ) ; pLZ_codes + = 3 ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 0 ] [ s_tdefl_len_sym [ match_len ] ] ) ;
TDEFL_PUT_BITS_FAST ( d - > m_huff_codes [ 0 ] [ s_tdefl_len_sym [ match_len ] ] , d - > m_huff_code_sizes [ 0 ] [ s_tdefl_len_sym [ match_len ] ] ) ;
TDEFL_PUT_BITS_FAST ( match_len & mz_bitmasks [ s_tdefl_len_extra [ match_len ] ] , s_tdefl_len_extra [ match_len ] ) ;
// This sequence coaxes MSVC into using cmov's vs. jmp's.
s0 = s_tdefl_small_dist_sym [ match_dist & 511 ] ;
n0 = s_tdefl_small_dist_extra [ match_dist & 511 ] ;
s1 = s_tdefl_large_dist_sym [ match_dist > > 8 ] ;
n1 = s_tdefl_large_dist_extra [ match_dist > > 8 ] ;
sym = ( match_dist < 512 ) ? s0 : s1 ;
num_extra_bits = ( match_dist < 512 ) ? n0 : n1 ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 1 ] [ sym ] ) ;
TDEFL_PUT_BITS_FAST ( d - > m_huff_codes [ 1 ] [ sym ] , d - > m_huff_code_sizes [ 1 ] [ sym ] ) ;
TDEFL_PUT_BITS_FAST ( match_dist & mz_bitmasks [ num_extra_bits ] , num_extra_bits ) ;
}
else
{
mz_uint lit = * pLZ_codes + + ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
TDEFL_PUT_BITS_FAST ( d - > m_huff_codes [ 0 ] [ lit ] , d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
if ( ( ( flags & 2 ) = = 0 ) & & ( pLZ_codes < pLZ_code_buf_end ) )
{
flags > > = 1 ;
lit = * pLZ_codes + + ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
TDEFL_PUT_BITS_FAST ( d - > m_huff_codes [ 0 ] [ lit ] , d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
if ( ( ( flags & 2 ) = = 0 ) & & ( pLZ_codes < pLZ_code_buf_end ) )
{
flags > > = 1 ;
lit = * pLZ_codes + + ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
TDEFL_PUT_BITS_FAST ( d - > m_huff_codes [ 0 ] [ lit ] , d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
}
}
}
if ( pOutput_buf > = d - > m_pOutput_buf_end )
return MZ_FALSE ;
* ( mz_uint64 * ) pOutput_buf = bit_buffer ;
pOutput_buf + = ( bits_in > > 3 ) ;
bit_buffer > > = ( bits_in & ~ 7 ) ;
bits_in & = 7 ;
}
# undef TDEFL_PUT_BITS_FAST
d - > m_pOutput_buf = pOutput_buf ;
d - > m_bits_in = 0 ;
d - > m_bit_buffer = 0 ;
while ( bits_in )
{
mz_uint32 n = MZ_MIN ( bits_in , 16 ) ;
TDEFL_PUT_BITS ( ( mz_uint ) bit_buffer & mz_bitmasks [ n ] , n ) ;
bit_buffer > > = n ;
bits_in - = n ;
}
TDEFL_PUT_BITS ( d - > m_huff_codes [ 0 ] [ 256 ] , d - > m_huff_code_sizes [ 0 ] [ 256 ] ) ;
return ( d - > m_pOutput_buf < d - > m_pOutput_buf_end ) ;
}
# else
static mz_bool tdefl_compress_lz_codes ( tdefl_compressor * d )
{
mz_uint flags ;
mz_uint8 * pLZ_codes ;
flags = 1 ;
for ( pLZ_codes = d - > m_lz_code_buf ; pLZ_codes < d - > m_pLZ_code_buf ; flags > > = 1 )
{
if ( flags = = 1 )
flags = * pLZ_codes + + | 0x100 ;
if ( flags & 1 )
{
mz_uint sym , num_extra_bits ;
mz_uint match_len = pLZ_codes [ 0 ] , match_dist = ( pLZ_codes [ 1 ] | ( pLZ_codes [ 2 ] < < 8 ) ) ; pLZ_codes + = 3 ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 0 ] [ s_tdefl_len_sym [ match_len ] ] ) ;
TDEFL_PUT_BITS ( d - > m_huff_codes [ 0 ] [ s_tdefl_len_sym [ match_len ] ] , d - > m_huff_code_sizes [ 0 ] [ s_tdefl_len_sym [ match_len ] ] ) ;
TDEFL_PUT_BITS ( match_len & mz_bitmasks [ s_tdefl_len_extra [ match_len ] ] , s_tdefl_len_extra [ match_len ] ) ;
if ( match_dist < 512 )
{
sym = s_tdefl_small_dist_sym [ match_dist ] ; num_extra_bits = s_tdefl_small_dist_extra [ match_dist ] ;
}
else
{
sym = s_tdefl_large_dist_sym [ match_dist > > 8 ] ; num_extra_bits = s_tdefl_large_dist_extra [ match_dist > > 8 ] ;
}
MZ_ASSERT ( d - > m_huff_code_sizes [ 1 ] [ sym ] ) ;
TDEFL_PUT_BITS ( d - > m_huff_codes [ 1 ] [ sym ] , d - > m_huff_code_sizes [ 1 ] [ sym ] ) ;
TDEFL_PUT_BITS ( match_dist & mz_bitmasks [ num_extra_bits ] , num_extra_bits ) ;
}
else
{
mz_uint lit = * pLZ_codes + + ;
MZ_ASSERT ( d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
TDEFL_PUT_BITS ( d - > m_huff_codes [ 0 ] [ lit ] , d - > m_huff_code_sizes [ 0 ] [ lit ] ) ;
}
}
TDEFL_PUT_BITS ( d - > m_huff_codes [ 0 ] [ 256 ] , d - > m_huff_code_sizes [ 0 ] [ 256 ] ) ;
return ( d - > m_pOutput_buf < d - > m_pOutput_buf_end ) ;
}
# endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
static mz_bool tdefl_compress_block ( tdefl_compressor * d , mz_bool static_block )
{
if ( static_block )
tdefl_start_static_block ( d ) ;
else
tdefl_start_dynamic_block ( d ) ;
return tdefl_compress_lz_codes ( d ) ;
}
static int tdefl_flush_block ( tdefl_compressor * d , int flush )
{
mz_uint saved_bit_buf , saved_bits_in ;
mz_uint8 * pSaved_output_buf ;
mz_bool comp_block_succeeded = MZ_FALSE ;
int n , use_raw_block = ( ( d - > m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS ) ! = 0 ) & & ( d - > m_lookahead_pos - d - > m_lz_code_buf_dict_pos ) < = d - > m_dict_size ;
mz_uint8 * pOutput_buf_start = ( ( d - > m_pPut_buf_func = = NULL ) & & ( ( * d - > m_pOut_buf_size - d - > m_out_buf_ofs ) > = TDEFL_OUT_BUF_SIZE ) ) ? ( ( mz_uint8 * ) d - > m_pOut_buf + d - > m_out_buf_ofs ) : d - > m_output_buf ;
d - > m_pOutput_buf = pOutput_buf_start ;
d - > m_pOutput_buf_end = d - > m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16 ;
MZ_ASSERT ( ! d - > m_output_flush_remaining ) ;
d - > m_output_flush_ofs = 0 ;
d - > m_output_flush_remaining = 0 ;
* 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 ) ;
TDEFL_PUT_BITS ( flush = = TDEFL_FINISH , 1 ) ;
pSaved_output_buf = d - > m_pOutput_buf ; saved_bit_buf = d - > m_bit_buffer ; saved_bits_in = d - > m_bits_in ;
if ( ! use_raw_block )
comp_block_succeeded = tdefl_compress_block ( d , ( d - > m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS ) | | ( d - > m_total_lz_bytes < 48 ) ) ;
// If the block gets expanded, forget the current contents of the output buffer and send a raw block instead.
if ( ( ( use_raw_block ) | | ( ( d - > m_total_lz_bytes ) & & ( ( d - > m_pOutput_buf - pSaved_output_buf + 1U ) > = d - > m_total_lz_bytes ) ) ) & &
( ( d - > m_lookahead_pos - d - > m_lz_code_buf_dict_pos ) < = d - > m_dict_size ) )
{
mz_uint i ; d - > m_pOutput_buf = pSaved_output_buf ; d - > m_bit_buffer = saved_bit_buf , d - > m_bits_in = saved_bits_in ;
TDEFL_PUT_BITS ( 0 , 2 ) ;
if ( d - > m_bits_in ) { TDEFL_PUT_BITS ( 0 , 8 - d - > m_bits_in ) ; }
for ( i = 2 ; i ; - - i , d - > m_total_lz_bytes ^ = 0xFFFF )
{
TDEFL_PUT_BITS ( d - > m_total_lz_bytes & 0xFFFF , 16 ) ;
}
for ( i = 0 ; i < d - > m_total_lz_bytes ; + + i )
{
TDEFL_PUT_BITS ( d - > m_dict [ ( d - > m_lz_code_buf_dict_pos + i ) & TDEFL_LZ_DICT_SIZE_MASK ] , 8 ) ;
}
}
// Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes.
else if ( ! comp_block_succeeded )
{
d - > m_pOutput_buf = pSaved_output_buf ; d - > m_bit_buffer = saved_bit_buf , d - > m_bits_in = saved_bits_in ;
tdefl_compress_block ( d , MZ_TRUE ) ;
}
if ( flush )
{
if ( flush = = TDEFL_FINISH )
{
if ( d - > m_bits_in ) { TDEFL_PUT_BITS ( 0 , 8 - d - > m_bits_in ) ; }
}
else
{
mz_uint i , z = 0 ; TDEFL_PUT_BITS ( 0 , 3 ) ; if ( d - > m_bits_in ) { TDEFL_PUT_BITS ( 0 , 8 - d - > m_bits_in ) ; } for ( i = 2 ; i ; - - i , z ^ = 0xFFFF ) { TDEFL_PUT_BITS ( z & 0xFFFF , 16 ) ; }
}
}
MZ_ASSERT ( d - > m_pOutput_buf < d - > m_pOutput_buf_end ) ;
memset ( & d - > m_huff_count [ 0 ] [ 0 ] , 0 , sizeof ( d - > m_huff_count [ 0 ] [ 0 ] ) * TDEFL_MAX_HUFF_SYMBOLS_0 ) ;
memset ( & d - > m_huff_count [ 1 ] [ 0 ] , 0 , sizeof ( d - > m_huff_count [ 1 ] [ 0 ] ) * TDEFL_MAX_HUFF_SYMBOLS_1 ) ;
d - > m_pLZ_code_buf = d - > m_lz_code_buf + 1 ; d - > m_pLZ_flags = d - > m_lz_code_buf ; d - > m_num_flags_left = 8 ; d - > m_lz_code_buf_dict_pos + = d - > m_total_lz_bytes ; d - > m_total_lz_bytes = 0 ; d - > m_block_index + + ;
if ( ( n = ( int ) ( d - > m_pOutput_buf - pOutput_buf_start ) ) ! = 0 )
{
if ( d - > m_pPut_buf_func )
{
* d - > m_pIn_buf_size = d - > m_pSrc - ( const mz_uint8 * ) d - > m_pIn_buf ;
if ( ! ( * d - > m_pPut_buf_func ) ( d - > m_output_buf , n , d - > m_pPut_buf_user ) )
return ( d - > m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED ) ;
}
else if ( pOutput_buf_start = = d - > m_output_buf )
{
int bytes_to_copy = ( int ) MZ_MIN ( ( size_t ) n , ( size_t ) ( * d - > m_pOut_buf_size - d - > m_out_buf_ofs ) ) ;
memcpy ( ( mz_uint8 * ) d - > m_pOut_buf + d - > m_out_buf_ofs , d - > m_output_buf , bytes_to_copy ) ;
d - > m_out_buf_ofs + = bytes_to_copy ;
if ( ( n - = bytes_to_copy ) ! = 0 )
{
d - > m_output_flush_ofs = bytes_to_copy ;
d - > m_output_flush_remaining = n ;
}
}
else
{
d - > m_out_buf_ofs + = n ;
}
}
return d - > m_output_flush_remaining ;
}
# if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
# define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p)
static MZ_FORCEINLINE void tdefl_find_match ( tdefl_compressor * d , mz_uint lookahead_pos , mz_uint max_dist , mz_uint max_match_len , mz_uint * pMatch_dist , mz_uint * pMatch_len )
{
mz_uint dist , pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK , match_len = * pMatch_len , probe_pos = pos , next_probe_pos , probe_len ;
mz_uint num_probes_left = d - > m_max_probes [ match_len > = 32 ] ;
const mz_uint16 * s = ( const mz_uint16 * ) ( d - > m_dict + pos ) , * p , * q ;
mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD ( & d - > m_dict [ pos + match_len - 1 ] ) , s01 = TDEFL_READ_UNALIGNED_WORD ( s ) ;
MZ_ASSERT ( max_match_len < = TDEFL_MAX_MATCH_LEN ) ; if ( max_match_len < = match_len ) return ;
for ( ; ; )
{
for ( ; ; )
{
if ( - - num_probes_left = = 0 ) return ;
# define TDEFL_PROBE \
next_probe_pos = d - > m_next [ probe_pos ] ; \
if ( ( ! next_probe_pos ) | | ( ( dist = ( mz_uint16 ) ( lookahead_pos - next_probe_pos ) ) > max_dist ) ) return ; \
probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK ; \
if ( TDEFL_READ_UNALIGNED_WORD ( & d - > m_dict [ probe_pos + match_len - 1 ] ) = = c01 ) break ;
TDEFL_PROBE ; TDEFL_PROBE ; TDEFL_PROBE ;
}
2019-04-21 17:30:36 +02:00
if ( ! dist ) break ;
q = ( const mz_uint16 * ) ( d - > m_dict + probe_pos ) ;
if ( TDEFL_READ_UNALIGNED_WORD ( q ) ! = s01 ) continue ;
p = s ; probe_len = 32 ;
2016-02-02 06:36:39 +01:00
do { } while ( ( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & & ( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & &
( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & & ( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & & ( - - probe_len > 0 ) ) ;
if ( ! probe_len )
{
* pMatch_dist = dist ; * pMatch_len = MZ_MIN ( max_match_len , TDEFL_MAX_MATCH_LEN ) ; break ;
}
else if ( ( probe_len = ( ( mz_uint ) ( p - s ) * 2 ) + ( mz_uint ) ( * ( const mz_uint8 * ) p = = * ( const mz_uint8 * ) q ) ) > match_len )
{
* pMatch_dist = dist ; if ( ( * pMatch_len = match_len = MZ_MIN ( max_match_len , probe_len ) ) = = max_match_len ) break ;
c01 = TDEFL_READ_UNALIGNED_WORD ( & d - > m_dict [ pos + match_len - 1 ] ) ;
}
}
}
# else
static MZ_FORCEINLINE void tdefl_find_match ( tdefl_compressor * d , mz_uint lookahead_pos , mz_uint max_dist , mz_uint max_match_len , mz_uint * pMatch_dist , mz_uint * pMatch_len )
{
mz_uint dist , pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK , match_len = * pMatch_len , probe_pos = pos , next_probe_pos , probe_len ;
mz_uint num_probes_left = d - > m_max_probes [ match_len > = 32 ] ;
const mz_uint8 * s = d - > m_dict + pos , * p , * q ;
mz_uint8 c0 = d - > m_dict [ pos + match_len ] , c1 = d - > m_dict [ pos + match_len - 1 ] ;
MZ_ASSERT ( max_match_len < = TDEFL_MAX_MATCH_LEN ) ; if ( max_match_len < = match_len ) return ;
for ( ; ; )
{
for ( ; ; )
{
if ( - - num_probes_left = = 0 ) return ;
# define TDEFL_PROBE \
next_probe_pos = d - > m_next [ probe_pos ] ; \
if ( ( ! next_probe_pos ) | | ( ( dist = ( mz_uint16 ) ( lookahead_pos - next_probe_pos ) ) > max_dist ) ) return ; \
probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK ; \
if ( ( d - > m_dict [ probe_pos + match_len ] = = c0 ) & & ( d - > m_dict [ probe_pos + match_len - 1 ] = = c1 ) ) break ;
TDEFL_PROBE ; TDEFL_PROBE ; TDEFL_PROBE ;
}
if ( ! dist ) break ; p = s ; q = d - > m_dict + probe_pos ; for ( probe_len = 0 ; probe_len < max_match_len ; probe_len + + ) if ( * p + + ! = * q + + ) break ;
if ( probe_len > match_len )
{
* pMatch_dist = dist ; if ( ( * pMatch_len = match_len = probe_len ) = = max_match_len ) return ;
c0 = d - > m_dict [ pos + match_len ] ; c1 = d - > m_dict [ pos + match_len - 1 ] ;
}
}
}
# endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
# if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
static mz_bool tdefl_compress_fast ( tdefl_compressor * d )
{
// Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio.
mz_uint lookahead_pos = d - > m_lookahead_pos , lookahead_size = d - > m_lookahead_size , dict_size = d - > m_dict_size , total_lz_bytes = d - > m_total_lz_bytes , num_flags_left = d - > m_num_flags_left ;
mz_uint8 * pLZ_code_buf = d - > m_pLZ_code_buf , * pLZ_flags = d - > m_pLZ_flags ;
mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK ;
while ( ( d - > m_src_buf_left ) | | ( ( d - > m_flush ) & & ( lookahead_size ) ) )
{
const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096 ;
mz_uint dst_pos = ( lookahead_pos + lookahead_size ) & TDEFL_LZ_DICT_SIZE_MASK ;
mz_uint num_bytes_to_process = ( mz_uint ) MZ_MIN ( d - > m_src_buf_left , TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size ) ;
d - > m_src_buf_left - = num_bytes_to_process ;
lookahead_size + = num_bytes_to_process ;
while ( num_bytes_to_process )
{
mz_uint32 n = MZ_MIN ( TDEFL_LZ_DICT_SIZE - dst_pos , num_bytes_to_process ) ;
memcpy ( d - > m_dict + dst_pos , d - > m_pSrc , n ) ;
if ( dst_pos < ( TDEFL_MAX_MATCH_LEN - 1 ) )
memcpy ( d - > m_dict + TDEFL_LZ_DICT_SIZE + dst_pos , d - > m_pSrc , MZ_MIN ( n , ( TDEFL_MAX_MATCH_LEN - 1 ) - dst_pos ) ) ;
d - > m_pSrc + = n ;
dst_pos = ( dst_pos + n ) & TDEFL_LZ_DICT_SIZE_MASK ;
num_bytes_to_process - = n ;
}
dict_size = MZ_MIN ( TDEFL_LZ_DICT_SIZE - lookahead_size , dict_size ) ;
if ( ( ! d - > m_flush ) & & ( lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE ) ) break ;
while ( lookahead_size > = 4 )
{
mz_uint cur_match_dist , cur_match_len = 1 ;
mz_uint8 * pCur_dict = d - > m_dict + cur_pos ;
mz_uint first_trigram = ( * ( const mz_uint32 * ) pCur_dict ) & 0xFFFFFF ;
mz_uint hash = ( first_trigram ^ ( first_trigram > > ( 24 - ( TDEFL_LZ_HASH_BITS - 8 ) ) ) ) & TDEFL_LEVEL1_HASH_SIZE_MASK ;
mz_uint probe_pos = d - > m_hash [ hash ] ;
d - > m_hash [ hash ] = ( mz_uint16 ) lookahead_pos ;
if ( ( ( cur_match_dist = ( mz_uint16 ) ( lookahead_pos - probe_pos ) ) < = dict_size ) & & ( ( * ( const mz_uint32 * ) ( d - > m_dict + ( probe_pos & = TDEFL_LZ_DICT_SIZE_MASK ) ) & 0xFFFFFF ) = = first_trigram ) )
{
const mz_uint16 * p = ( const mz_uint16 * ) pCur_dict ;
const mz_uint16 * q = ( const mz_uint16 * ) ( d - > m_dict + probe_pos ) ;
mz_uint32 probe_len = 32 ;
do { } while ( ( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & & ( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & &
( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & & ( TDEFL_READ_UNALIGNED_WORD ( + + p ) = = TDEFL_READ_UNALIGNED_WORD ( + + q ) ) & & ( - - probe_len > 0 ) ) ;
cur_match_len = ( ( mz_uint ) ( p - ( const mz_uint16 * ) pCur_dict ) * 2 ) + ( mz_uint ) ( * ( const mz_uint8 * ) p = = * ( const mz_uint8 * ) q ) ;
if ( ! probe_len )
cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0 ;
if ( ( cur_match_len < TDEFL_MIN_MATCH_LEN ) | | ( ( cur_match_len = = TDEFL_MIN_MATCH_LEN ) & & ( cur_match_dist > = 8U * 1024U ) ) )
{
cur_match_len = 1 ;
* pLZ_code_buf + + = ( mz_uint8 ) first_trigram ;
* pLZ_flags = ( mz_uint8 ) ( * pLZ_flags > > 1 ) ;
d - > m_huff_count [ 0 ] [ ( mz_uint8 ) first_trigram ] + + ;
}
else
{
mz_uint32 s0 , s1 ;
cur_match_len = MZ_MIN ( cur_match_len , lookahead_size ) ;
MZ_ASSERT ( ( cur_match_len > = TDEFL_MIN_MATCH_LEN ) & & ( cur_match_dist > = 1 ) & & ( cur_match_dist < = TDEFL_LZ_DICT_SIZE ) ) ;
cur_match_dist - - ;
pLZ_code_buf [ 0 ] = ( mz_uint8 ) ( cur_match_len - TDEFL_MIN_MATCH_LEN ) ;
* ( mz_uint16 * ) ( & pLZ_code_buf [ 1 ] ) = ( mz_uint16 ) cur_match_dist ;
pLZ_code_buf + = 3 ;
* pLZ_flags = ( mz_uint8 ) ( ( * pLZ_flags > > 1 ) | 0x80 ) ;
s0 = s_tdefl_small_dist_sym [ cur_match_dist & 511 ] ;
s1 = s_tdefl_large_dist_sym [ cur_match_dist > > 8 ] ;
d - > m_huff_count [ 1 ] [ ( cur_match_dist < 512 ) ? s0 : s1 ] + + ;
d - > m_huff_count [ 0 ] [ s_tdefl_len_sym [ cur_match_len - TDEFL_MIN_MATCH_LEN ] ] + + ;
}
}
else
{
* pLZ_code_buf + + = ( mz_uint8 ) first_trigram ;
* pLZ_flags = ( mz_uint8 ) ( * pLZ_flags > > 1 ) ;
d - > m_huff_count [ 0 ] [ ( mz_uint8 ) first_trigram ] + + ;
}
if ( - - num_flags_left = = 0 ) { num_flags_left = 8 ; pLZ_flags = pLZ_code_buf + + ; }
total_lz_bytes + = cur_match_len ;
lookahead_pos + = cur_match_len ;
dict_size = MZ_MIN ( dict_size + cur_match_len , TDEFL_LZ_DICT_SIZE ) ;
cur_pos = ( cur_pos + cur_match_len ) & TDEFL_LZ_DICT_SIZE_MASK ;
MZ_ASSERT ( lookahead_size > = cur_match_len ) ;
lookahead_size - = cur_match_len ;
if ( pLZ_code_buf > & d - > m_lz_code_buf [ TDEFL_LZ_CODE_BUF_SIZE - 8 ] )
{
int n ;
d - > m_lookahead_pos = lookahead_pos ; d - > m_lookahead_size = lookahead_size ; d - > m_dict_size = dict_size ;
d - > m_total_lz_bytes = total_lz_bytes ; d - > m_pLZ_code_buf = pLZ_code_buf ; d - > m_pLZ_flags = pLZ_flags ; d - > m_num_flags_left = num_flags_left ;
if ( ( n = tdefl_flush_block ( d , 0 ) ) ! = 0 )
return ( n < 0 ) ? MZ_FALSE : MZ_TRUE ;
total_lz_bytes = d - > m_total_lz_bytes ; pLZ_code_buf = d - > m_pLZ_code_buf ; pLZ_flags = d - > m_pLZ_flags ; num_flags_left = d - > m_num_flags_left ;
}
}
while ( lookahead_size )
{
mz_uint8 lit = d - > m_dict [ cur_pos ] ;
total_lz_bytes + + ;
* pLZ_code_buf + + = lit ;
* pLZ_flags = ( mz_uint8 ) ( * pLZ_flags > > 1 ) ;
if ( - - num_flags_left = = 0 ) { num_flags_left = 8 ; pLZ_flags = pLZ_code_buf + + ; }
d - > m_huff_count [ 0 ] [ lit ] + + ;
lookahead_pos + + ;
dict_size = MZ_MIN ( dict_size + 1 , TDEFL_LZ_DICT_SIZE ) ;
cur_pos = ( cur_pos + 1 ) & TDEFL_LZ_DICT_SIZE_MASK ;
lookahead_size - - ;
if ( pLZ_code_buf > & d - > m_lz_code_buf [ TDEFL_LZ_CODE_BUF_SIZE - 8 ] )
{
int n ;
d - > m_lookahead_pos = lookahead_pos ; d - > m_lookahead_size = lookahead_size ; d - > m_dict_size = dict_size ;
d - > m_total_lz_bytes = total_lz_bytes ; d - > m_pLZ_code_buf = pLZ_code_buf ; d - > m_pLZ_flags = pLZ_flags ; d - > m_num_flags_left = num_flags_left ;
if ( ( n = tdefl_flush_block ( d , 0 ) ) ! = 0 )
return ( n < 0 ) ? MZ_FALSE : MZ_TRUE ;
total_lz_bytes = d - > m_total_lz_bytes ; pLZ_code_buf = d - > m_pLZ_code_buf ; pLZ_flags = d - > m_pLZ_flags ; num_flags_left = d - > m_num_flags_left ;
}
}
}
d - > m_lookahead_pos = lookahead_pos ; d - > m_lookahead_size = lookahead_size ; d - > m_dict_size = dict_size ;
d - > m_total_lz_bytes = total_lz_bytes ; d - > m_pLZ_code_buf = pLZ_code_buf ; d - > m_pLZ_flags = pLZ_flags ; d - > m_num_flags_left = num_flags_left ;
return MZ_TRUE ;
}
# endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
static MZ_FORCEINLINE void tdefl_record_literal ( tdefl_compressor * d , mz_uint8 lit )
{
d - > m_total_lz_bytes + + ;
* d - > m_pLZ_code_buf + + = lit ;
* d - > m_pLZ_flags = ( mz_uint8 ) ( * d - > m_pLZ_flags > > 1 ) ; if ( - - d - > m_num_flags_left = = 0 ) { d - > m_num_flags_left = 8 ; d - > m_pLZ_flags = d - > m_pLZ_code_buf + + ; }
d - > m_huff_count [ 0 ] [ lit ] + + ;
}
static MZ_FORCEINLINE void tdefl_record_match ( tdefl_compressor * d , mz_uint match_len , mz_uint match_dist )
{
mz_uint32 s0 , s1 ;
MZ_ASSERT ( ( match_len > = TDEFL_MIN_MATCH_LEN ) & & ( match_dist > = 1 ) & & ( match_dist < = TDEFL_LZ_DICT_SIZE ) ) ;
d - > m_total_lz_bytes + = match_len ;
d - > m_pLZ_code_buf [ 0 ] = ( mz_uint8 ) ( match_len - TDEFL_MIN_MATCH_LEN ) ;
match_dist - = 1 ;
d - > m_pLZ_code_buf [ 1 ] = ( mz_uint8 ) ( match_dist & 0xFF ) ;
d - > m_pLZ_code_buf [ 2 ] = ( mz_uint8 ) ( match_dist > > 8 ) ; d - > m_pLZ_code_buf + = 3 ;
* d - > m_pLZ_flags = ( mz_uint8 ) ( ( * d - > m_pLZ_flags > > 1 ) | 0x80 ) ; if ( - - d - > m_num_flags_left = = 0 ) { d - > m_num_flags_left = 8 ; d - > m_pLZ_flags = d - > m_pLZ_code_buf + + ; }
s0 = s_tdefl_small_dist_sym [ match_dist & 511 ] ; s1 = s_tdefl_large_dist_sym [ ( match_dist > > 8 ) & 127 ] ;
d - > m_huff_count [ 1 ] [ ( match_dist < 512 ) ? s0 : s1 ] + + ;
if ( match_len > = TDEFL_MIN_MATCH_LEN ) d - > m_huff_count [ 0 ] [ s_tdefl_len_sym [ match_len - TDEFL_MIN_MATCH_LEN ] ] + + ;
}
static mz_bool tdefl_compress_normal ( tdefl_compressor * d )
{
const mz_uint8 * pSrc = d - > m_pSrc ; size_t src_buf_left = d - > m_src_buf_left ;
tdefl_flush flush = d - > m_flush ;
while ( ( src_buf_left ) | | ( ( flush ) & & ( d - > m_lookahead_size ) ) )
{
mz_uint len_to_move , cur_match_dist , cur_match_len , cur_pos ;
// Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN.
if ( ( d - > m_lookahead_size + d - > m_dict_size ) > = ( TDEFL_MIN_MATCH_LEN - 1 ) )
{
mz_uint dst_pos = ( d - > m_lookahead_pos + d - > m_lookahead_size ) & TDEFL_LZ_DICT_SIZE_MASK , ins_pos = d - > m_lookahead_pos + d - > m_lookahead_size - 2 ;
mz_uint hash = ( d - > m_dict [ ins_pos & TDEFL_LZ_DICT_SIZE_MASK ] < < TDEFL_LZ_HASH_SHIFT ) ^ d - > m_dict [ ( ins_pos + 1 ) & TDEFL_LZ_DICT_SIZE_MASK ] ;
mz_uint num_bytes_to_process = ( mz_uint ) MZ_MIN ( src_buf_left , TDEFL_MAX_MATCH_LEN - d - > m_lookahead_size ) ;
const mz_uint8 * pSrc_end = pSrc + num_bytes_to_process ;
src_buf_left - = num_bytes_to_process ;
d - > m_lookahead_size + = num_bytes_to_process ;
while ( pSrc ! = pSrc_end )
{
mz_uint8 c = * pSrc + + ; d - > m_dict [ dst_pos ] = c ; if ( dst_pos < ( TDEFL_MAX_MATCH_LEN - 1 ) ) d - > m_dict [ TDEFL_LZ_DICT_SIZE + dst_pos ] = c ;
hash = ( ( hash < < TDEFL_LZ_HASH_SHIFT ) ^ c ) & ( TDEFL_LZ_HASH_SIZE - 1 ) ;
d - > m_next [ ins_pos & TDEFL_LZ_DICT_SIZE_MASK ] = d - > m_hash [ hash ] ; d - > m_hash [ hash ] = ( mz_uint16 ) ( ins_pos ) ;
dst_pos = ( dst_pos + 1 ) & TDEFL_LZ_DICT_SIZE_MASK ; ins_pos + + ;
}
}
else
{
while ( ( src_buf_left ) & & ( d - > m_lookahead_size < TDEFL_MAX_MATCH_LEN ) )
{
mz_uint8 c = * pSrc + + ;
mz_uint dst_pos = ( d - > m_lookahead_pos + d - > m_lookahead_size ) & TDEFL_LZ_DICT_SIZE_MASK ;
src_buf_left - - ;
d - > m_dict [ dst_pos ] = c ;
if ( dst_pos < ( TDEFL_MAX_MATCH_LEN - 1 ) )
d - > m_dict [ TDEFL_LZ_DICT_SIZE + dst_pos ] = c ;
if ( ( + + d - > m_lookahead_size + d - > m_dict_size ) > = TDEFL_MIN_MATCH_LEN )
{
mz_uint ins_pos = d - > m_lookahead_pos + ( d - > m_lookahead_size - 1 ) - 2 ;
mz_uint hash = ( ( d - > m_dict [ ins_pos & TDEFL_LZ_DICT_SIZE_MASK ] < < ( TDEFL_LZ_HASH_SHIFT * 2 ) ) ^ ( d - > m_dict [ ( ins_pos + 1 ) & TDEFL_LZ_DICT_SIZE_MASK ] < < TDEFL_LZ_HASH_SHIFT ) ^ c ) & ( TDEFL_LZ_HASH_SIZE - 1 ) ;
d - > m_next [ ins_pos & TDEFL_LZ_DICT_SIZE_MASK ] = d - > m_hash [ hash ] ; d - > m_hash [ hash ] = ( mz_uint16 ) ( ins_pos ) ;
}
}
}
d - > m_dict_size = MZ_MIN ( TDEFL_LZ_DICT_SIZE - d - > m_lookahead_size , d - > m_dict_size ) ;
if ( ( ! flush ) & & ( d - > m_lookahead_size < TDEFL_MAX_MATCH_LEN ) )
break ;
// Simple lazy/greedy parsing state machine.
len_to_move = 1 ; cur_match_dist = 0 ; cur_match_len = d - > m_saved_match_len ? d - > m_saved_match_len : ( TDEFL_MIN_MATCH_LEN - 1 ) ; cur_pos = d - > m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK ;
if ( d - > m_flags & ( TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS ) )
{
if ( ( d - > m_dict_size ) & & ( ! ( d - > m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS ) ) )
{
mz_uint8 c = d - > m_dict [ ( cur_pos - 1 ) & TDEFL_LZ_DICT_SIZE_MASK ] ;
cur_match_len = 0 ; while ( cur_match_len < d - > m_lookahead_size ) { if ( d - > m_dict [ cur_pos + cur_match_len ] ! = c ) break ; cur_match_len + + ; }
if ( cur_match_len < TDEFL_MIN_MATCH_LEN ) cur_match_len = 0 ; else cur_match_dist = 1 ;
}
}
else
{
tdefl_find_match ( d , d - > m_lookahead_pos , d - > m_dict_size , d - > m_lookahead_size , & cur_match_dist , & cur_match_len ) ;
}
if ( ( ( cur_match_len = = TDEFL_MIN_MATCH_LEN ) & & ( cur_match_dist > = 8U * 1024U ) ) | | ( cur_pos = = cur_match_dist ) | | ( ( d - > m_flags & TDEFL_FILTER_MATCHES ) & & ( cur_match_len < = 5 ) ) )
{
cur_match_dist = cur_match_len = 0 ;
}
if ( d - > m_saved_match_len )
{
if ( cur_match_len > d - > m_saved_match_len )
{
tdefl_record_literal ( d , ( mz_uint8 ) d - > m_saved_lit ) ;
if ( cur_match_len > = 128 )
{
tdefl_record_match ( d , cur_match_len , cur_match_dist ) ;
d - > m_saved_match_len = 0 ; len_to_move = cur_match_len ;
}
else
{
d - > m_saved_lit = d - > m_dict [ cur_pos ] ; d - > m_saved_match_dist = cur_match_dist ; d - > m_saved_match_len = cur_match_len ;
}
}
else
{
tdefl_record_match ( d , d - > m_saved_match_len , d - > m_saved_match_dist ) ;
len_to_move = d - > m_saved_match_len - 1 ; d - > m_saved_match_len = 0 ;
}
}
else if ( ! cur_match_dist )
tdefl_record_literal ( d , d - > m_dict [ MZ_MIN ( cur_pos , sizeof ( d - > m_dict ) - 1 ) ] ) ;
else if ( ( d - > m_greedy_parsing ) | | ( d - > m_flags & TDEFL_RLE_MATCHES ) | | ( cur_match_len > = 128 ) )
{
tdefl_record_match ( d , cur_match_len , cur_match_dist ) ;
len_to_move = cur_match_len ;
}
else
{
d - > m_saved_lit = d - > m_dict [ MZ_MIN ( cur_pos , sizeof ( d - > m_dict ) - 1 ) ] ; d - > m_saved_match_dist = cur_match_dist ; d - > m_saved_match_len = cur_match_len ;
}
// Move the lookahead forward by len_to_move bytes.
d - > m_lookahead_pos + = len_to_move ;
MZ_ASSERT ( d - > m_lookahead_size > = len_to_move ) ;
d - > m_lookahead_size - = len_to_move ;
d - > m_dict_size = MZ_MIN ( d - > m_dict_size + len_to_move , TDEFL_LZ_DICT_SIZE ) ;
// Check if it's time to flush the current LZ codes to the internal output buffer.
if ( ( d - > m_pLZ_code_buf > & d - > m_lz_code_buf [ TDEFL_LZ_CODE_BUF_SIZE - 8 ] ) | |
( ( d - > m_total_lz_bytes > 31 * 1024 ) & & ( ( ( ( ( mz_uint ) ( d - > m_pLZ_code_buf - d - > m_lz_code_buf ) * 115 ) > > 7 ) > = d - > m_total_lz_bytes ) | | ( d - > m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS ) ) ) )
{
int n ;
d - > m_pSrc = pSrc ; d - > m_src_buf_left = src_buf_left ;
if ( ( n = tdefl_flush_block ( d , 0 ) ) ! = 0 )
return ( n < 0 ) ? MZ_FALSE : MZ_TRUE ;
}
}
d - > m_pSrc = pSrc ; d - > m_src_buf_left = src_buf_left ;
return MZ_TRUE ;
}
static tdefl_status tdefl_flush_output_buffer ( tdefl_compressor * d )
{
if ( d - > m_pIn_buf_size )
{
* d - > m_pIn_buf_size = d - > m_pSrc - ( const mz_uint8 * ) d - > m_pIn_buf ;
}
if ( d - > m_pOut_buf_size )
{
size_t n = MZ_MIN ( * d - > m_pOut_buf_size - d - > m_out_buf_ofs , d - > m_output_flush_remaining ) ;
memcpy ( ( mz_uint8 * ) d - > m_pOut_buf + d - > m_out_buf_ofs , d - > m_output_buf + d - > m_output_flush_ofs , n ) ;
d - > m_output_flush_ofs + = ( mz_uint ) n ;
d - > m_output_flush_remaining - = ( mz_uint ) n ;
d - > m_out_buf_ofs + = n ;
* d - > m_pOut_buf_size = d - > m_out_buf_ofs ;
}
return ( d - > m_finished & & ! d - > m_output_flush_remaining ) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY ;
}
tdefl_status tdefl_compress ( tdefl_compressor * d , const void * pIn_buf , size_t * pIn_buf_size , void * pOut_buf , size_t * pOut_buf_size , tdefl_flush flush )
{
if ( ! d )
{
if ( pIn_buf_size ) * pIn_buf_size = 0 ;
if ( pOut_buf_size ) * pOut_buf_size = 0 ;
return TDEFL_STATUS_BAD_PARAM ;
}
d - > m_pIn_buf = pIn_buf ; d - > m_pIn_buf_size = pIn_buf_size ;
d - > m_pOut_buf = pOut_buf ; d - > m_pOut_buf_size = pOut_buf_size ;
d - > m_pSrc = ( const mz_uint8 * ) ( pIn_buf ) ; d - > m_src_buf_left = pIn_buf_size ? * pIn_buf_size : 0 ;
d - > m_out_buf_ofs = 0 ;
d - > m_flush = flush ;
if ( ( ( d - > m_pPut_buf_func ! = NULL ) = = ( ( pOut_buf ! = NULL ) | | ( pOut_buf_size ! = NULL ) ) ) | | ( d - > m_prev_return_status ! = TDEFL_STATUS_OKAY ) | |
( d - > m_wants_to_finish & & ( flush ! = TDEFL_FINISH ) ) | | ( pIn_buf_size & & * pIn_buf_size & & ! pIn_buf ) | | ( pOut_buf_size & & * pOut_buf_size & & ! pOut_buf ) )
{
if ( pIn_buf_size ) * pIn_buf_size = 0 ;
if ( pOut_buf_size ) * pOut_buf_size = 0 ;
return ( d - > m_prev_return_status = TDEFL_STATUS_BAD_PARAM ) ;
}
d - > m_wants_to_finish | = ( flush = = TDEFL_FINISH ) ;
if ( ( d - > m_output_flush_remaining ) | | ( d - > m_finished ) )
return ( d - > m_prev_return_status = tdefl_flush_output_buffer ( d ) ) ;
# if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
if ( ( ( d - > m_flags & TDEFL_MAX_PROBES_MASK ) = = 1 ) & &
( ( d - > m_flags & TDEFL_GREEDY_PARSING_FLAG ) ! = 0 ) & &
( ( d - > m_flags & ( TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES ) ) = = 0 ) )
{
if ( ! tdefl_compress_fast ( d ) )
return d - > m_prev_return_status ;
}
else
# endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
{
if ( ! tdefl_compress_normal ( d ) )
return d - > m_prev_return_status ;
}
if ( ( flush ) & & ( ! d - > m_lookahead_size ) & & ( ! d - > m_src_buf_left ) & & ( ! d - > m_output_flush_remaining ) )
{
if ( tdefl_flush_block ( d , flush ) < 0 )
return d - > m_prev_return_status ;
d - > m_finished = ( flush = = TDEFL_FINISH ) ;
if ( flush = = TDEFL_FULL_FLUSH ) { MZ_CLEAR_OBJ ( d - > m_hash ) ; MZ_CLEAR_OBJ ( d - > m_next ) ; d - > m_dict_size = 0 ; }
}
return ( d - > m_prev_return_status = tdefl_flush_output_buffer ( d ) ) ;
}
tdefl_status tdefl_init ( tdefl_compressor * d , tdefl_put_buf_func_ptr pPut_buf_func , void * pPut_buf_user , int flags )
{
d - > m_pPut_buf_func = pPut_buf_func ; d - > m_pPut_buf_user = pPut_buf_user ;
d - > m_flags = ( mz_uint ) ( flags ) ; d - > m_max_probes [ 0 ] = 1 + ( ( flags & 0xFFF ) + 2 ) / 3 ; d - > m_greedy_parsing = ( flags & TDEFL_GREEDY_PARSING_FLAG ) ! = 0 ;
d - > m_max_probes [ 1 ] = 1 + ( ( ( flags & 0xFFF ) > > 2 ) + 2 ) / 3 ;
if ( ! ( flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG ) ) MZ_CLEAR_OBJ ( d - > m_hash ) ;
d - > m_lookahead_pos = d - > m_lookahead_size = d - > m_dict_size = d - > m_total_lz_bytes = d - > m_lz_code_buf_dict_pos = d - > m_bits_in = 0 ;
d - > m_output_flush_ofs = d - > m_output_flush_remaining = d - > m_finished = d - > m_block_index = d - > m_bit_buffer = d - > m_wants_to_finish = 0 ;
d - > m_pLZ_code_buf = d - > m_lz_code_buf + 1 ; d - > m_pLZ_flags = d - > m_lz_code_buf ; d - > m_num_flags_left = 8 ;
d - > m_pOutput_buf = d - > m_output_buf ; 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_pIn_buf = NULL ; d - > m_pOut_buf = NULL ;
d - > m_pIn_buf_size = NULL ; d - > m_pOut_buf_size = NULL ;
d - > m_flush = TDEFL_NO_FLUSH ; d - > m_pSrc = NULL ; d - > m_src_buf_left = 0 ; d - > m_out_buf_ofs = 0 ;
memset ( & d - > m_huff_count [ 0 ] [ 0 ] , 0 , sizeof ( d - > m_huff_count [ 0 ] [ 0 ] ) * TDEFL_MAX_HUFF_SYMBOLS_0 ) ;
memset ( & d - > m_huff_count [ 1 ] [ 0 ] , 0 , sizeof ( d - > m_huff_count [ 1 ] [ 0 ] ) * TDEFL_MAX_HUFF_SYMBOLS_1 ) ;
return TDEFL_STATUS_OKAY ;
}
typedef struct
{
size_t m_size , m_capacity ;
mz_uint8 * m_pBuf ;
mz_bool m_expandable ;
} tdefl_output_buffer ;
# ifndef MINIZ_NO_ZLIB_APIS
static const mz_uint s_tdefl_num_probes [ 11 ] = { 0 , 1 , 6 , 32 , 16 , 32 , 128 , 256 , 512 , 768 , 1500 } ;
// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files).
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 ) ;
( void ) window_bits ;
if ( ! level ) comp_flags | = TDEFL_FORCE_ALL_RAW_BLOCKS ;
else if ( strategy = = MZ_FILTERED ) comp_flags | = TDEFL_FILTER_MATCHES ;
else if ( strategy = = MZ_HUFFMAN_ONLY ) comp_flags & = ~ TDEFL_MAX_PROBES_MASK ;
else if ( strategy = = MZ_FIXED ) comp_flags | = TDEFL_FORCE_ALL_STATIC_BLOCKS ;
else if ( strategy = = MZ_RLE ) comp_flags | = TDEFL_RLE_MATCHES ;
return comp_flags ;
}
# endif //MINIZ_NO_ZLIB_APIS
# endif // MINIZ_HEADER_FILE_ONLY
/*
This is free and unencumbered software released into the public domain .
Anyone is free to copy , modify , publish , use , compile , sell , or
distribute this software , either in source code form or as a compiled
binary , for any purpose , commercial or non - commercial , and by any
means .
In jurisdictions that recognize copyright laws , the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain . We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors . We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law .
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 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 .
For more information , please refer to < http : //unlicense.org/>
*/