mirror of https://github.com/PCSX2/pcsx2.git
3rdparty/zlib: Update to 1.3
This commit is contained in:
parent
fe0d31ae94
commit
828c0bcb99
|
@ -1,6 +1,99 @@
|
||||||
|
|
||||||
ChangeLog file for zlib
|
ChangeLog file for zlib
|
||||||
|
|
||||||
|
Changes in 1.3 (18 Aug 2023)
|
||||||
|
- Remove K&R function definitions and zlib2ansi
|
||||||
|
- Fix bug in deflateBound() for level 0 and memLevel 9
|
||||||
|
- Fix bug when gzungetc() is used immediately after gzopen()
|
||||||
|
- Fix bug when using gzflush() with a very small buffer
|
||||||
|
- Fix crash when gzsetparams() attempted for transparent write
|
||||||
|
- Fix test/example.c to work with FORCE_STORED
|
||||||
|
- Rewrite of zran in examples (see zran.c version history)
|
||||||
|
- Fix minizip to allow it to open an empty zip file
|
||||||
|
- Fix reading disk number start on zip64 files in minizip
|
||||||
|
- Fix logic error in minizip argument processing
|
||||||
|
- Add minizip testing to Makefile
|
||||||
|
- Read multiple bytes instead of byte-by-byte in minizip unzip.c
|
||||||
|
- Add memory sanitizer to configure (--memory)
|
||||||
|
- Various portability improvements
|
||||||
|
- Various documentation improvements
|
||||||
|
- Various spelling and typo corrections
|
||||||
|
|
||||||
|
Changes in 1.2.13 (13 Oct 2022)
|
||||||
|
- Fix configure issue that discarded provided CC definition
|
||||||
|
- Correct incorrect inputs provided to the CRC functions
|
||||||
|
- Repair prototypes and exporting of new CRC functions
|
||||||
|
- Fix inflateBack to detect invalid input with distances too far
|
||||||
|
- Have infback() deliver all of the available output up to any error
|
||||||
|
- Fix a bug when getting a gzip header extra field with inflate()
|
||||||
|
- Fix bug in block type selection when Z_FIXED used
|
||||||
|
- Tighten deflateBound bounds
|
||||||
|
- Remove deleted assembler code references
|
||||||
|
- Various portability and appearance improvements
|
||||||
|
|
||||||
|
Changes in 1.2.12 (27 Mar 2022)
|
||||||
|
- Cygwin does not have _wopen(), so do not create gzopen_w() there
|
||||||
|
- Permit a deflateParams() parameter change as soon as possible
|
||||||
|
- Limit hash table inserts after switch from stored deflate
|
||||||
|
- Fix bug when window full in deflate_stored()
|
||||||
|
- Fix CLEAR_HASH macro to be usable as a single statement
|
||||||
|
- Avoid a conversion error in gzseek when off_t type too small
|
||||||
|
- Have Makefile return non-zero error code on test failure
|
||||||
|
- Avoid some conversion warnings in gzread.c and gzwrite.c
|
||||||
|
- Update use of errno for newer Windows CE versions
|
||||||
|
- Small speedup to inflate [psumbera]
|
||||||
|
- Return an error if the gzputs string length can't fit in an int
|
||||||
|
- Add address checking in clang to -w option of configure
|
||||||
|
- Don't compute check value for raw inflate if asked to validate
|
||||||
|
- Handle case where inflateSync used when header never processed
|
||||||
|
- Avoid the use of ptrdiff_t
|
||||||
|
- Avoid an undefined behavior of memcpy() in gzappend()
|
||||||
|
- Avoid undefined behaviors of memcpy() in gz*printf()
|
||||||
|
- Avoid an undefined behavior of memcpy() in _tr_stored_block()
|
||||||
|
- Make the names in functions declarations identical to definitions
|
||||||
|
- Remove old assembler code in which bugs have manifested
|
||||||
|
- Fix deflateEnd() to not report an error at start of raw deflate
|
||||||
|
- Add legal disclaimer to README
|
||||||
|
- Emphasize the need to continue decompressing gzip members
|
||||||
|
- Correct the initialization requirements for deflateInit2()
|
||||||
|
- Fix a bug that can crash deflate on some input when using Z_FIXED
|
||||||
|
- Assure that the number of bits for deflatePrime() is valid
|
||||||
|
- Use a structure to make globals in enough.c evident
|
||||||
|
- Use a macro for the printf format of big_t in enough.c
|
||||||
|
- Clean up code style in enough.c, update version
|
||||||
|
- Use inline function instead of macro for index in enough.c
|
||||||
|
- Clarify that prefix codes are counted in enough.c
|
||||||
|
- Show all the codes for the maximum tables size in enough.c
|
||||||
|
- Add gznorm.c example, which normalizes gzip files
|
||||||
|
- Fix the zran.c example to work on a multiple-member gzip file
|
||||||
|
- Add tables for crc32_combine(), to speed it up by a factor of 200
|
||||||
|
- Add crc32_combine_gen() and crc32_combine_op() for fast combines
|
||||||
|
- Speed up software CRC-32 computation by a factor of 1.5 to 3
|
||||||
|
- Use atomic test and set, if available, for dynamic CRC tables
|
||||||
|
- Don't bother computing check value after successful inflateSync()
|
||||||
|
- Correct comment in crc32.c
|
||||||
|
- Add use of the ARMv8 crc32 instructions when requested
|
||||||
|
- Use ARM crc32 instructions if the ARM architecture has them
|
||||||
|
- Explicitly note that the 32-bit check values are 32 bits
|
||||||
|
- Avoid adding empty gzip member after gzflush with Z_FINISH
|
||||||
|
- Fix memory leak on error in gzlog.c
|
||||||
|
- Fix error in comment on the polynomial representation of a byte
|
||||||
|
- Clarify gz* function interfaces, referring to parameter names
|
||||||
|
- Change macro name in inflate.c to avoid collision in VxWorks
|
||||||
|
- Correct typo in blast.c
|
||||||
|
- Improve portability of contrib/minizip
|
||||||
|
- Fix indentation in minizip's zip.c
|
||||||
|
- Replace black/white with allow/block. (theresa-m)
|
||||||
|
- minizip warning fix if MAXU32 already defined. (gvollant)
|
||||||
|
- Fix unztell64() in minizip to work past 4GB. (Daniël Hörchner)
|
||||||
|
- Clean up minizip to reduce warnings for testing
|
||||||
|
- Add fallthrough comments for gcc
|
||||||
|
- Eliminate use of ULL constants
|
||||||
|
- Separate out address sanitizing from warnings in configure
|
||||||
|
- Remove destructive aspects of make distclean
|
||||||
|
- Check for cc masquerading as gcc or clang in configure
|
||||||
|
- Fix crc32.c to compile local functions only if used
|
||||||
|
|
||||||
Changes in 1.2.11 (15 Jan 2017)
|
Changes in 1.2.11 (15 Jan 2017)
|
||||||
- Fix deflate stored bug when pulling last block from window
|
- Fix deflate stored bug when pulling last block from window
|
||||||
- Permit immediate deflateParams changes before any deflate input
|
- Permit immediate deflateParams changes before any deflate input
|
||||||
|
@ -96,7 +189,7 @@ Changes in 1.2.7.1 (24 Mar 2013)
|
||||||
- Fix types in contrib/minizip to match result of get_crc_table()
|
- Fix types in contrib/minizip to match result of get_crc_table()
|
||||||
- Simplify contrib/vstudio/vc10 with 'd' suffix
|
- Simplify contrib/vstudio/vc10 with 'd' suffix
|
||||||
- Add TOP support to win32/Makefile.msc
|
- Add TOP support to win32/Makefile.msc
|
||||||
- Suport i686 and amd64 assembler builds in CMakeLists.txt
|
- Support i686 and amd64 assembler builds in CMakeLists.txt
|
||||||
- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h
|
- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h
|
||||||
- Add vc11 and vc12 build files to contrib/vstudio
|
- Add vc11 and vc12 build files to contrib/vstudio
|
||||||
- Add gzvprintf() as an undocumented function in zlib
|
- Add gzvprintf() as an undocumented function in zlib
|
||||||
|
@ -296,14 +389,14 @@ Changes in 1.2.5.1 (10 Sep 2011)
|
||||||
- Use u4 type for crc_table to avoid conversion warnings
|
- Use u4 type for crc_table to avoid conversion warnings
|
||||||
- Apply casts in zlib.h to avoid conversion warnings
|
- Apply casts in zlib.h to avoid conversion warnings
|
||||||
- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]
|
- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]
|
||||||
- Improve inflateSync() documentation to note indeterminancy
|
- Improve inflateSync() documentation to note indeterminacy
|
||||||
- Add deflatePending() function to return the amount of pending output
|
- Add deflatePending() function to return the amount of pending output
|
||||||
- Correct the spelling of "specification" in FAQ [Randers-Pehrson]
|
- Correct the spelling of "specification" in FAQ [Randers-Pehrson]
|
||||||
- Add a check in configure for stdarg.h, use for gzprintf()
|
- Add a check in configure for stdarg.h, use for gzprintf()
|
||||||
- Check that pointers fit in ints when gzprint() compiled old style
|
- Check that pointers fit in ints when gzprint() compiled old style
|
||||||
- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]
|
- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]
|
||||||
- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]
|
- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]
|
||||||
- Add debug records in assmebler code [Londer]
|
- Add debug records in assembler code [Londer]
|
||||||
- Update RFC references to use http://tools.ietf.org/html/... [Li]
|
- Update RFC references to use http://tools.ietf.org/html/... [Li]
|
||||||
- Add --archs option, use of libtool to configure for Mac OS X [Borstel]
|
- Add --archs option, use of libtool to configure for Mac OS X [Borstel]
|
||||||
|
|
||||||
|
@ -511,7 +604,7 @@ Changes in 1.2.3.5 (8 Jan 2010)
|
||||||
- Don't use _vsnprintf on later versions of MSVC [Lowman]
|
- Don't use _vsnprintf on later versions of MSVC [Lowman]
|
||||||
- Add CMake build script and input file [Lowman]
|
- Add CMake build script and input file [Lowman]
|
||||||
- Update contrib/minizip to 1.1 [Svensson, Vollant]
|
- Update contrib/minizip to 1.1 [Svensson, Vollant]
|
||||||
- Moved nintendods directory from contrib to .
|
- Moved nintendods directory from contrib to root
|
||||||
- Replace gzio.c with a new set of routines with the same functionality
|
- Replace gzio.c with a new set of routines with the same functionality
|
||||||
- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above
|
- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above
|
||||||
- Update contrib/minizip to 1.1b
|
- Update contrib/minizip to 1.1b
|
||||||
|
@ -685,7 +778,7 @@ Changes in 1.2.2.4 (11 July 2005)
|
||||||
- Be more strict on incomplete code sets in inflate_table() and increase
|
- Be more strict on incomplete code sets in inflate_table() and increase
|
||||||
ENOUGH and MAXD -- this repairs a possible security vulnerability for
|
ENOUGH and MAXD -- this repairs a possible security vulnerability for
|
||||||
invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for
|
invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for
|
||||||
discovering the vulnerability and providing test cases.
|
discovering the vulnerability and providing test cases
|
||||||
- Add ia64 support to configure for HP-UX [Smith]
|
- Add ia64 support to configure for HP-UX [Smith]
|
||||||
- Add error return to gzread() for format or i/o error [Levin]
|
- Add error return to gzread() for format or i/o error [Levin]
|
||||||
- Use malloc.h for OS/2 [Necasek]
|
- Use malloc.h for OS/2 [Necasek]
|
||||||
|
@ -721,7 +814,7 @@ Changes in 1.2.2.2 (30 December 2004)
|
||||||
- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
|
- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
|
||||||
- Add updated make_vms.com [Coghlan], update README
|
- Add updated make_vms.com [Coghlan], update README
|
||||||
- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
|
- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
|
||||||
fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
|
fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html
|
||||||
- Add FAQ entry and comments in deflate.c on uninitialized memory access
|
- Add FAQ entry and comments in deflate.c on uninitialized memory access
|
||||||
- Add Solaris 9 make options in configure [Gilbert]
|
- Add Solaris 9 make options in configure [Gilbert]
|
||||||
- Allow strerror() usage in gzio.c for STDC
|
- Allow strerror() usage in gzio.c for STDC
|
||||||
|
@ -792,7 +885,7 @@ Changes in 1.2.1.1 (9 January 2004)
|
||||||
- Fix a big fat bug in inftrees.c that prevented decoding valid
|
- Fix a big fat bug in inftrees.c that prevented decoding valid
|
||||||
dynamic blocks with only literals and no distance codes --
|
dynamic blocks with only literals and no distance codes --
|
||||||
Thanks to "Hot Emu" for the bug report and sample file
|
Thanks to "Hot Emu" for the bug report and sample file
|
||||||
- Add a note to puff.c on no distance codes case.
|
- Add a note to puff.c on no distance codes case
|
||||||
|
|
||||||
Changes in 1.2.1 (17 November 2003)
|
Changes in 1.2.1 (17 November 2003)
|
||||||
- Remove a tab in contrib/gzappend/gzappend.c
|
- Remove a tab in contrib/gzappend/gzappend.c
|
||||||
|
@ -970,7 +1063,7 @@ Changes in 1.2.0.1 (17 March 2003)
|
||||||
- Include additional header file on VMS for off_t typedef
|
- Include additional header file on VMS for off_t typedef
|
||||||
- Try to use _vsnprintf where it supplants vsprintf [Vollant]
|
- Try to use _vsnprintf where it supplants vsprintf [Vollant]
|
||||||
- Add some casts in inffast.c
|
- Add some casts in inffast.c
|
||||||
- Enchance comments in zlib.h on what happens if gzprintf() tries to
|
- Enhance comments in zlib.h on what happens if gzprintf() tries to
|
||||||
write more than 4095 bytes before compression
|
write more than 4095 bytes before compression
|
||||||
- Remove unused state from inflateBackEnd()
|
- Remove unused state from inflateBackEnd()
|
||||||
- Remove exit(0) from minigzip.c, example.c
|
- Remove exit(0) from minigzip.c, example.c
|
||||||
|
@ -1036,14 +1129,14 @@ Changes in 1.2.0 (9 March 2003)
|
||||||
- Add contrib/puff/ simple inflate for deflate format description
|
- Add contrib/puff/ simple inflate for deflate format description
|
||||||
|
|
||||||
Changes in 1.1.4 (11 March 2002)
|
Changes in 1.1.4 (11 March 2002)
|
||||||
- ZFREE was repeated on same allocation on some error conditions.
|
- ZFREE was repeated on same allocation on some error conditions
|
||||||
This creates a security problem described in
|
This creates a security problem described in
|
||||||
http://www.zlib.org/advisory-2002-03-11.txt
|
http://www.zlib.org/advisory-2002-03-11.txt
|
||||||
- Returned incorrect error (Z_MEM_ERROR) on some invalid data
|
- Returned incorrect error (Z_MEM_ERROR) on some invalid data
|
||||||
- Avoid accesses before window for invalid distances with inflate window
|
- Avoid accesses before window for invalid distances with inflate window
|
||||||
less than 32K.
|
less than 32K
|
||||||
- force windowBits > 8 to avoid a bug in the encoder for a window size
|
- force windowBits > 8 to avoid a bug in the encoder for a window size
|
||||||
of 256 bytes. (A complete fix will be available in 1.1.5).
|
of 256 bytes. (A complete fix will be available in 1.1.5)
|
||||||
|
|
||||||
Changes in 1.1.3 (9 July 1998)
|
Changes in 1.1.3 (9 July 1998)
|
||||||
- fix "an inflate input buffer bug that shows up on rare but persistent
|
- fix "an inflate input buffer bug that shows up on rare but persistent
|
||||||
|
@ -1117,7 +1210,7 @@ Changes in 1.1.1 (27 Feb 98)
|
||||||
- remove block truncation heuristic which had very marginal effect for zlib
|
- remove block truncation heuristic which had very marginal effect for zlib
|
||||||
(smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
|
(smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
|
||||||
compression ratio on some files. This also allows inlining _tr_tally for
|
compression ratio on some files. This also allows inlining _tr_tally for
|
||||||
matches in deflate_slow.
|
matches in deflate_slow
|
||||||
- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
|
- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
|
||||||
|
|
||||||
Changes in 1.1.0 (24 Feb 98)
|
Changes in 1.1.0 (24 Feb 98)
|
||||||
|
@ -1148,7 +1241,7 @@ Changes in 1.0.9 (17 Feb 1998)
|
||||||
- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
|
- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
|
||||||
- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
|
- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
|
||||||
- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
|
- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
|
||||||
the declaration of FAR (Gilles VOllant)
|
the declaration of FAR (Gilles Vollant)
|
||||||
- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
|
- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
|
||||||
- read_buf buf parameter of type Bytef* instead of charf*
|
- read_buf buf parameter of type Bytef* instead of charf*
|
||||||
- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
|
- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
|
||||||
|
@ -1162,7 +1255,7 @@ Changes in 1.0.8 (27 Jan 1998)
|
||||||
- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
|
- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
|
||||||
- use constant arrays for the static trees in trees.c instead of computing
|
- use constant arrays for the static trees in trees.c instead of computing
|
||||||
them at run time (thanks to Ken Raeburn for this suggestion). To create
|
them at run time (thanks to Ken Raeburn for this suggestion). To create
|
||||||
trees.h, compile with GEN_TREES_H and run "make test".
|
trees.h, compile with GEN_TREES_H and run "make test"
|
||||||
- check return code of example in "make test" and display result
|
- check return code of example in "make test" and display result
|
||||||
- pass minigzip command line options to file_compress
|
- pass minigzip command line options to file_compress
|
||||||
- simplifying code of inflateSync to avoid gcc 2.8 bug
|
- simplifying code of inflateSync to avoid gcc 2.8 bug
|
||||||
|
@ -1201,12 +1294,12 @@ Changes in 1.0.6 (19 Jan 1998)
|
||||||
- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
|
- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
|
||||||
gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
|
gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
|
||||||
- Fix a deflate bug occurring only with compression level 0 (thanks to
|
- Fix a deflate bug occurring only with compression level 0 (thanks to
|
||||||
Andy Buckler for finding this one).
|
Andy Buckler for finding this one)
|
||||||
- In minigzip, pass transparently also the first byte for .Z files.
|
- In minigzip, pass transparently also the first byte for .Z files
|
||||||
- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
|
- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
|
||||||
- check Z_FINISH in inflate (thanks to Marc Schluper)
|
- check Z_FINISH in inflate (thanks to Marc Schluper)
|
||||||
- Implement deflateCopy (thanks to Adam Costello)
|
- Implement deflateCopy (thanks to Adam Costello)
|
||||||
- make static libraries by default in configure, add --shared option.
|
- make static libraries by default in configure, add --shared option
|
||||||
- move MSDOS or Windows specific files to directory msdos
|
- move MSDOS or Windows specific files to directory msdos
|
||||||
- suppress the notion of partial flush to simplify the interface
|
- suppress the notion of partial flush to simplify the interface
|
||||||
(but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
|
(but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
|
||||||
|
@ -1218,7 +1311,7 @@ Changes in 1.0.6 (19 Jan 1998)
|
||||||
- added Makefile.nt (thanks to Stephen Williams)
|
- added Makefile.nt (thanks to Stephen Williams)
|
||||||
- added the unsupported "contrib" directory:
|
- added the unsupported "contrib" directory:
|
||||||
contrib/asm386/ by Gilles Vollant <info@winimage.com>
|
contrib/asm386/ by Gilles Vollant <info@winimage.com>
|
||||||
386 asm code replacing longest_match().
|
386 asm code replacing longest_match()
|
||||||
contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
|
contrib/iostream/ by Kevin Ruland <kevin@rodin.wustl.edu>
|
||||||
A C++ I/O streams interface to the zlib gz* functions
|
A C++ I/O streams interface to the zlib gz* functions
|
||||||
contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
|
contrib/iostream2/ by Tyge Løvset <Tyge.Lovset@cmr.no>
|
||||||
|
@ -1226,7 +1319,7 @@ Changes in 1.0.6 (19 Jan 1998)
|
||||||
contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
|
contrib/untgz/ by "Pedro A. Aranda Guti\irrez" <paag@tid.es>
|
||||||
A very simple tar.gz file extractor using zlib
|
A very simple tar.gz file extractor using zlib
|
||||||
contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
|
contrib/visual-basic.txt by Carlos Rios <c_rios@sonda.cl>
|
||||||
How to use compress(), uncompress() and the gz* functions from VB.
|
How to use compress(), uncompress() and the gz* functions from VB
|
||||||
- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
|
- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
|
||||||
level) in minigzip (thanks to Tom Lane)
|
level) in minigzip (thanks to Tom Lane)
|
||||||
|
|
||||||
|
@ -1235,8 +1328,8 @@ Changes in 1.0.6 (19 Jan 1998)
|
||||||
- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
|
- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
|
||||||
- add undocumented function zError to convert error code to string
|
- add undocumented function zError to convert error code to string
|
||||||
(for Tim Smithers)
|
(for Tim Smithers)
|
||||||
- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
|
- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code
|
||||||
- Use default memcpy for Symantec MSDOS compiler.
|
- Use default memcpy for Symantec MSDOS compiler
|
||||||
- Add EXPORT keyword for check_func (needed for Windows DLL)
|
- Add EXPORT keyword for check_func (needed for Windows DLL)
|
||||||
- add current directory to LD_LIBRARY_PATH for "make test"
|
- add current directory to LD_LIBRARY_PATH for "make test"
|
||||||
- create also a link for libz.so.1
|
- create also a link for libz.so.1
|
||||||
|
@ -1249,7 +1342,7 @@ Changes in 1.0.6 (19 Jan 1998)
|
||||||
- allow compilation with ANSI keywords only enabled for TurboC in large model
|
- allow compilation with ANSI keywords only enabled for TurboC in large model
|
||||||
- avoid "versionString"[0] (Borland bug)
|
- avoid "versionString"[0] (Borland bug)
|
||||||
- add NEED_DUMMY_RETURN for Borland
|
- add NEED_DUMMY_RETURN for Borland
|
||||||
- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
|
- use variable z_verbose for tracing in debug mode (L. Peter Deutsch)
|
||||||
- allow compilation with CC
|
- allow compilation with CC
|
||||||
- defined STDC for OS/2 (David Charlap)
|
- defined STDC for OS/2 (David Charlap)
|
||||||
- limit external names to 8 chars for MVS (Thomas Lund)
|
- limit external names to 8 chars for MVS (Thomas Lund)
|
||||||
|
@ -1259,7 +1352,7 @@ Changes in 1.0.6 (19 Jan 1998)
|
||||||
- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
|
- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
|
||||||
- added makelcc.bat for lcc-win32 (Tom St Denis)
|
- added makelcc.bat for lcc-win32 (Tom St Denis)
|
||||||
- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
|
- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
|
||||||
- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
|
- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion
|
||||||
- check for unistd.h in configure (for off_t)
|
- check for unistd.h in configure (for off_t)
|
||||||
- remove useless check parameter in inflate_blocks_free
|
- remove useless check parameter in inflate_blocks_free
|
||||||
- avoid useless assignment of s->check to itself in inflate_blocks_new
|
- avoid useless assignment of s->check to itself in inflate_blocks_new
|
||||||
|
@ -1280,7 +1373,7 @@ Changes in 1.0.5 (3 Jan 98)
|
||||||
Changes in 1.0.4 (24 Jul 96)
|
Changes in 1.0.4 (24 Jul 96)
|
||||||
- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
|
- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
|
||||||
bit, so the decompressor could decompress all the correct data but went
|
bit, so the decompressor could decompress all the correct data but went
|
||||||
on to attempt decompressing extra garbage data. This affected minigzip too.
|
on to attempt decompressing extra garbage data. This affected minigzip too
|
||||||
- zlibVersion and gzerror return const char* (needed for DLL)
|
- zlibVersion and gzerror return const char* (needed for DLL)
|
||||||
- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
|
- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
|
||||||
- use z_error only for DEBUG (avoid problem with DLLs)
|
- use z_error only for DEBUG (avoid problem with DLLs)
|
||||||
|
@ -1310,7 +1403,7 @@ Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
|
||||||
- fix array overlay in deflate.c which sometimes caused bad compressed data
|
- fix array overlay in deflate.c which sometimes caused bad compressed data
|
||||||
- fix inflate bug with empty stored block
|
- fix inflate bug with empty stored block
|
||||||
- fix MSDOS medium model which was broken in 0.99
|
- fix MSDOS medium model which was broken in 0.99
|
||||||
- fix deflateParams() which could generate bad compressed data.
|
- fix deflateParams() which could generate bad compressed data
|
||||||
- Bytef is define'd instead of typedef'ed (work around Borland bug)
|
- Bytef is define'd instead of typedef'ed (work around Borland bug)
|
||||||
- added an INDEX file
|
- added an INDEX file
|
||||||
- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
|
- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
|
||||||
|
@ -1331,7 +1424,7 @@ Changes in 0.99 (27 Jan 96)
|
||||||
- allow preset dictionary shared between compressor and decompressor
|
- allow preset dictionary shared between compressor and decompressor
|
||||||
- allow compression level 0 (no compression)
|
- allow compression level 0 (no compression)
|
||||||
- add deflateParams in zlib.h: allow dynamic change of compression level
|
- add deflateParams in zlib.h: allow dynamic change of compression level
|
||||||
and compression strategy.
|
and compression strategy
|
||||||
- test large buffers and deflateParams in example.c
|
- test large buffers and deflateParams in example.c
|
||||||
- add optional "configure" to build zlib as a shared library
|
- add optional "configure" to build zlib as a shared library
|
||||||
- suppress Makefile.qnx, use configure instead
|
- suppress Makefile.qnx, use configure instead
|
||||||
|
@ -1370,33 +1463,33 @@ Changes in 0.99 (27 Jan 96)
|
||||||
- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
|
- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
|
||||||
- in fcalloc, normalize pointer if size > 65520 bytes
|
- in fcalloc, normalize pointer if size > 65520 bytes
|
||||||
- don't use special fcalloc for 32 bit Borland C++
|
- don't use special fcalloc for 32 bit Borland C++
|
||||||
- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
|
- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc.
|
||||||
- use Z_BINARY instead of BINARY
|
- use Z_BINARY instead of BINARY
|
||||||
- document that gzclose after gzdopen will close the file
|
- document that gzclose after gzdopen will close the file
|
||||||
- allow "a" as mode in gzopen.
|
- allow "a" as mode in gzopen
|
||||||
- fix error checking in gzread
|
- fix error checking in gzread
|
||||||
- allow skipping .gz extra-field on pipes
|
- allow skipping .gz extra-field on pipes
|
||||||
- added reference to Perl interface in README
|
- added reference to Perl interface in README
|
||||||
- put the crc table in FAR data (I dislike more and more the medium model :)
|
- put the crc table in FAR data (I dislike more and more the medium model :)
|
||||||
- added get_crc_table
|
- added get_crc_table
|
||||||
- added a dimension to all arrays (Borland C can't count).
|
- added a dimension to all arrays (Borland C can't count)
|
||||||
- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
|
- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
|
||||||
- guard against multiple inclusion of *.h (for precompiled header on Mac)
|
- guard against multiple inclusion of *.h (for precompiled header on Mac)
|
||||||
- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
|
- Watcom C pretends to be Microsoft C small model even in 32 bit mode
|
||||||
- don't use unsized arrays to avoid silly warnings by Visual C++:
|
- don't use unsized arrays to avoid silly warnings by Visual C++:
|
||||||
warning C4746: 'inflate_mask' : unsized array treated as '__far'
|
warning C4746: 'inflate_mask' : unsized array treated as '__far'
|
||||||
(what's wrong with far data in far model?).
|
(what's wrong with far data in far model?)
|
||||||
- define enum out of inflate_blocks_state to allow compilation with C++
|
- define enum out of inflate_blocks_state to allow compilation with C++
|
||||||
|
|
||||||
Changes in 0.95 (16 Aug 95)
|
Changes in 0.95 (16 Aug 95)
|
||||||
- fix MSDOS small and medium model (now easier to adapt to any compiler)
|
- fix MSDOS small and medium model (now easier to adapt to any compiler)
|
||||||
- inlined send_bits
|
- inlined send_bits
|
||||||
- fix the final (:-) bug for deflate with flush (output was correct but
|
- fix the final (:-) bug for deflate with flush (output was correct but
|
||||||
not completely flushed in rare occasions).
|
not completely flushed in rare occasions)
|
||||||
- default window size is same for compression and decompression
|
- default window size is same for compression and decompression
|
||||||
(it's now sufficient to set MAX_WBITS in zconf.h).
|
(it's now sufficient to set MAX_WBITS in zconf.h)
|
||||||
- voidp -> voidpf and voidnp -> voidp (for consistency with other
|
- voidp -> voidpf and voidnp -> voidp (for consistency with other
|
||||||
typedefs and because voidnp was not near in large model).
|
typedefs and because voidnp was not near in large model)
|
||||||
|
|
||||||
Changes in 0.94 (13 Aug 95)
|
Changes in 0.94 (13 Aug 95)
|
||||||
- support MSDOS medium model
|
- support MSDOS medium model
|
||||||
|
@ -1405,12 +1498,12 @@ Changes in 0.94 (13 Aug 95)
|
||||||
- added support for VMS
|
- added support for VMS
|
||||||
- allow a compression level in gzopen()
|
- allow a compression level in gzopen()
|
||||||
- gzflush now calls fflush
|
- gzflush now calls fflush
|
||||||
- For deflate with flush, flush even if no more input is provided.
|
- For deflate with flush, flush even if no more input is provided
|
||||||
- rename libgz.a as libz.a
|
- rename libgz.a as libz.a
|
||||||
- avoid complex expression in infcodes.c triggering Turbo C bug
|
- avoid complex expression in infcodes.c triggering Turbo C bug
|
||||||
- work around a problem with gcc on Alpha (in INSERT_STRING)
|
- work around a problem with gcc on Alpha (in INSERT_STRING)
|
||||||
- don't use inline functions (problem with some gcc versions)
|
- don't use inline functions (problem with some gcc versions)
|
||||||
- allow renaming of Byte, uInt, etc... with #define.
|
- allow renaming of Byte, uInt, etc... with #define
|
||||||
- avoid warning about (unused) pointer before start of array in deflate.c
|
- avoid warning about (unused) pointer before start of array in deflate.c
|
||||||
- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
|
- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
|
||||||
- avoid reserved word 'new' in trees.c
|
- avoid reserved word 'new' in trees.c
|
||||||
|
@ -1429,7 +1522,7 @@ Changes in 0.92 (3 May 95)
|
||||||
- no memcpy on Pyramid
|
- no memcpy on Pyramid
|
||||||
- suppressed inftest.c
|
- suppressed inftest.c
|
||||||
- optimized fill_window, put longest_match inline for gcc
|
- optimized fill_window, put longest_match inline for gcc
|
||||||
- optimized inflate on stored blocks.
|
- optimized inflate on stored blocks
|
||||||
- untabify all sources to simplify patches
|
- untabify all sources to simplify patches
|
||||||
|
|
||||||
Changes in 0.91 (2 May 95)
|
Changes in 0.91 (2 May 95)
|
||||||
|
@ -1447,7 +1540,7 @@ Changes in 0.9 (1 May 95)
|
||||||
- let again gzread copy uncompressed data unchanged (was working in 0.71)
|
- let again gzread copy uncompressed data unchanged (was working in 0.71)
|
||||||
- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
|
- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
|
||||||
- added a test of inflateSync in example.c
|
- added a test of inflateSync in example.c
|
||||||
- moved MAX_WBITS to zconf.h because users might want to change that.
|
- moved MAX_WBITS to zconf.h because users might want to change that
|
||||||
- document explicitly that zalloc(64K) on MSDOS must return a normalized
|
- document explicitly that zalloc(64K) on MSDOS must return a normalized
|
||||||
pointer (zero offset)
|
pointer (zero offset)
|
||||||
- added Makefiles for Microsoft C, Turbo C, Borland C++
|
- added Makefiles for Microsoft C, Turbo C, Borland C++
|
||||||
|
@ -1456,7 +1549,7 @@ Changes in 0.9 (1 May 95)
|
||||||
Changes in 0.8 (29 April 95)
|
Changes in 0.8 (29 April 95)
|
||||||
- added fast inflate (inffast.c)
|
- added fast inflate (inffast.c)
|
||||||
- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
|
- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
|
||||||
is incompatible with previous versions of zlib which returned Z_OK.
|
is incompatible with previous versions of zlib which returned Z_OK
|
||||||
- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
|
- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
|
||||||
(actually that was not a compiler bug, see 0.81 above)
|
(actually that was not a compiler bug, see 0.81 above)
|
||||||
- gzread no longer reads one extra byte in certain cases
|
- gzread no longer reads one extra byte in certain cases
|
||||||
|
@ -1466,50 +1559,50 @@ Changes in 0.8 (29 April 95)
|
||||||
|
|
||||||
Changes in 0.71 (14 April 95)
|
Changes in 0.71 (14 April 95)
|
||||||
- Fixed more MSDOS compilation problems :( There is still a bug with
|
- Fixed more MSDOS compilation problems :( There is still a bug with
|
||||||
TurboC large model.
|
TurboC large model
|
||||||
|
|
||||||
Changes in 0.7 (14 April 95)
|
Changes in 0.7 (14 April 95)
|
||||||
- Added full inflate support.
|
- Added full inflate support
|
||||||
- Simplified the crc32() interface. The pre- and post-conditioning
|
- Simplified the crc32() interface. The pre- and post-conditioning
|
||||||
(one's complement) is now done inside crc32(). WARNING: this is
|
(one's complement) is now done inside crc32(). WARNING: this is
|
||||||
incompatible with previous versions; see zlib.h for the new usage.
|
incompatible with previous versions; see zlib.h for the new usage
|
||||||
|
|
||||||
Changes in 0.61 (12 April 95)
|
Changes in 0.61 (12 April 95)
|
||||||
- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
|
- workaround for a bug in TurboC. example and minigzip now work on MSDOS
|
||||||
|
|
||||||
Changes in 0.6 (11 April 95)
|
Changes in 0.6 (11 April 95)
|
||||||
- added minigzip.c
|
- added minigzip.c
|
||||||
- added gzdopen to reopen a file descriptor as gzFile
|
- added gzdopen to reopen a file descriptor as gzFile
|
||||||
- added transparent reading of non-gziped files in gzread.
|
- added transparent reading of non-gziped files in gzread
|
||||||
- fixed bug in gzread (don't read crc as data)
|
- fixed bug in gzread (don't read crc as data)
|
||||||
- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
|
- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose)
|
||||||
- don't allocate big arrays in the stack (for MSDOS)
|
- don't allocate big arrays in the stack (for MSDOS)
|
||||||
- fix some MSDOS compilation problems
|
- fix some MSDOS compilation problems
|
||||||
|
|
||||||
Changes in 0.5:
|
Changes in 0.5:
|
||||||
- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
|
- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
|
||||||
not yet Z_FULL_FLUSH.
|
not yet Z_FULL_FLUSH
|
||||||
- support decompression but only in a single step (forced Z_FINISH)
|
- support decompression but only in a single step (forced Z_FINISH)
|
||||||
- added opaque object for zalloc and zfree.
|
- added opaque object for zalloc and zfree
|
||||||
- added deflateReset and inflateReset
|
- added deflateReset and inflateReset
|
||||||
- added a variable zlib_version for consistency checking.
|
- added a variable zlib_version for consistency checking
|
||||||
- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
|
- renamed the 'filter' parameter of deflateInit2 as 'strategy'
|
||||||
Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
|
Added Z_FILTERED and Z_HUFFMAN_ONLY constants
|
||||||
|
|
||||||
Changes in 0.4:
|
Changes in 0.4:
|
||||||
- avoid "zip" everywhere, use zlib instead of ziplib.
|
- avoid "zip" everywhere, use zlib instead of ziplib
|
||||||
- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
|
- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
|
||||||
if compression method == 8.
|
if compression method == 8
|
||||||
- added adler32 and crc32
|
- added adler32 and crc32
|
||||||
- renamed deflateOptions as deflateInit2, call one or the other but not both
|
- renamed deflateOptions as deflateInit2, call one or the other but not both
|
||||||
- added the method parameter for deflateInit2.
|
- added the method parameter for deflateInit2
|
||||||
- added inflateInit2
|
- added inflateInit2
|
||||||
- simplied considerably deflateInit and inflateInit by not supporting
|
- simplified considerably deflateInit and inflateInit by not supporting
|
||||||
user-provided history buffer. This is supported only in deflateInit2
|
user-provided history buffer. This is supported only in deflateInit2
|
||||||
and inflateInit2.
|
and inflateInit2
|
||||||
|
|
||||||
Changes in 0.3:
|
Changes in 0.3:
|
||||||
- prefix all macro names with Z_
|
- prefix all macro names with Z_
|
||||||
- use Z_FINISH instead of deflateEnd to finish compression.
|
- use Z_FINISH instead of deflateEnd to finish compression
|
||||||
- added Z_HUFFMAN_ONLY
|
- added Z_HUFFMAN_ONLY
|
||||||
- added gzerror()
|
- added gzerror()
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
If your question is not there, please check the zlib home page
|
If your question is not there, please check the zlib home page
|
||||||
http://zlib.net/ which may have more recent information.
|
http://zlib.net/ which may have more recent information.
|
||||||
The lastest zlib FAQ is at http://zlib.net/zlib_faq.html
|
The latest zlib FAQ is at http://zlib.net/zlib_faq.html
|
||||||
|
|
||||||
|
|
||||||
1. Is zlib Y2K-compliant?
|
1. Is zlib Y2K-compliant?
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
Copyright notice:
|
||||||
|
|
||||||
|
(C) 1995-2022 Jean-loup Gailly and Mark Adler
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
Jean-loup Gailly Mark Adler
|
||||||
|
jloup@gzip.org madler@alumni.caltech.edu
|
|
@ -1,6 +1,6 @@
|
||||||
ZLIB DATA COMPRESSION LIBRARY
|
ZLIB DATA COMPRESSION LIBRARY
|
||||||
|
|
||||||
zlib 1.2.11 is a general purpose data compression library. All the code is
|
zlib 1.3 is a general purpose data compression library. All the code is
|
||||||
thread safe. The data format used by the zlib library is described by RFCs
|
thread safe. The data format used by the zlib library is described by RFCs
|
||||||
(Request for Comments) 1950 to 1952 in the files
|
(Request for Comments) 1950 to 1952 in the files
|
||||||
http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
|
http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
|
||||||
|
@ -29,18 +29,17 @@ PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
|
||||||
|
|
||||||
Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
|
Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
|
||||||
issue of Dr. Dobb's Journal; a copy of the article is available at
|
issue of Dr. Dobb's Journal; a copy of the article is available at
|
||||||
http://marknelson.us/1997/01/01/zlib-engine/ .
|
https://marknelson.us/posts/1997/01/01/zlib-engine.html .
|
||||||
|
|
||||||
The changes made in version 1.2.11 are documented in the file ChangeLog.
|
The changes made in version 1.3 are documented in the file ChangeLog.
|
||||||
|
|
||||||
Unsupported third party contributions are provided in directory contrib/ .
|
Unsupported third party contributions are provided in directory contrib/ .
|
||||||
|
|
||||||
zlib is available in Java using the java.util.zip package, documented at
|
zlib is available in Java using the java.util.zip package. Follow the API
|
||||||
http://java.sun.com/developer/technicalArticles/Programming/compression/ .
|
Documentation link at: https://docs.oracle.com/search/?q=java.util.zip .
|
||||||
|
|
||||||
A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is available
|
A Perl interface to zlib and bzip2 written by Paul Marquess <pmqs@cpan.org>
|
||||||
at CPAN (Comprehensive Perl Archive Network) sites, including
|
can be found at https://github.com/pmqs/IO-Compress .
|
||||||
http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
|
|
||||||
|
|
||||||
A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
|
A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
|
||||||
available in Python 1.5 and later versions, see
|
available in Python 1.5 and later versions, see
|
||||||
|
@ -64,7 +63,7 @@ Notes for some targets:
|
||||||
- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
|
- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
|
||||||
when compiled with cc.
|
when compiled with cc.
|
||||||
|
|
||||||
- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
|
- On Digital Unix 4.0D (formerly OSF/1) on AlphaServer, the cc option -std1 is
|
||||||
necessary to get gzprintf working correctly. This is done by configure.
|
necessary to get gzprintf working correctly. This is done by configure.
|
||||||
|
|
||||||
- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
|
- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
|
||||||
|
@ -84,7 +83,7 @@ Acknowledgments:
|
||||||
|
|
||||||
Copyright notice:
|
Copyright notice:
|
||||||
|
|
||||||
(C) 1995-2017 Jean-loup Gailly and Mark Adler
|
(C) 1995-2023 Jean-loup Gailly and Mark Adler
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
This software is provided 'as-is', without any express or implied
|
||||||
warranty. In no event will the authors be held liable for any damages
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
@ -108,7 +107,10 @@ Copyright notice:
|
||||||
If you use the zlib library in a product, we would appreciate *not* receiving
|
If you use the zlib library in a product, we would appreciate *not* receiving
|
||||||
lengthy legal documents to sign. The sources are provided for free but without
|
lengthy legal documents to sign. The sources are provided for free but without
|
||||||
warranty of any kind. The library has been entirely written by Jean-loup
|
warranty of any kind. The library has been entirely written by Jean-loup
|
||||||
Gailly and Mark Adler; it does not include third-party code.
|
Gailly and Mark Adler; it does not include third-party code. We make all
|
||||||
|
contributions to and distributions of this project solely in our personal
|
||||||
|
capacity, and are not conveying any rights to any intellectual property of
|
||||||
|
any third parties.
|
||||||
|
|
||||||
If you redistribute modified sources, we would appreciate that you include in
|
If you redistribute modified sources, we would appreciate that you include in
|
||||||
the file ChangeLog history information documenting your changes. Please read
|
the file ChangeLog history information documenting your changes. Please read
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
#include "zutil.h"
|
#include "zutil.h"
|
||||||
|
|
||||||
local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
|
|
||||||
|
|
||||||
#define BASE 65521U /* largest prime smaller than 65536 */
|
#define BASE 65521U /* largest prime smaller than 65536 */
|
||||||
#define NMAX 5552
|
#define NMAX 5552
|
||||||
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
|
||||||
|
@ -60,11 +58,7 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
uLong ZEXPORT adler32_z(adler, buf, len)
|
uLong ZEXPORT adler32_z(uLong adler, const Bytef *buf, z_size_t len) {
|
||||||
uLong adler;
|
|
||||||
const Bytef *buf;
|
|
||||||
z_size_t len;
|
|
||||||
{
|
|
||||||
unsigned long sum2;
|
unsigned long sum2;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
|
@ -131,20 +125,12 @@ uLong ZEXPORT adler32_z(adler, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
uLong ZEXPORT adler32(adler, buf, len)
|
uLong ZEXPORT adler32(uLong adler, const Bytef *buf, uInt len) {
|
||||||
uLong adler;
|
|
||||||
const Bytef *buf;
|
|
||||||
uInt len;
|
|
||||||
{
|
|
||||||
return adler32_z(adler, buf, len);
|
return adler32_z(adler, buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
local uLong adler32_combine_(adler1, adler2, len2)
|
local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2) {
|
||||||
uLong adler1;
|
|
||||||
uLong adler2;
|
|
||||||
z_off64_t len2;
|
|
||||||
{
|
|
||||||
unsigned long sum1;
|
unsigned long sum1;
|
||||||
unsigned long sum2;
|
unsigned long sum2;
|
||||||
unsigned rem;
|
unsigned rem;
|
||||||
|
@ -169,18 +155,10 @@ local uLong adler32_combine_(adler1, adler2, len2)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================================================================= */
|
/* ========================================================================= */
|
||||||
uLong ZEXPORT adler32_combine(adler1, adler2, len2)
|
uLong ZEXPORT adler32_combine(uLong adler1, uLong adler2, z_off_t len2) {
|
||||||
uLong adler1;
|
|
||||||
uLong adler2;
|
|
||||||
z_off_t len2;
|
|
||||||
{
|
|
||||||
return adler32_combine_(adler1, adler2, len2);
|
return adler32_combine_(adler1, adler2, len2);
|
||||||
}
|
}
|
||||||
|
|
||||||
uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
|
uLong ZEXPORT adler32_combine64(uLong adler1, uLong adler2, z_off64_t len2) {
|
||||||
uLong adler1;
|
|
||||||
uLong adler2;
|
|
||||||
z_off64_t len2;
|
|
||||||
{
|
|
||||||
return adler32_combine_(adler1, adler2, len2);
|
return adler32_combine_(adler1, adler2, len2);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,8 @@
|
||||||
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
|
memory, Z_BUF_ERROR if there was not enough room in the output buffer,
|
||||||
Z_STREAM_ERROR if the level parameter is invalid.
|
Z_STREAM_ERROR if the level parameter is invalid.
|
||||||
*/
|
*/
|
||||||
int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
|
int ZEXPORT compress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||||
Bytef *dest;
|
uLong sourceLen, int level) {
|
||||||
uLongf *destLen;
|
|
||||||
const Bytef *source;
|
|
||||||
uLong sourceLen;
|
|
||||||
int level;
|
|
||||||
{
|
|
||||||
z_stream stream;
|
z_stream stream;
|
||||||
int err;
|
int err;
|
||||||
const uInt max = (uInt)-1;
|
const uInt max = (uInt)-1;
|
||||||
|
@ -65,12 +60,8 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
*/
|
*/
|
||||||
int ZEXPORT compress (dest, destLen, source, sourceLen)
|
int ZEXPORT compress(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||||
Bytef *dest;
|
uLong sourceLen) {
|
||||||
uLongf *destLen;
|
|
||||||
const Bytef *source;
|
|
||||||
uLong sourceLen;
|
|
||||||
{
|
|
||||||
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
|
return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,9 +69,7 @@ int ZEXPORT compress (dest, destLen, source, sourceLen)
|
||||||
If the default memLevel or windowBits for deflateInit() is changed, then
|
If the default memLevel or windowBits for deflateInit() is changed, then
|
||||||
this function needs to be updated.
|
this function needs to be updated.
|
||||||
*/
|
*/
|
||||||
uLong ZEXPORT compressBound (sourceLen)
|
uLong ZEXPORT compressBound(uLong sourceLen) {
|
||||||
uLong sourceLen;
|
|
||||||
{
|
|
||||||
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
|
||||||
(sourceLen >> 25) + 13;
|
(sourceLen >> 25) + 13;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
||||||
/* deflate.h -- internal compression state
|
/* deflate.h -- internal compression state
|
||||||
* Copyright (C) 1995-2016 Jean-loup Gailly
|
* Copyright (C) 1995-2018 Jean-loup Gailly
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ typedef struct internal_state {
|
||||||
/* Depth of each subtree used as tie breaker for trees of equal frequency
|
/* Depth of each subtree used as tie breaker for trees of equal frequency
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uchf *l_buf; /* buffer for literals or lengths */
|
uchf *sym_buf; /* buffer for distances and literals/lengths */
|
||||||
|
|
||||||
uInt lit_bufsize;
|
uInt lit_bufsize;
|
||||||
/* Size of match buffer for literals/lengths. There are 4 reasons for
|
/* Size of match buffer for literals/lengths. There are 4 reasons for
|
||||||
|
@ -239,13 +239,8 @@ typedef struct internal_state {
|
||||||
* - I can't count above 4
|
* - I can't count above 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
uInt last_lit; /* running index in l_buf */
|
uInt sym_next; /* running index in sym_buf */
|
||||||
|
uInt sym_end; /* symbol table full when sym_next reaches this */
|
||||||
ushf *d_buf;
|
|
||||||
/* Buffer for distances. To simplify the code, d_buf and l_buf have
|
|
||||||
* the same number of elements. To use different lengths, an extra flag
|
|
||||||
* array would be necessary.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ulg opt_len; /* bit length of current block with optimal trees */
|
ulg opt_len; /* bit length of current block with optimal trees */
|
||||||
ulg static_len; /* bit length of current block with static trees */
|
ulg static_len; /* bit length of current block with static trees */
|
||||||
|
@ -296,14 +291,14 @@ typedef struct internal_state {
|
||||||
memory checker errors from longest match routines */
|
memory checker errors from longest match routines */
|
||||||
|
|
||||||
/* in trees.c */
|
/* in trees.c */
|
||||||
void ZLIB_INTERNAL _tr_init OF((deflate_state *s));
|
void ZLIB_INTERNAL _tr_init(deflate_state *s);
|
||||||
int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
|
int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc);
|
||||||
void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf,
|
void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
|
||||||
ulg stored_len, int last));
|
ulg stored_len, int last);
|
||||||
void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s));
|
void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s);
|
||||||
void ZLIB_INTERNAL _tr_align OF((deflate_state *s));
|
void ZLIB_INTERNAL _tr_align(deflate_state *s);
|
||||||
void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
|
void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
|
||||||
ulg stored_len, int last));
|
ulg stored_len, int last);
|
||||||
|
|
||||||
#define d_code(dist) \
|
#define d_code(dist) \
|
||||||
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
|
((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
|
||||||
|
@ -325,20 +320,22 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf,
|
||||||
|
|
||||||
# define _tr_tally_lit(s, c, flush) \
|
# define _tr_tally_lit(s, c, flush) \
|
||||||
{ uch cc = (c); \
|
{ uch cc = (c); \
|
||||||
s->d_buf[s->last_lit] = 0; \
|
s->sym_buf[s->sym_next++] = 0; \
|
||||||
s->l_buf[s->last_lit++] = cc; \
|
s->sym_buf[s->sym_next++] = 0; \
|
||||||
|
s->sym_buf[s->sym_next++] = cc; \
|
||||||
s->dyn_ltree[cc].Freq++; \
|
s->dyn_ltree[cc].Freq++; \
|
||||||
flush = (s->last_lit == s->lit_bufsize-1); \
|
flush = (s->sym_next == s->sym_end); \
|
||||||
}
|
}
|
||||||
# define _tr_tally_dist(s, distance, length, flush) \
|
# define _tr_tally_dist(s, distance, length, flush) \
|
||||||
{ uch len = (uch)(length); \
|
{ uch len = (uch)(length); \
|
||||||
ush dist = (ush)(distance); \
|
ush dist = (ush)(distance); \
|
||||||
s->d_buf[s->last_lit] = dist; \
|
s->sym_buf[s->sym_next++] = (uch)dist; \
|
||||||
s->l_buf[s->last_lit++] = len; \
|
s->sym_buf[s->sym_next++] = (uch)(dist >> 8); \
|
||||||
|
s->sym_buf[s->sym_next++] = len; \
|
||||||
dist--; \
|
dist--; \
|
||||||
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
|
s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
|
||||||
s->dyn_dtree[d_code(dist)].Freq++; \
|
s->dyn_dtree[d_code(dist)].Freq++; \
|
||||||
flush = (s->last_lit == s->lit_bufsize-1); \
|
flush = (s->sym_next == s->sym_end); \
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
|
# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
|
||||||
|
|
|
@ -1,49 +0,0 @@
|
||||||
This directory contains examples of the use of zlib and other relevant
|
|
||||||
programs and documentation.
|
|
||||||
|
|
||||||
enough.c
|
|
||||||
calculation and justification of ENOUGH parameter in inftrees.h
|
|
||||||
- calculates the maximum table space used in inflate tree
|
|
||||||
construction over all possible Huffman codes
|
|
||||||
|
|
||||||
fitblk.c
|
|
||||||
compress just enough input to nearly fill a requested output size
|
|
||||||
- zlib isn't designed to do this, but fitblk does it anyway
|
|
||||||
|
|
||||||
gun.c
|
|
||||||
uncompress a gzip file
|
|
||||||
- illustrates the use of inflateBack() for high speed file-to-file
|
|
||||||
decompression using call-back functions
|
|
||||||
- is approximately twice as fast as gzip -d
|
|
||||||
- also provides Unix uncompress functionality, again twice as fast
|
|
||||||
|
|
||||||
gzappend.c
|
|
||||||
append to a gzip file
|
|
||||||
- illustrates the use of the Z_BLOCK flush parameter for inflate()
|
|
||||||
- illustrates the use of deflatePrime() to start at any bit
|
|
||||||
|
|
||||||
gzjoin.c
|
|
||||||
join gzip files without recalculating the crc or recompressing
|
|
||||||
- illustrates the use of the Z_BLOCK flush parameter for inflate()
|
|
||||||
- illustrates the use of crc32_combine()
|
|
||||||
|
|
||||||
gzlog.c
|
|
||||||
gzlog.h
|
|
||||||
efficiently and robustly maintain a message log file in gzip format
|
|
||||||
- illustrates use of raw deflate, Z_PARTIAL_FLUSH, deflatePrime(),
|
|
||||||
and deflateSetDictionary()
|
|
||||||
- illustrates use of a gzip header extra field
|
|
||||||
|
|
||||||
zlib_how.html
|
|
||||||
painfully comprehensive description of zpipe.c (see below)
|
|
||||||
- describes in excruciating detail the use of deflate() and inflate()
|
|
||||||
|
|
||||||
zpipe.c
|
|
||||||
reads and writes zlib streams from stdin to stdout
|
|
||||||
- illustrates the proper use of deflate() and inflate()
|
|
||||||
- deeply commented in zlib_how.html (see above)
|
|
||||||
|
|
||||||
zran.c
|
|
||||||
index a zlib or gzip stream and randomly access it
|
|
||||||
- illustrates the use of Z_BLOCK, inflatePrime(), and
|
|
||||||
inflateSetDictionary() to provide random access
|
|
|
@ -1,572 +0,0 @@
|
||||||
/* enough.c -- determine the maximum size of inflate's Huffman code tables over
|
|
||||||
* all possible valid and complete Huffman codes, subject to a length limit.
|
|
||||||
* Copyright (C) 2007, 2008, 2012 Mark Adler
|
|
||||||
* Version 1.4 18 August 2012 Mark Adler
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Version history:
|
|
||||||
1.0 3 Jan 2007 First version (derived from codecount.c version 1.4)
|
|
||||||
1.1 4 Jan 2007 Use faster incremental table usage computation
|
|
||||||
Prune examine() search on previously visited states
|
|
||||||
1.2 5 Jan 2007 Comments clean up
|
|
||||||
As inflate does, decrease root for short codes
|
|
||||||
Refuse cases where inflate would increase root
|
|
||||||
1.3 17 Feb 2008 Add argument for initial root table size
|
|
||||||
Fix bug for initial root table size == max - 1
|
|
||||||
Use a macro to compute the history index
|
|
||||||
1.4 18 Aug 2012 Avoid shifts more than bits in type (caused endless loop!)
|
|
||||||
Clean up comparisons of different types
|
|
||||||
Clean up code indentation
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
Examine all possible Huffman codes for a given number of symbols and a
|
|
||||||
maximum code length in bits to determine the maximum table size for zilb's
|
|
||||||
inflate. Only complete Huffman codes are counted.
|
|
||||||
|
|
||||||
Two codes are considered distinct if the vectors of the number of codes per
|
|
||||||
length are not identical. So permutations of the symbol assignments result
|
|
||||||
in the same code for the counting, as do permutations of the assignments of
|
|
||||||
the bit values to the codes (i.e. only canonical codes are counted).
|
|
||||||
|
|
||||||
We build a code from shorter to longer lengths, determining how many symbols
|
|
||||||
are coded at each length. At each step, we have how many symbols remain to
|
|
||||||
be coded, what the last code length used was, and how many bit patterns of
|
|
||||||
that length remain unused. Then we add one to the code length and double the
|
|
||||||
number of unused patterns to graduate to the next code length. We then
|
|
||||||
assign all portions of the remaining symbols to that code length that
|
|
||||||
preserve the properties of a correct and eventually complete code. Those
|
|
||||||
properties are: we cannot use more bit patterns than are available; and when
|
|
||||||
all the symbols are used, there are exactly zero possible bit patterns
|
|
||||||
remaining.
|
|
||||||
|
|
||||||
The inflate Huffman decoding algorithm uses two-level lookup tables for
|
|
||||||
speed. There is a single first-level table to decode codes up to root bits
|
|
||||||
in length (root == 9 in the current inflate implementation). The table
|
|
||||||
has 1 << root entries and is indexed by the next root bits of input. Codes
|
|
||||||
shorter than root bits have replicated table entries, so that the correct
|
|
||||||
entry is pointed to regardless of the bits that follow the short code. If
|
|
||||||
the code is longer than root bits, then the table entry points to a second-
|
|
||||||
level table. The size of that table is determined by the longest code with
|
|
||||||
that root-bit prefix. If that longest code has length len, then the table
|
|
||||||
has size 1 << (len - root), to index the remaining bits in that set of
|
|
||||||
codes. Each subsequent root-bit prefix then has its own sub-table. The
|
|
||||||
total number of table entries required by the code is calculated
|
|
||||||
incrementally as the number of codes at each bit length is populated. When
|
|
||||||
all of the codes are shorter than root bits, then root is reduced to the
|
|
||||||
longest code length, resulting in a single, smaller, one-level table.
|
|
||||||
|
|
||||||
The inflate algorithm also provides for small values of root (relative to
|
|
||||||
the log2 of the number of symbols), where the shortest code has more bits
|
|
||||||
than root. In that case, root is increased to the length of the shortest
|
|
||||||
code. This program, by design, does not handle that case, so it is verified
|
|
||||||
that the number of symbols is less than 2^(root + 1).
|
|
||||||
|
|
||||||
In order to speed up the examination (by about ten orders of magnitude for
|
|
||||||
the default arguments), the intermediate states in the build-up of a code
|
|
||||||
are remembered and previously visited branches are pruned. The memory
|
|
||||||
required for this will increase rapidly with the total number of symbols and
|
|
||||||
the maximum code length in bits. However this is a very small price to pay
|
|
||||||
for the vast speedup.
|
|
||||||
|
|
||||||
First, all of the possible Huffman codes are counted, and reachable
|
|
||||||
intermediate states are noted by a non-zero count in a saved-results array.
|
|
||||||
Second, the intermediate states that lead to (root + 1) bit or longer codes
|
|
||||||
are used to look at all sub-codes from those junctures for their inflate
|
|
||||||
memory usage. (The amount of memory used is not affected by the number of
|
|
||||||
codes of root bits or less in length.) Third, the visited states in the
|
|
||||||
construction of those sub-codes and the associated calculation of the table
|
|
||||||
size is recalled in order to avoid recalculating from the same juncture.
|
|
||||||
Beginning the code examination at (root + 1) bit codes, which is enabled by
|
|
||||||
identifying the reachable nodes, accounts for about six of the orders of
|
|
||||||
magnitude of improvement for the default arguments. About another four
|
|
||||||
orders of magnitude come from not revisiting previous states. Out of
|
|
||||||
approximately 2x10^16 possible Huffman codes, only about 2x10^6 sub-codes
|
|
||||||
need to be examined to cover all of the possible table memory usage cases
|
|
||||||
for the default arguments of 286 symbols limited to 15-bit codes.
|
|
||||||
|
|
||||||
Note that an unsigned long long type is used for counting. It is quite easy
|
|
||||||
to exceed the capacity of an eight-byte integer with a large number of
|
|
||||||
symbols and a large maximum code length, so multiple-precision arithmetic
|
|
||||||
would need to replace the unsigned long long arithmetic in that case. This
|
|
||||||
program will abort if an overflow occurs. The big_t type identifies where
|
|
||||||
the counting takes place.
|
|
||||||
|
|
||||||
An unsigned long long type is also used for calculating the number of
|
|
||||||
possible codes remaining at the maximum length. This limits the maximum
|
|
||||||
code length to the number of bits in a long long minus the number of bits
|
|
||||||
needed to represent the symbols in a flat code. The code_t type identifies
|
|
||||||
where the bit pattern counting takes place.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#define local static
|
|
||||||
|
|
||||||
/* special data types */
|
|
||||||
typedef unsigned long long big_t; /* type for code counting */
|
|
||||||
typedef unsigned long long code_t; /* type for bit pattern counting */
|
|
||||||
struct tab { /* type for been here check */
|
|
||||||
size_t len; /* length of bit vector in char's */
|
|
||||||
char *vec; /* allocated bit vector */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The array for saving results, num[], is indexed with this triplet:
|
|
||||||
|
|
||||||
syms: number of symbols remaining to code
|
|
||||||
left: number of available bit patterns at length len
|
|
||||||
len: number of bits in the codes currently being assigned
|
|
||||||
|
|
||||||
Those indices are constrained thusly when saving results:
|
|
||||||
|
|
||||||
syms: 3..totsym (totsym == total symbols to code)
|
|
||||||
left: 2..syms - 1, but only the evens (so syms == 8 -> 2, 4, 6)
|
|
||||||
len: 1..max - 1 (max == maximum code length in bits)
|
|
||||||
|
|
||||||
syms == 2 is not saved since that immediately leads to a single code. left
|
|
||||||
must be even, since it represents the number of available bit patterns at
|
|
||||||
the current length, which is double the number at the previous length.
|
|
||||||
left ends at syms-1 since left == syms immediately results in a single code.
|
|
||||||
(left > sym is not allowed since that would result in an incomplete code.)
|
|
||||||
len is less than max, since the code completes immediately when len == max.
|
|
||||||
|
|
||||||
The offset into the array is calculated for the three indices with the
|
|
||||||
first one (syms) being outermost, and the last one (len) being innermost.
|
|
||||||
We build the array with length max-1 lists for the len index, with syms-3
|
|
||||||
of those for each symbol. There are totsym-2 of those, with each one
|
|
||||||
varying in length as a function of sym. See the calculation of index in
|
|
||||||
count() for the index, and the calculation of size in main() for the size
|
|
||||||
of the array.
|
|
||||||
|
|
||||||
For the deflate example of 286 symbols limited to 15-bit codes, the array
|
|
||||||
has 284,284 entries, taking up 2.17 MB for an 8-byte big_t. More than
|
|
||||||
half of the space allocated for saved results is actually used -- not all
|
|
||||||
possible triplets are reached in the generation of valid Huffman codes.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* The array for tracking visited states, done[], is itself indexed identically
|
|
||||||
to the num[] array as described above for the (syms, left, len) triplet.
|
|
||||||
Each element in the array is further indexed by the (mem, rem) doublet,
|
|
||||||
where mem is the amount of inflate table space used so far, and rem is the
|
|
||||||
remaining unused entries in the current inflate sub-table. Each indexed
|
|
||||||
element is simply one bit indicating whether the state has been visited or
|
|
||||||
not. Since the ranges for mem and rem are not known a priori, each bit
|
|
||||||
vector is of a variable size, and grows as needed to accommodate the visited
|
|
||||||
states. mem and rem are used to calculate a single index in a triangular
|
|
||||||
array. Since the range of mem is expected in the default case to be about
|
|
||||||
ten times larger than the range of rem, the array is skewed to reduce the
|
|
||||||
memory usage, with eight times the range for mem than for rem. See the
|
|
||||||
calculations for offset and bit in beenhere() for the details.
|
|
||||||
|
|
||||||
For the deflate example of 286 symbols limited to 15-bit codes, the bit
|
|
||||||
vectors grow to total approximately 21 MB, in addition to the 4.3 MB done[]
|
|
||||||
array itself.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Globals to avoid propagating constants or constant pointers recursively */
|
|
||||||
local int max; /* maximum allowed bit length for the codes */
|
|
||||||
local int root; /* size of base code table in bits */
|
|
||||||
local int large; /* largest code table so far */
|
|
||||||
local size_t size; /* number of elements in num and done */
|
|
||||||
local int *code; /* number of symbols assigned to each bit length */
|
|
||||||
local big_t *num; /* saved results array for code counting */
|
|
||||||
local struct tab *done; /* states already evaluated array */
|
|
||||||
|
|
||||||
/* Index function for num[] and done[] */
|
|
||||||
#define INDEX(i,j,k) (((size_t)((i-1)>>1)*((i-2)>>1)+(j>>1)-1)*(max-1)+k-1)
|
|
||||||
|
|
||||||
/* Free allocated space. Uses globals code, num, and done. */
|
|
||||||
local void cleanup(void)
|
|
||||||
{
|
|
||||||
size_t n;
|
|
||||||
|
|
||||||
if (done != NULL) {
|
|
||||||
for (n = 0; n < size; n++)
|
|
||||||
if (done[n].len)
|
|
||||||
free(done[n].vec);
|
|
||||||
free(done);
|
|
||||||
}
|
|
||||||
if (num != NULL)
|
|
||||||
free(num);
|
|
||||||
if (code != NULL)
|
|
||||||
free(code);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the number of possible Huffman codes using bit patterns of lengths
|
|
||||||
len through max inclusive, coding syms symbols, with left bit patterns of
|
|
||||||
length len unused -- return -1 if there is an overflow in the counting.
|
|
||||||
Keep a record of previous results in num to prevent repeating the same
|
|
||||||
calculation. Uses the globals max and num. */
|
|
||||||
local big_t count(int syms, int len, int left)
|
|
||||||
{
|
|
||||||
big_t sum; /* number of possible codes from this juncture */
|
|
||||||
big_t got; /* value returned from count() */
|
|
||||||
int least; /* least number of syms to use at this juncture */
|
|
||||||
int most; /* most number of syms to use at this juncture */
|
|
||||||
int use; /* number of bit patterns to use in next call */
|
|
||||||
size_t index; /* index of this case in *num */
|
|
||||||
|
|
||||||
/* see if only one possible code */
|
|
||||||
if (syms == left)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* note and verify the expected state */
|
|
||||||
assert(syms > left && left > 0 && len < max);
|
|
||||||
|
|
||||||
/* see if we've done this one already */
|
|
||||||
index = INDEX(syms, left, len);
|
|
||||||
got = num[index];
|
|
||||||
if (got)
|
|
||||||
return got; /* we have -- return the saved result */
|
|
||||||
|
|
||||||
/* we need to use at least this many bit patterns so that the code won't be
|
|
||||||
incomplete at the next length (more bit patterns than symbols) */
|
|
||||||
least = (left << 1) - syms;
|
|
||||||
if (least < 0)
|
|
||||||
least = 0;
|
|
||||||
|
|
||||||
/* we can use at most this many bit patterns, lest there not be enough
|
|
||||||
available for the remaining symbols at the maximum length (if there were
|
|
||||||
no limit to the code length, this would become: most = left - 1) */
|
|
||||||
most = (((code_t)left << (max - len)) - syms) /
|
|
||||||
(((code_t)1 << (max - len)) - 1);
|
|
||||||
|
|
||||||
/* count all possible codes from this juncture and add them up */
|
|
||||||
sum = 0;
|
|
||||||
for (use = least; use <= most; use++) {
|
|
||||||
got = count(syms - use, len + 1, (left - use) << 1);
|
|
||||||
sum += got;
|
|
||||||
if (got == (big_t)0 - 1 || sum < got) /* overflow */
|
|
||||||
return (big_t)0 - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* verify that all recursive calls are productive */
|
|
||||||
assert(sum != 0);
|
|
||||||
|
|
||||||
/* save the result and return it */
|
|
||||||
num[index] = sum;
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if we've been here before, set to true if not. Set a bit in a
|
|
||||||
bit vector to indicate visiting this state. Each (syms,len,left) state
|
|
||||||
has a variable size bit vector indexed by (mem,rem). The bit vector is
|
|
||||||
lengthened if needed to allow setting the (mem,rem) bit. */
|
|
||||||
local int beenhere(int syms, int len, int left, int mem, int rem)
|
|
||||||
{
|
|
||||||
size_t index; /* index for this state's bit vector */
|
|
||||||
size_t offset; /* offset in this state's bit vector */
|
|
||||||
int bit; /* mask for this state's bit */
|
|
||||||
size_t length; /* length of the bit vector in bytes */
|
|
||||||
char *vector; /* new or enlarged bit vector */
|
|
||||||
|
|
||||||
/* point to vector for (syms,left,len), bit in vector for (mem,rem) */
|
|
||||||
index = INDEX(syms, left, len);
|
|
||||||
mem -= 1 << root;
|
|
||||||
offset = (mem >> 3) + rem;
|
|
||||||
offset = ((offset * (offset + 1)) >> 1) + rem;
|
|
||||||
bit = 1 << (mem & 7);
|
|
||||||
|
|
||||||
/* see if we've been here */
|
|
||||||
length = done[index].len;
|
|
||||||
if (offset < length && (done[index].vec[offset] & bit) != 0)
|
|
||||||
return 1; /* done this! */
|
|
||||||
|
|
||||||
/* we haven't been here before -- set the bit to show we have now */
|
|
||||||
|
|
||||||
/* see if we need to lengthen the vector in order to set the bit */
|
|
||||||
if (length <= offset) {
|
|
||||||
/* if we have one already, enlarge it, zero out the appended space */
|
|
||||||
if (length) {
|
|
||||||
do {
|
|
||||||
length <<= 1;
|
|
||||||
} while (length <= offset);
|
|
||||||
vector = realloc(done[index].vec, length);
|
|
||||||
if (vector != NULL)
|
|
||||||
memset(vector + done[index].len, 0, length - done[index].len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* otherwise we need to make a new vector and zero it out */
|
|
||||||
else {
|
|
||||||
length = 1 << (len - root);
|
|
||||||
while (length <= offset)
|
|
||||||
length <<= 1;
|
|
||||||
vector = calloc(length, sizeof(char));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* in either case, bail if we can't get the memory */
|
|
||||||
if (vector == NULL) {
|
|
||||||
fputs("abort: unable to allocate enough memory\n", stderr);
|
|
||||||
cleanup();
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* install the new vector */
|
|
||||||
done[index].len = length;
|
|
||||||
done[index].vec = vector;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set the bit */
|
|
||||||
done[index].vec[offset] |= bit;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Examine all possible codes from the given node (syms, len, left). Compute
|
|
||||||
the amount of memory required to build inflate's decoding tables, where the
|
|
||||||
number of code structures used so far is mem, and the number remaining in
|
|
||||||
the current sub-table is rem. Uses the globals max, code, root, large, and
|
|
||||||
done. */
|
|
||||||
local void examine(int syms, int len, int left, int mem, int rem)
|
|
||||||
{
|
|
||||||
int least; /* least number of syms to use at this juncture */
|
|
||||||
int most; /* most number of syms to use at this juncture */
|
|
||||||
int use; /* number of bit patterns to use in next call */
|
|
||||||
|
|
||||||
/* see if we have a complete code */
|
|
||||||
if (syms == left) {
|
|
||||||
/* set the last code entry */
|
|
||||||
code[len] = left;
|
|
||||||
|
|
||||||
/* complete computation of memory used by this code */
|
|
||||||
while (rem < left) {
|
|
||||||
left -= rem;
|
|
||||||
rem = 1 << (len - root);
|
|
||||||
mem += rem;
|
|
||||||
}
|
|
||||||
assert(rem == left);
|
|
||||||
|
|
||||||
/* if this is a new maximum, show the entries used and the sub-code */
|
|
||||||
if (mem > large) {
|
|
||||||
large = mem;
|
|
||||||
printf("max %d: ", mem);
|
|
||||||
for (use = root + 1; use <= max; use++)
|
|
||||||
if (code[use])
|
|
||||||
printf("%d[%d] ", code[use], use);
|
|
||||||
putchar('\n');
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove entries as we drop back down in the recursion */
|
|
||||||
code[len] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prune the tree if we can */
|
|
||||||
if (beenhere(syms, len, left, mem, rem))
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* we need to use at least this many bit patterns so that the code won't be
|
|
||||||
incomplete at the next length (more bit patterns than symbols) */
|
|
||||||
least = (left << 1) - syms;
|
|
||||||
if (least < 0)
|
|
||||||
least = 0;
|
|
||||||
|
|
||||||
/* we can use at most this many bit patterns, lest there not be enough
|
|
||||||
available for the remaining symbols at the maximum length (if there were
|
|
||||||
no limit to the code length, this would become: most = left - 1) */
|
|
||||||
most = (((code_t)left << (max - len)) - syms) /
|
|
||||||
(((code_t)1 << (max - len)) - 1);
|
|
||||||
|
|
||||||
/* occupy least table spaces, creating new sub-tables as needed */
|
|
||||||
use = least;
|
|
||||||
while (rem < use) {
|
|
||||||
use -= rem;
|
|
||||||
rem = 1 << (len - root);
|
|
||||||
mem += rem;
|
|
||||||
}
|
|
||||||
rem -= use;
|
|
||||||
|
|
||||||
/* examine codes from here, updating table space as we go */
|
|
||||||
for (use = least; use <= most; use++) {
|
|
||||||
code[len] = use;
|
|
||||||
examine(syms - use, len + 1, (left - use) << 1,
|
|
||||||
mem + (rem ? 1 << (len - root) : 0), rem << 1);
|
|
||||||
if (rem == 0) {
|
|
||||||
rem = 1 << (len - root);
|
|
||||||
mem += rem;
|
|
||||||
}
|
|
||||||
rem--;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* remove entries as we drop back down in the recursion */
|
|
||||||
code[len] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Look at all sub-codes starting with root + 1 bits. Look at only the valid
|
|
||||||
intermediate code states (syms, left, len). For each completed code,
|
|
||||||
calculate the amount of memory required by inflate to build the decoding
|
|
||||||
tables. Find the maximum amount of memory required and show the code that
|
|
||||||
requires that maximum. Uses the globals max, root, and num. */
|
|
||||||
local void enough(int syms)
|
|
||||||
{
|
|
||||||
int n; /* number of remaing symbols for this node */
|
|
||||||
int left; /* number of unused bit patterns at this length */
|
|
||||||
size_t index; /* index of this case in *num */
|
|
||||||
|
|
||||||
/* clear code */
|
|
||||||
for (n = 0; n <= max; n++)
|
|
||||||
code[n] = 0;
|
|
||||||
|
|
||||||
/* look at all (root + 1) bit and longer codes */
|
|
||||||
large = 1 << root; /* base table */
|
|
||||||
if (root < max) /* otherwise, there's only a base table */
|
|
||||||
for (n = 3; n <= syms; n++)
|
|
||||||
for (left = 2; left < n; left += 2)
|
|
||||||
{
|
|
||||||
/* look at all reachable (root + 1) bit nodes, and the
|
|
||||||
resulting codes (complete at root + 2 or more) */
|
|
||||||
index = INDEX(n, left, root + 1);
|
|
||||||
if (root + 1 < max && num[index]) /* reachable node */
|
|
||||||
examine(n, root + 1, left, 1 << root, 0);
|
|
||||||
|
|
||||||
/* also look at root bit codes with completions at root + 1
|
|
||||||
bits (not saved in num, since complete), just in case */
|
|
||||||
if (num[index - 1] && n <= left << 1)
|
|
||||||
examine((n - left) << 1, root + 1, (n - left) << 1,
|
|
||||||
1 << root, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* done */
|
|
||||||
printf("done: maximum of %d table entries\n", large);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Examine and show the total number of possible Huffman codes for a given
|
|
||||||
maximum number of symbols, initial root table size, and maximum code length
|
|
||||||
in bits -- those are the command arguments in that order. The default
|
|
||||||
values are 286, 9, and 15 respectively, for the deflate literal/length code.
|
|
||||||
The possible codes are counted for each number of coded symbols from two to
|
|
||||||
the maximum. The counts for each of those and the total number of codes are
|
|
||||||
shown. The maximum number of inflate table entires is then calculated
|
|
||||||
across all possible codes. Each new maximum number of table entries and the
|
|
||||||
associated sub-code (starting at root + 1 == 10 bits) is shown.
|
|
||||||
|
|
||||||
To count and examine Huffman codes that are not length-limited, provide a
|
|
||||||
maximum length equal to the number of symbols minus one.
|
|
||||||
|
|
||||||
For the deflate literal/length code, use "enough". For the deflate distance
|
|
||||||
code, use "enough 30 6".
|
|
||||||
|
|
||||||
This uses the %llu printf format to print big_t numbers, which assumes that
|
|
||||||
big_t is an unsigned long long. If the big_t type is changed (for example
|
|
||||||
to a multiple precision type), the method of printing will also need to be
|
|
||||||
updated.
|
|
||||||
*/
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int syms; /* total number of symbols to code */
|
|
||||||
int n; /* number of symbols to code for this run */
|
|
||||||
big_t got; /* return value of count() */
|
|
||||||
big_t sum; /* accumulated number of codes over n */
|
|
||||||
code_t word; /* for counting bits in code_t */
|
|
||||||
|
|
||||||
/* set up globals for cleanup() */
|
|
||||||
code = NULL;
|
|
||||||
num = NULL;
|
|
||||||
done = NULL;
|
|
||||||
|
|
||||||
/* get arguments -- default to the deflate literal/length code */
|
|
||||||
syms = 286;
|
|
||||||
root = 9;
|
|
||||||
max = 15;
|
|
||||||
if (argc > 1) {
|
|
||||||
syms = atoi(argv[1]);
|
|
||||||
if (argc > 2) {
|
|
||||||
root = atoi(argv[2]);
|
|
||||||
if (argc > 3)
|
|
||||||
max = atoi(argv[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (argc > 4 || syms < 2 || root < 1 || max < 1) {
|
|
||||||
fputs("invalid arguments, need: [sym >= 2 [root >= 1 [max >= 1]]]\n",
|
|
||||||
stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if not restricting the code length, the longest is syms - 1 */
|
|
||||||
if (max > syms - 1)
|
|
||||||
max = syms - 1;
|
|
||||||
|
|
||||||
/* determine the number of bits in a code_t */
|
|
||||||
for (n = 0, word = 1; word; n++, word <<= 1)
|
|
||||||
;
|
|
||||||
|
|
||||||
/* make sure that the calculation of most will not overflow */
|
|
||||||
if (max > n || (code_t)(syms - 2) >= (((code_t)0 - 1) >> (max - 1))) {
|
|
||||||
fputs("abort: code length too long for internal types\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reject impossible code requests */
|
|
||||||
if ((code_t)(syms - 1) > ((code_t)1 << max) - 1) {
|
|
||||||
fprintf(stderr, "%d symbols cannot be coded in %d bits\n",
|
|
||||||
syms, max);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate code vector */
|
|
||||||
code = calloc(max + 1, sizeof(int));
|
|
||||||
if (code == NULL) {
|
|
||||||
fputs("abort: unable to allocate enough memory\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* determine size of saved results array, checking for overflows,
|
|
||||||
allocate and clear the array (set all to zero with calloc()) */
|
|
||||||
if (syms == 2) /* iff max == 1 */
|
|
||||||
num = NULL; /* won't be saving any results */
|
|
||||||
else {
|
|
||||||
size = syms >> 1;
|
|
||||||
if (size > ((size_t)0 - 1) / (n = (syms - 1) >> 1) ||
|
|
||||||
(size *= n, size > ((size_t)0 - 1) / (n = max - 1)) ||
|
|
||||||
(size *= n, size > ((size_t)0 - 1) / sizeof(big_t)) ||
|
|
||||||
(num = calloc(size, sizeof(big_t))) == NULL) {
|
|
||||||
fputs("abort: unable to allocate enough memory\n", stderr);
|
|
||||||
cleanup();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* count possible codes for all numbers of symbols, add up counts */
|
|
||||||
sum = 0;
|
|
||||||
for (n = 2; n <= syms; n++) {
|
|
||||||
got = count(n, 1, 2);
|
|
||||||
sum += got;
|
|
||||||
if (got == (big_t)0 - 1 || sum < got) { /* overflow */
|
|
||||||
fputs("abort: can't count that high!\n", stderr);
|
|
||||||
cleanup();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("%llu %d-codes\n", got, n);
|
|
||||||
}
|
|
||||||
printf("%llu total codes for 2 to %d symbols", sum, syms);
|
|
||||||
if (max < syms - 1)
|
|
||||||
printf(" (%d-bit length limit)\n", max);
|
|
||||||
else
|
|
||||||
puts(" (no length limit)");
|
|
||||||
|
|
||||||
/* allocate and clear done array for beenhere() */
|
|
||||||
if (syms == 2)
|
|
||||||
done = NULL;
|
|
||||||
else if (size > ((size_t)0 - 1) / sizeof(struct tab) ||
|
|
||||||
(done = calloc(size, sizeof(struct tab))) == NULL) {
|
|
||||||
fputs("abort: unable to allocate enough memory\n", stderr);
|
|
||||||
cleanup();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* find and show maximum inflate table usage */
|
|
||||||
if (root > max) /* reduce root to max length */
|
|
||||||
root = max;
|
|
||||||
if ((code_t)syms < ((code_t)1 << (root + 1)))
|
|
||||||
enough(syms);
|
|
||||||
else
|
|
||||||
puts("cannot handle minimum code lengths > root");
|
|
||||||
|
|
||||||
/* done */
|
|
||||||
cleanup();
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,233 +0,0 @@
|
||||||
/* fitblk.c: example of fitting compressed output to a specified size
|
|
||||||
Not copyrighted -- provided to the public domain
|
|
||||||
Version 1.1 25 November 2004 Mark Adler */
|
|
||||||
|
|
||||||
/* Version history:
|
|
||||||
1.0 24 Nov 2004 First version
|
|
||||||
1.1 25 Nov 2004 Change deflateInit2() to deflateInit()
|
|
||||||
Use fixed-size, stack-allocated raw buffers
|
|
||||||
Simplify code moving compression to subroutines
|
|
||||||
Use assert() for internal errors
|
|
||||||
Add detailed description of approach
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Approach to just fitting a requested compressed size:
|
|
||||||
|
|
||||||
fitblk performs three compression passes on a portion of the input
|
|
||||||
data in order to determine how much of that input will compress to
|
|
||||||
nearly the requested output block size. The first pass generates
|
|
||||||
enough deflate blocks to produce output to fill the requested
|
|
||||||
output size plus a specfied excess amount (see the EXCESS define
|
|
||||||
below). The last deflate block may go quite a bit past that, but
|
|
||||||
is discarded. The second pass decompresses and recompresses just
|
|
||||||
the compressed data that fit in the requested plus excess sized
|
|
||||||
buffer. The deflate process is terminated after that amount of
|
|
||||||
input, which is less than the amount consumed on the first pass.
|
|
||||||
The last deflate block of the result will be of a comparable size
|
|
||||||
to the final product, so that the header for that deflate block and
|
|
||||||
the compression ratio for that block will be about the same as in
|
|
||||||
the final product. The third compression pass decompresses the
|
|
||||||
result of the second step, but only the compressed data up to the
|
|
||||||
requested size minus an amount to allow the compressed stream to
|
|
||||||
complete (see the MARGIN define below). That will result in a
|
|
||||||
final compressed stream whose length is less than or equal to the
|
|
||||||
requested size. Assuming sufficient input and a requested size
|
|
||||||
greater than a few hundred bytes, the shortfall will typically be
|
|
||||||
less than ten bytes.
|
|
||||||
|
|
||||||
If the input is short enough that the first compression completes
|
|
||||||
before filling the requested output size, then that compressed
|
|
||||||
stream is return with no recompression.
|
|
||||||
|
|
||||||
EXCESS is chosen to be just greater than the shortfall seen in a
|
|
||||||
two pass approach similar to the above. That shortfall is due to
|
|
||||||
the last deflate block compressing more efficiently with a smaller
|
|
||||||
header on the second pass. EXCESS is set to be large enough so
|
|
||||||
that there is enough uncompressed data for the second pass to fill
|
|
||||||
out the requested size, and small enough so that the final deflate
|
|
||||||
block of the second pass will be close in size to the final deflate
|
|
||||||
block of the third and final pass. MARGIN is chosen to be just
|
|
||||||
large enough to assure that the final compression has enough room
|
|
||||||
to complete in all cases.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "zlib.h"
|
|
||||||
|
|
||||||
#define local static
|
|
||||||
|
|
||||||
/* print nastygram and leave */
|
|
||||||
local void quit(char *why)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "fitblk abort: %s\n", why);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define RAWLEN 4096 /* intermediate uncompressed buffer size */
|
|
||||||
|
|
||||||
/* compress from file to def until provided buffer is full or end of
|
|
||||||
input reached; return last deflate() return value, or Z_ERRNO if
|
|
||||||
there was read error on the file */
|
|
||||||
local int partcompress(FILE *in, z_streamp def)
|
|
||||||
{
|
|
||||||
int ret, flush;
|
|
||||||
unsigned char raw[RAWLEN];
|
|
||||||
|
|
||||||
flush = Z_NO_FLUSH;
|
|
||||||
do {
|
|
||||||
def->avail_in = fread(raw, 1, RAWLEN, in);
|
|
||||||
if (ferror(in))
|
|
||||||
return Z_ERRNO;
|
|
||||||
def->next_in = raw;
|
|
||||||
if (feof(in))
|
|
||||||
flush = Z_FINISH;
|
|
||||||
ret = deflate(def, flush);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
} while (def->avail_out != 0 && flush == Z_NO_FLUSH);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* recompress from inf's input to def's output; the input for inf and
|
|
||||||
the output for def are set in those structures before calling;
|
|
||||||
return last deflate() return value, or Z_MEM_ERROR if inflate()
|
|
||||||
was not able to allocate enough memory when it needed to */
|
|
||||||
local int recompress(z_streamp inf, z_streamp def)
|
|
||||||
{
|
|
||||||
int ret, flush;
|
|
||||||
unsigned char raw[RAWLEN];
|
|
||||||
|
|
||||||
flush = Z_NO_FLUSH;
|
|
||||||
do {
|
|
||||||
/* decompress */
|
|
||||||
inf->avail_out = RAWLEN;
|
|
||||||
inf->next_out = raw;
|
|
||||||
ret = inflate(inf, Z_NO_FLUSH);
|
|
||||||
assert(ret != Z_STREAM_ERROR && ret != Z_DATA_ERROR &&
|
|
||||||
ret != Z_NEED_DICT);
|
|
||||||
if (ret == Z_MEM_ERROR)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* compress what was decompresed until done or no room */
|
|
||||||
def->avail_in = RAWLEN - inf->avail_out;
|
|
||||||
def->next_in = raw;
|
|
||||||
if (inf->avail_out != 0)
|
|
||||||
flush = Z_FINISH;
|
|
||||||
ret = deflate(def, flush);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
} while (ret != Z_STREAM_END && def->avail_out != 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define EXCESS 256 /* empirically determined stream overage */
|
|
||||||
#define MARGIN 8 /* amount to back off for completion */
|
|
||||||
|
|
||||||
/* compress from stdin to fixed-size block on stdout */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int ret; /* return code */
|
|
||||||
unsigned size; /* requested fixed output block size */
|
|
||||||
unsigned have; /* bytes written by deflate() call */
|
|
||||||
unsigned char *blk; /* intermediate and final stream */
|
|
||||||
unsigned char *tmp; /* close to desired size stream */
|
|
||||||
z_stream def, inf; /* zlib deflate and inflate states */
|
|
||||||
|
|
||||||
/* get requested output size */
|
|
||||||
if (argc != 2)
|
|
||||||
quit("need one argument: size of output block");
|
|
||||||
ret = strtol(argv[1], argv + 1, 10);
|
|
||||||
if (argv[1][0] != 0)
|
|
||||||
quit("argument must be a number");
|
|
||||||
if (ret < 8) /* 8 is minimum zlib stream size */
|
|
||||||
quit("need positive size of 8 or greater");
|
|
||||||
size = (unsigned)ret;
|
|
||||||
|
|
||||||
/* allocate memory for buffers and compression engine */
|
|
||||||
blk = malloc(size + EXCESS);
|
|
||||||
def.zalloc = Z_NULL;
|
|
||||||
def.zfree = Z_NULL;
|
|
||||||
def.opaque = Z_NULL;
|
|
||||||
ret = deflateInit(&def, Z_DEFAULT_COMPRESSION);
|
|
||||||
if (ret != Z_OK || blk == NULL)
|
|
||||||
quit("out of memory");
|
|
||||||
|
|
||||||
/* compress from stdin until output full, or no more input */
|
|
||||||
def.avail_out = size + EXCESS;
|
|
||||||
def.next_out = blk;
|
|
||||||
ret = partcompress(stdin, &def);
|
|
||||||
if (ret == Z_ERRNO)
|
|
||||||
quit("error reading input");
|
|
||||||
|
|
||||||
/* if it all fit, then size was undersubscribed -- done! */
|
|
||||||
if (ret == Z_STREAM_END && def.avail_out >= EXCESS) {
|
|
||||||
/* write block to stdout */
|
|
||||||
have = size + EXCESS - def.avail_out;
|
|
||||||
if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
|
|
||||||
quit("error writing output");
|
|
||||||
|
|
||||||
/* clean up and print results to stderr */
|
|
||||||
ret = deflateEnd(&def);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
free(blk);
|
|
||||||
fprintf(stderr,
|
|
||||||
"%u bytes unused out of %u requested (all input)\n",
|
|
||||||
size - have, size);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* it didn't all fit -- set up for recompression */
|
|
||||||
inf.zalloc = Z_NULL;
|
|
||||||
inf.zfree = Z_NULL;
|
|
||||||
inf.opaque = Z_NULL;
|
|
||||||
inf.avail_in = 0;
|
|
||||||
inf.next_in = Z_NULL;
|
|
||||||
ret = inflateInit(&inf);
|
|
||||||
tmp = malloc(size + EXCESS);
|
|
||||||
if (ret != Z_OK || tmp == NULL)
|
|
||||||
quit("out of memory");
|
|
||||||
ret = deflateReset(&def);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
|
|
||||||
/* do first recompression close to the right amount */
|
|
||||||
inf.avail_in = size + EXCESS;
|
|
||||||
inf.next_in = blk;
|
|
||||||
def.avail_out = size + EXCESS;
|
|
||||||
def.next_out = tmp;
|
|
||||||
ret = recompress(&inf, &def);
|
|
||||||
if (ret == Z_MEM_ERROR)
|
|
||||||
quit("out of memory");
|
|
||||||
|
|
||||||
/* set up for next reocmpression */
|
|
||||||
ret = inflateReset(&inf);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
ret = deflateReset(&def);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
|
|
||||||
/* do second and final recompression (third compression) */
|
|
||||||
inf.avail_in = size - MARGIN; /* assure stream will complete */
|
|
||||||
inf.next_in = tmp;
|
|
||||||
def.avail_out = size;
|
|
||||||
def.next_out = blk;
|
|
||||||
ret = recompress(&inf, &def);
|
|
||||||
if (ret == Z_MEM_ERROR)
|
|
||||||
quit("out of memory");
|
|
||||||
assert(ret == Z_STREAM_END); /* otherwise MARGIN too small */
|
|
||||||
|
|
||||||
/* done -- write block to stdout */
|
|
||||||
have = size - def.avail_out;
|
|
||||||
if (fwrite(blk, 1, have, stdout) != have || ferror(stdout))
|
|
||||||
quit("error writing output");
|
|
||||||
|
|
||||||
/* clean up and print results to stderr */
|
|
||||||
free(tmp);
|
|
||||||
ret = inflateEnd(&inf);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
ret = deflateEnd(&def);
|
|
||||||
assert(ret != Z_STREAM_ERROR);
|
|
||||||
free(blk);
|
|
||||||
fprintf(stderr,
|
|
||||||
"%u bytes unused out of %u requested (%lu input)\n",
|
|
||||||
size - have, size, def.total_in);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,702 +0,0 @@
|
||||||
/* gun.c -- simple gunzip to give an example of the use of inflateBack()
|
|
||||||
* Copyright (C) 2003, 2005, 2008, 2010, 2012 Mark Adler
|
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
|
||||||
Version 1.7 12 August 2012 Mark Adler */
|
|
||||||
|
|
||||||
/* Version history:
|
|
||||||
1.0 16 Feb 2003 First version for testing of inflateBack()
|
|
||||||
1.1 21 Feb 2005 Decompress concatenated gzip streams
|
|
||||||
Remove use of "this" variable (C++ keyword)
|
|
||||||
Fix return value for in()
|
|
||||||
Improve allocation failure checking
|
|
||||||
Add typecasting for void * structures
|
|
||||||
Add -h option for command version and usage
|
|
||||||
Add a bunch of comments
|
|
||||||
1.2 20 Mar 2005 Add Unix compress (LZW) decompression
|
|
||||||
Copy file attributes from input file to output file
|
|
||||||
1.3 12 Jun 2005 Add casts for error messages [Oberhumer]
|
|
||||||
1.4 8 Dec 2006 LZW decompression speed improvements
|
|
||||||
1.5 9 Feb 2008 Avoid warning in latest version of gcc
|
|
||||||
1.6 17 Jan 2010 Avoid signed/unsigned comparison warnings
|
|
||||||
1.7 12 Aug 2012 Update for z_const usage in zlib 1.2.8
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
gun [ -t ] [ name ... ]
|
|
||||||
|
|
||||||
decompresses the data in the named gzip files. If no arguments are given,
|
|
||||||
gun will decompress from stdin to stdout. The names must end in .gz, -gz,
|
|
||||||
.z, -z, _z, or .Z. The uncompressed data will be written to a file name
|
|
||||||
with the suffix stripped. On success, the original file is deleted. On
|
|
||||||
failure, the output file is deleted. For most failures, the command will
|
|
||||||
continue to process the remaining names on the command line. A memory
|
|
||||||
allocation failure will abort the command. If -t is specified, then the
|
|
||||||
listed files or stdin will be tested as gzip files for integrity (without
|
|
||||||
checking for a proper suffix), no output will be written, and no files
|
|
||||||
will be deleted.
|
|
||||||
|
|
||||||
Like gzip, gun allows concatenated gzip streams and will decompress them,
|
|
||||||
writing all of the uncompressed data to the output. Unlike gzip, gun allows
|
|
||||||
an empty file on input, and will produce no error writing an empty output
|
|
||||||
file.
|
|
||||||
|
|
||||||
gun will also decompress files made by Unix compress, which uses LZW
|
|
||||||
compression. These files are automatically detected by virtue of their
|
|
||||||
magic header bytes. Since the end of Unix compress stream is marked by the
|
|
||||||
end-of-file, they cannot be concantenated. If a Unix compress stream is
|
|
||||||
encountered in an input file, it is the last stream in that file.
|
|
||||||
|
|
||||||
Like gunzip and uncompress, the file attributes of the original compressed
|
|
||||||
file are maintained in the final uncompressed file, to the extent that the
|
|
||||||
user permissions allow it.
|
|
||||||
|
|
||||||
On my Mac OS X PowerPC G4, gun is almost twice as fast as gunzip (version
|
|
||||||
1.2.4) is on the same file, when gun is linked with zlib 1.2.2. Also the
|
|
||||||
LZW decompression provided by gun is about twice as fast as the standard
|
|
||||||
Unix uncompress command.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* external functions and related types and constants */
|
|
||||||
#include <stdio.h> /* fprintf() */
|
|
||||||
#include <stdlib.h> /* malloc(), free() */
|
|
||||||
#include <string.h> /* strerror(), strcmp(), strlen(), memcpy() */
|
|
||||||
#include <errno.h> /* errno */
|
|
||||||
#include <fcntl.h> /* open() */
|
|
||||||
#include <unistd.h> /* read(), write(), close(), chown(), unlink() */
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h> /* stat(), chmod() */
|
|
||||||
#include <utime.h> /* utime() */
|
|
||||||
#include "zlib.h" /* inflateBackInit(), inflateBack(), */
|
|
||||||
/* inflateBackEnd(), crc32() */
|
|
||||||
|
|
||||||
/* function declaration */
|
|
||||||
#define local static
|
|
||||||
|
|
||||||
/* buffer constants */
|
|
||||||
#define SIZE 32768U /* input and output buffer sizes */
|
|
||||||
#define PIECE 16384 /* limits i/o chunks for 16-bit int case */
|
|
||||||
|
|
||||||
/* structure for infback() to pass to input function in() -- it maintains the
|
|
||||||
input file and a buffer of size SIZE */
|
|
||||||
struct ind {
|
|
||||||
int infile;
|
|
||||||
unsigned char *inbuf;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Load input buffer, assumed to be empty, and return bytes loaded and a
|
|
||||||
pointer to them. read() is called until the buffer is full, or until it
|
|
||||||
returns end-of-file or error. Return 0 on error. */
|
|
||||||
local unsigned in(void *in_desc, z_const unsigned char **buf)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned len;
|
|
||||||
unsigned char *next;
|
|
||||||
struct ind *me = (struct ind *)in_desc;
|
|
||||||
|
|
||||||
next = me->inbuf;
|
|
||||||
*buf = next;
|
|
||||||
len = 0;
|
|
||||||
do {
|
|
||||||
ret = PIECE;
|
|
||||||
if ((unsigned)ret > SIZE - len)
|
|
||||||
ret = (int)(SIZE - len);
|
|
||||||
ret = (int)read(me->infile, next, ret);
|
|
||||||
if (ret == -1) {
|
|
||||||
len = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
next += ret;
|
|
||||||
len += ret;
|
|
||||||
} while (ret != 0 && len < SIZE);
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* structure for infback() to pass to output function out() -- it maintains the
|
|
||||||
output file, a running CRC-32 check on the output and the total number of
|
|
||||||
bytes output, both for checking against the gzip trailer. (The length in
|
|
||||||
the gzip trailer is stored modulo 2^32, so it's ok if a long is 32 bits and
|
|
||||||
the output is greater than 4 GB.) */
|
|
||||||
struct outd {
|
|
||||||
int outfile;
|
|
||||||
int check; /* true if checking crc and total */
|
|
||||||
unsigned long crc;
|
|
||||||
unsigned long total;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Write output buffer and update the CRC-32 and total bytes written. write()
|
|
||||||
is called until all of the output is written or an error is encountered.
|
|
||||||
On success out() returns 0. For a write failure, out() returns 1. If the
|
|
||||||
output file descriptor is -1, then nothing is written.
|
|
||||||
*/
|
|
||||||
local int out(void *out_desc, unsigned char *buf, unsigned len)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
struct outd *me = (struct outd *)out_desc;
|
|
||||||
|
|
||||||
if (me->check) {
|
|
||||||
me->crc = crc32(me->crc, buf, len);
|
|
||||||
me->total += len;
|
|
||||||
}
|
|
||||||
if (me->outfile != -1)
|
|
||||||
do {
|
|
||||||
ret = PIECE;
|
|
||||||
if ((unsigned)ret > len)
|
|
||||||
ret = (int)len;
|
|
||||||
ret = (int)write(me->outfile, buf, ret);
|
|
||||||
if (ret == -1)
|
|
||||||
return 1;
|
|
||||||
buf += ret;
|
|
||||||
len -= ret;
|
|
||||||
} while (len != 0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* next input byte macro for use inside lunpipe() and gunpipe() */
|
|
||||||
#define NEXT() (have ? 0 : (have = in(indp, &next)), \
|
|
||||||
last = have ? (have--, (int)(*next++)) : -1)
|
|
||||||
|
|
||||||
/* memory for gunpipe() and lunpipe() --
|
|
||||||
the first 256 entries of prefix[] and suffix[] are never used, could
|
|
||||||
have offset the index, but it's faster to waste the memory */
|
|
||||||
unsigned char inbuf[SIZE]; /* input buffer */
|
|
||||||
unsigned char outbuf[SIZE]; /* output buffer */
|
|
||||||
unsigned short prefix[65536]; /* index to LZW prefix string */
|
|
||||||
unsigned char suffix[65536]; /* one-character LZW suffix */
|
|
||||||
unsigned char match[65280 + 2]; /* buffer for reversed match or gzip
|
|
||||||
32K sliding window */
|
|
||||||
|
|
||||||
/* throw out what's left in the current bits byte buffer (this is a vestigial
|
|
||||||
aspect of the compressed data format derived from an implementation that
|
|
||||||
made use of a special VAX machine instruction!) */
|
|
||||||
#define FLUSHCODE() \
|
|
||||||
do { \
|
|
||||||
left = 0; \
|
|
||||||
rem = 0; \
|
|
||||||
if (chunk > have) { \
|
|
||||||
chunk -= have; \
|
|
||||||
have = 0; \
|
|
||||||
if (NEXT() == -1) \
|
|
||||||
break; \
|
|
||||||
chunk--; \
|
|
||||||
if (chunk > have) { \
|
|
||||||
chunk = have = 0; \
|
|
||||||
break; \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
have -= chunk; \
|
|
||||||
next += chunk; \
|
|
||||||
chunk = 0; \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
/* Decompress a compress (LZW) file from indp to outfile. The compress magic
|
|
||||||
header (two bytes) has already been read and verified. There are have bytes
|
|
||||||
of buffered input at next. strm is used for passing error information back
|
|
||||||
to gunpipe().
|
|
||||||
|
|
||||||
lunpipe() will return Z_OK on success, Z_BUF_ERROR for an unexpected end of
|
|
||||||
file, read error, or write error (a write error indicated by strm->next_in
|
|
||||||
not equal to Z_NULL), or Z_DATA_ERROR for invalid input.
|
|
||||||
*/
|
|
||||||
local int lunpipe(unsigned have, z_const unsigned char *next, struct ind *indp,
|
|
||||||
int outfile, z_stream *strm)
|
|
||||||
{
|
|
||||||
int last; /* last byte read by NEXT(), or -1 if EOF */
|
|
||||||
unsigned chunk; /* bytes left in current chunk */
|
|
||||||
int left; /* bits left in rem */
|
|
||||||
unsigned rem; /* unused bits from input */
|
|
||||||
int bits; /* current bits per code */
|
|
||||||
unsigned code; /* code, table traversal index */
|
|
||||||
unsigned mask; /* mask for current bits codes */
|
|
||||||
int max; /* maximum bits per code for this stream */
|
|
||||||
unsigned flags; /* compress flags, then block compress flag */
|
|
||||||
unsigned end; /* last valid entry in prefix/suffix tables */
|
|
||||||
unsigned temp; /* current code */
|
|
||||||
unsigned prev; /* previous code */
|
|
||||||
unsigned final; /* last character written for previous code */
|
|
||||||
unsigned stack; /* next position for reversed string */
|
|
||||||
unsigned outcnt; /* bytes in output buffer */
|
|
||||||
struct outd outd; /* output structure */
|
|
||||||
unsigned char *p;
|
|
||||||
|
|
||||||
/* set up output */
|
|
||||||
outd.outfile = outfile;
|
|
||||||
outd.check = 0;
|
|
||||||
|
|
||||||
/* process remainder of compress header -- a flags byte */
|
|
||||||
flags = NEXT();
|
|
||||||
if (last == -1)
|
|
||||||
return Z_BUF_ERROR;
|
|
||||||
if (flags & 0x60) {
|
|
||||||
strm->msg = (char *)"unknown lzw flags set";
|
|
||||||
return Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
max = flags & 0x1f;
|
|
||||||
if (max < 9 || max > 16) {
|
|
||||||
strm->msg = (char *)"lzw bits out of range";
|
|
||||||
return Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
if (max == 9) /* 9 doesn't really mean 9 */
|
|
||||||
max = 10;
|
|
||||||
flags &= 0x80; /* true if block compress */
|
|
||||||
|
|
||||||
/* clear table */
|
|
||||||
bits = 9;
|
|
||||||
mask = 0x1ff;
|
|
||||||
end = flags ? 256 : 255;
|
|
||||||
|
|
||||||
/* set up: get first 9-bit code, which is the first decompressed byte, but
|
|
||||||
don't create a table entry until the next code */
|
|
||||||
if (NEXT() == -1) /* no compressed data is ok */
|
|
||||||
return Z_OK;
|
|
||||||
final = prev = (unsigned)last; /* low 8 bits of code */
|
|
||||||
if (NEXT() == -1) /* missing a bit */
|
|
||||||
return Z_BUF_ERROR;
|
|
||||||
if (last & 1) { /* code must be < 256 */
|
|
||||||
strm->msg = (char *)"invalid lzw code";
|
|
||||||
return Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
rem = (unsigned)last >> 1; /* remaining 7 bits */
|
|
||||||
left = 7;
|
|
||||||
chunk = bits - 2; /* 7 bytes left in this chunk */
|
|
||||||
outbuf[0] = (unsigned char)final; /* write first decompressed byte */
|
|
||||||
outcnt = 1;
|
|
||||||
|
|
||||||
/* decode codes */
|
|
||||||
stack = 0;
|
|
||||||
for (;;) {
|
|
||||||
/* if the table will be full after this, increment the code size */
|
|
||||||
if (end >= mask && bits < max) {
|
|
||||||
FLUSHCODE();
|
|
||||||
bits++;
|
|
||||||
mask <<= 1;
|
|
||||||
mask++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get a code of length bits */
|
|
||||||
if (chunk == 0) /* decrement chunk modulo bits */
|
|
||||||
chunk = bits;
|
|
||||||
code = rem; /* low bits of code */
|
|
||||||
if (NEXT() == -1) { /* EOF is end of compressed data */
|
|
||||||
/* write remaining buffered output */
|
|
||||||
if (outcnt && out(&outd, outbuf, outcnt)) {
|
|
||||||
strm->next_in = outbuf; /* signal write error */
|
|
||||||
return Z_BUF_ERROR;
|
|
||||||
}
|
|
||||||
return Z_OK;
|
|
||||||
}
|
|
||||||
code += (unsigned)last << left; /* middle (or high) bits of code */
|
|
||||||
left += 8;
|
|
||||||
chunk--;
|
|
||||||
if (bits > left) { /* need more bits */
|
|
||||||
if (NEXT() == -1) /* can't end in middle of code */
|
|
||||||
return Z_BUF_ERROR;
|
|
||||||
code += (unsigned)last << left; /* high bits of code */
|
|
||||||
left += 8;
|
|
||||||
chunk--;
|
|
||||||
}
|
|
||||||
code &= mask; /* mask to current code length */
|
|
||||||
left -= bits; /* number of unused bits */
|
|
||||||
rem = (unsigned)last >> (8 - left); /* unused bits from last byte */
|
|
||||||
|
|
||||||
/* process clear code (256) */
|
|
||||||
if (code == 256 && flags) {
|
|
||||||
FLUSHCODE();
|
|
||||||
bits = 9; /* initialize bits and mask */
|
|
||||||
mask = 0x1ff;
|
|
||||||
end = 255; /* empty table */
|
|
||||||
continue; /* get next code */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* special code to reuse last match */
|
|
||||||
temp = code; /* save the current code */
|
|
||||||
if (code > end) {
|
|
||||||
/* Be picky on the allowed code here, and make sure that the code
|
|
||||||
we drop through (prev) will be a valid index so that random
|
|
||||||
input does not cause an exception. The code != end + 1 check is
|
|
||||||
empirically derived, and not checked in the original uncompress
|
|
||||||
code. If this ever causes a problem, that check could be safely
|
|
||||||
removed. Leaving this check in greatly improves gun's ability
|
|
||||||
to detect random or corrupted input after a compress header.
|
|
||||||
In any case, the prev > end check must be retained. */
|
|
||||||
if (code != end + 1 || prev > end) {
|
|
||||||
strm->msg = (char *)"invalid lzw code";
|
|
||||||
return Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
match[stack++] = (unsigned char)final;
|
|
||||||
code = prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* walk through linked list to generate output in reverse order */
|
|
||||||
p = match + stack;
|
|
||||||
while (code >= 256) {
|
|
||||||
*p++ = suffix[code];
|
|
||||||
code = prefix[code];
|
|
||||||
}
|
|
||||||
stack = p - match;
|
|
||||||
match[stack++] = (unsigned char)code;
|
|
||||||
final = code;
|
|
||||||
|
|
||||||
/* link new table entry */
|
|
||||||
if (end < mask) {
|
|
||||||
end++;
|
|
||||||
prefix[end] = (unsigned short)prev;
|
|
||||||
suffix[end] = (unsigned char)final;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set previous code for next iteration */
|
|
||||||
prev = temp;
|
|
||||||
|
|
||||||
/* write output in forward order */
|
|
||||||
while (stack > SIZE - outcnt) {
|
|
||||||
while (outcnt < SIZE)
|
|
||||||
outbuf[outcnt++] = match[--stack];
|
|
||||||
if (out(&outd, outbuf, outcnt)) {
|
|
||||||
strm->next_in = outbuf; /* signal write error */
|
|
||||||
return Z_BUF_ERROR;
|
|
||||||
}
|
|
||||||
outcnt = 0;
|
|
||||||
}
|
|
||||||
p = match + stack;
|
|
||||||
do {
|
|
||||||
outbuf[outcnt++] = *--p;
|
|
||||||
} while (p > match);
|
|
||||||
stack = 0;
|
|
||||||
|
|
||||||
/* loop for next code with final and prev as the last match, rem and
|
|
||||||
left provide the first 0..7 bits of the next code, end is the last
|
|
||||||
valid table entry */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decompress a gzip file from infile to outfile. strm is assumed to have been
|
|
||||||
successfully initialized with inflateBackInit(). The input file may consist
|
|
||||||
of a series of gzip streams, in which case all of them will be decompressed
|
|
||||||
to the output file. If outfile is -1, then the gzip stream(s) integrity is
|
|
||||||
checked and nothing is written.
|
|
||||||
|
|
||||||
The return value is a zlib error code: Z_MEM_ERROR if out of memory,
|
|
||||||
Z_DATA_ERROR if the header or the compressed data is invalid, or if the
|
|
||||||
trailer CRC-32 check or length doesn't match, Z_BUF_ERROR if the input ends
|
|
||||||
prematurely or a write error occurs, or Z_ERRNO if junk (not a another gzip
|
|
||||||
stream) follows a valid gzip stream.
|
|
||||||
*/
|
|
||||||
local int gunpipe(z_stream *strm, int infile, int outfile)
|
|
||||||
{
|
|
||||||
int ret, first, last;
|
|
||||||
unsigned have, flags, len;
|
|
||||||
z_const unsigned char *next = NULL;
|
|
||||||
struct ind ind, *indp;
|
|
||||||
struct outd outd;
|
|
||||||
|
|
||||||
/* setup input buffer */
|
|
||||||
ind.infile = infile;
|
|
||||||
ind.inbuf = inbuf;
|
|
||||||
indp = &ind;
|
|
||||||
|
|
||||||
/* decompress concatenated gzip streams */
|
|
||||||
have = 0; /* no input data read in yet */
|
|
||||||
first = 1; /* looking for first gzip header */
|
|
||||||
strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
|
|
||||||
for (;;) {
|
|
||||||
/* look for the two magic header bytes for a gzip stream */
|
|
||||||
if (NEXT() == -1) {
|
|
||||||
ret = Z_OK;
|
|
||||||
break; /* empty gzip stream is ok */
|
|
||||||
}
|
|
||||||
if (last != 31 || (NEXT() != 139 && last != 157)) {
|
|
||||||
strm->msg = (char *)"incorrect header check";
|
|
||||||
ret = first ? Z_DATA_ERROR : Z_ERRNO;
|
|
||||||
break; /* not a gzip or compress header */
|
|
||||||
}
|
|
||||||
first = 0; /* next non-header is junk */
|
|
||||||
|
|
||||||
/* process a compress (LZW) file -- can't be concatenated after this */
|
|
||||||
if (last == 157) {
|
|
||||||
ret = lunpipe(have, next, indp, outfile, strm);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process remainder of gzip header */
|
|
||||||
ret = Z_BUF_ERROR;
|
|
||||||
if (NEXT() != 8) { /* only deflate method allowed */
|
|
||||||
if (last == -1) break;
|
|
||||||
strm->msg = (char *)"unknown compression method";
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
flags = NEXT(); /* header flags */
|
|
||||||
NEXT(); /* discard mod time, xflgs, os */
|
|
||||||
NEXT();
|
|
||||||
NEXT();
|
|
||||||
NEXT();
|
|
||||||
NEXT();
|
|
||||||
NEXT();
|
|
||||||
if (last == -1) break;
|
|
||||||
if (flags & 0xe0) {
|
|
||||||
strm->msg = (char *)"unknown header flags set";
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (flags & 4) { /* extra field */
|
|
||||||
len = NEXT();
|
|
||||||
len += (unsigned)(NEXT()) << 8;
|
|
||||||
if (last == -1) break;
|
|
||||||
while (len > have) {
|
|
||||||
len -= have;
|
|
||||||
have = 0;
|
|
||||||
if (NEXT() == -1) break;
|
|
||||||
len--;
|
|
||||||
}
|
|
||||||
if (last == -1) break;
|
|
||||||
have -= len;
|
|
||||||
next += len;
|
|
||||||
}
|
|
||||||
if (flags & 8) /* file name */
|
|
||||||
while (NEXT() != 0 && last != -1)
|
|
||||||
;
|
|
||||||
if (flags & 16) /* comment */
|
|
||||||
while (NEXT() != 0 && last != -1)
|
|
||||||
;
|
|
||||||
if (flags & 2) { /* header crc */
|
|
||||||
NEXT();
|
|
||||||
NEXT();
|
|
||||||
}
|
|
||||||
if (last == -1) break;
|
|
||||||
|
|
||||||
/* set up output */
|
|
||||||
outd.outfile = outfile;
|
|
||||||
outd.check = 1;
|
|
||||||
outd.crc = crc32(0L, Z_NULL, 0);
|
|
||||||
outd.total = 0;
|
|
||||||
|
|
||||||
/* decompress data to output */
|
|
||||||
strm->next_in = next;
|
|
||||||
strm->avail_in = have;
|
|
||||||
ret = inflateBack(strm, in, indp, out, &outd);
|
|
||||||
if (ret != Z_STREAM_END) break;
|
|
||||||
next = strm->next_in;
|
|
||||||
have = strm->avail_in;
|
|
||||||
strm->next_in = Z_NULL; /* so Z_BUF_ERROR means EOF */
|
|
||||||
|
|
||||||
/* check trailer */
|
|
||||||
ret = Z_BUF_ERROR;
|
|
||||||
if (NEXT() != (int)(outd.crc & 0xff) ||
|
|
||||||
NEXT() != (int)((outd.crc >> 8) & 0xff) ||
|
|
||||||
NEXT() != (int)((outd.crc >> 16) & 0xff) ||
|
|
||||||
NEXT() != (int)((outd.crc >> 24) & 0xff)) {
|
|
||||||
/* crc error */
|
|
||||||
if (last != -1) {
|
|
||||||
strm->msg = (char *)"incorrect data check";
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (NEXT() != (int)(outd.total & 0xff) ||
|
|
||||||
NEXT() != (int)((outd.total >> 8) & 0xff) ||
|
|
||||||
NEXT() != (int)((outd.total >> 16) & 0xff) ||
|
|
||||||
NEXT() != (int)((outd.total >> 24) & 0xff)) {
|
|
||||||
/* length error */
|
|
||||||
if (last != -1) {
|
|
||||||
strm->msg = (char *)"incorrect length check";
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* go back and look for another gzip stream */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy file attributes, from -> to, as best we can. This is best effort, so
|
|
||||||
no errors are reported. The mode bits, including suid, sgid, and the sticky
|
|
||||||
bit are copied (if allowed), the owner's user id and group id are copied
|
|
||||||
(again if allowed), and the access and modify times are copied. */
|
|
||||||
local void copymeta(char *from, char *to)
|
|
||||||
{
|
|
||||||
struct stat was;
|
|
||||||
struct utimbuf when;
|
|
||||||
|
|
||||||
/* get all of from's Unix meta data, return if not a regular file */
|
|
||||||
if (stat(from, &was) != 0 || (was.st_mode & S_IFMT) != S_IFREG)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* set to's mode bits, ignore errors */
|
|
||||||
(void)chmod(to, was.st_mode & 07777);
|
|
||||||
|
|
||||||
/* copy owner's user and group, ignore errors */
|
|
||||||
(void)chown(to, was.st_uid, was.st_gid);
|
|
||||||
|
|
||||||
/* copy access and modify times, ignore errors */
|
|
||||||
when.actime = was.st_atime;
|
|
||||||
when.modtime = was.st_mtime;
|
|
||||||
(void)utime(to, &when);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decompress the file inname to the file outnname, of if test is true, just
|
|
||||||
decompress without writing and check the gzip trailer for integrity. If
|
|
||||||
inname is NULL or an empty string, read from stdin. If outname is NULL or
|
|
||||||
an empty string, write to stdout. strm is a pre-initialized inflateBack
|
|
||||||
structure. When appropriate, copy the file attributes from inname to
|
|
||||||
outname.
|
|
||||||
|
|
||||||
gunzip() returns 1 if there is an out-of-memory error or an unexpected
|
|
||||||
return code from gunpipe(). Otherwise it returns 0.
|
|
||||||
*/
|
|
||||||
local int gunzip(z_stream *strm, char *inname, char *outname, int test)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int infile, outfile;
|
|
||||||
|
|
||||||
/* open files */
|
|
||||||
if (inname == NULL || *inname == 0) {
|
|
||||||
inname = "-";
|
|
||||||
infile = 0; /* stdin */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
infile = open(inname, O_RDONLY, 0);
|
|
||||||
if (infile == -1) {
|
|
||||||
fprintf(stderr, "gun cannot open %s\n", inname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (test)
|
|
||||||
outfile = -1;
|
|
||||||
else if (outname == NULL || *outname == 0) {
|
|
||||||
outname = "-";
|
|
||||||
outfile = 1; /* stdout */
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
outfile = open(outname, O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
|
||||||
if (outfile == -1) {
|
|
||||||
close(infile);
|
|
||||||
fprintf(stderr, "gun cannot create %s\n", outname);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
/* decompress */
|
|
||||||
ret = gunpipe(strm, infile, outfile);
|
|
||||||
if (outfile > 2) close(outfile);
|
|
||||||
if (infile > 2) close(infile);
|
|
||||||
|
|
||||||
/* interpret result */
|
|
||||||
switch (ret) {
|
|
||||||
case Z_OK:
|
|
||||||
case Z_ERRNO:
|
|
||||||
if (infile > 2 && outfile > 2) {
|
|
||||||
copymeta(inname, outname); /* copy attributes */
|
|
||||||
unlink(inname);
|
|
||||||
}
|
|
||||||
if (ret == Z_ERRNO)
|
|
||||||
fprintf(stderr, "gun warning: trailing garbage ignored in %s\n",
|
|
||||||
inname);
|
|
||||||
break;
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
if (outfile > 2) unlink(outname);
|
|
||||||
fprintf(stderr, "gun data error on %s: %s\n", inname, strm->msg);
|
|
||||||
break;
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
if (outfile > 2) unlink(outname);
|
|
||||||
fprintf(stderr, "gun out of memory error--aborting\n");
|
|
||||||
return 1;
|
|
||||||
case Z_BUF_ERROR:
|
|
||||||
if (outfile > 2) unlink(outname);
|
|
||||||
if (strm->next_in != Z_NULL) {
|
|
||||||
fprintf(stderr, "gun write error on %s: %s\n",
|
|
||||||
outname, strerror(errno));
|
|
||||||
}
|
|
||||||
else if (errno) {
|
|
||||||
fprintf(stderr, "gun read error on %s: %s\n",
|
|
||||||
inname, strerror(errno));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "gun unexpected end of file on %s\n",
|
|
||||||
inname);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (outfile > 2) unlink(outname);
|
|
||||||
fprintf(stderr, "gun internal error--aborting\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Process the gun command line arguments. See the command syntax near the
|
|
||||||
beginning of this source file. */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int ret, len, test;
|
|
||||||
char *outname;
|
|
||||||
unsigned char *window;
|
|
||||||
z_stream strm;
|
|
||||||
|
|
||||||
/* initialize inflateBack state for repeated use */
|
|
||||||
window = match; /* reuse LZW match buffer */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
ret = inflateBackInit(&strm, 15, window);
|
|
||||||
if (ret != Z_OK) {
|
|
||||||
fprintf(stderr, "gun out of memory error--aborting\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decompress each file to the same name with the suffix removed */
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
test = 0;
|
|
||||||
if (argc && strcmp(*argv, "-h") == 0) {
|
|
||||||
fprintf(stderr, "gun 1.6 (17 Jan 2010)\n");
|
|
||||||
fprintf(stderr, "Copyright (C) 2003-2010 Mark Adler\n");
|
|
||||||
fprintf(stderr, "usage: gun [-t] [file1.gz [file2.Z ...]]\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (argc && strcmp(*argv, "-t") == 0) {
|
|
||||||
test = 1;
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
}
|
|
||||||
if (argc)
|
|
||||||
do {
|
|
||||||
if (test)
|
|
||||||
outname = NULL;
|
|
||||||
else {
|
|
||||||
len = (int)strlen(*argv);
|
|
||||||
if (strcmp(*argv + len - 3, ".gz") == 0 ||
|
|
||||||
strcmp(*argv + len - 3, "-gz") == 0)
|
|
||||||
len -= 3;
|
|
||||||
else if (strcmp(*argv + len - 2, ".z") == 0 ||
|
|
||||||
strcmp(*argv + len - 2, "-z") == 0 ||
|
|
||||||
strcmp(*argv + len - 2, "_z") == 0 ||
|
|
||||||
strcmp(*argv + len - 2, ".Z") == 0)
|
|
||||||
len -= 2;
|
|
||||||
else {
|
|
||||||
fprintf(stderr, "gun error: no gz type on %s--skipping\n",
|
|
||||||
*argv);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
outname = malloc(len + 1);
|
|
||||||
if (outname == NULL) {
|
|
||||||
fprintf(stderr, "gun out of memory error--aborting\n");
|
|
||||||
ret = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
memcpy(outname, *argv, len);
|
|
||||||
outname[len] = 0;
|
|
||||||
}
|
|
||||||
ret = gunzip(&strm, *argv, outname, test);
|
|
||||||
if (outname != NULL) free(outname);
|
|
||||||
if (ret) break;
|
|
||||||
} while (argv++, --argc);
|
|
||||||
else
|
|
||||||
ret = gunzip(&strm, NULL, NULL, test);
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
inflateBackEnd(&strm);
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -1,504 +0,0 @@
|
||||||
/* gzappend -- command to append to a gzip file
|
|
||||||
|
|
||||||
Copyright (C) 2003, 2012 Mark Adler, all rights reserved
|
|
||||||
version 1.2, 11 Oct 2012
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the author be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
Mark Adler madler@alumni.caltech.edu
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Change history:
|
|
||||||
*
|
|
||||||
* 1.0 19 Oct 2003 - First version
|
|
||||||
* 1.1 4 Nov 2003 - Expand and clarify some comments and notes
|
|
||||||
* - Add version and copyright to help
|
|
||||||
* - Send help to stdout instead of stderr
|
|
||||||
* - Add some preemptive typecasts
|
|
||||||
* - Add L to constants in lseek() calls
|
|
||||||
* - Remove some debugging information in error messages
|
|
||||||
* - Use new data_type definition for zlib 1.2.1
|
|
||||||
* - Simplfy and unify file operations
|
|
||||||
* - Finish off gzip file in gztack()
|
|
||||||
* - Use deflatePrime() instead of adding empty blocks
|
|
||||||
* - Keep gzip file clean on appended file read errors
|
|
||||||
* - Use in-place rotate instead of auxiliary buffer
|
|
||||||
* (Why you ask? Because it was fun to write!)
|
|
||||||
* 1.2 11 Oct 2012 - Fix for proper z_const usage
|
|
||||||
* - Check for input buffer malloc failure
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
gzappend takes a gzip file and appends to it, compressing files from the
|
|
||||||
command line or data from stdin. The gzip file is written to directly, to
|
|
||||||
avoid copying that file, in case it's large. Note that this results in the
|
|
||||||
unfriendly behavior that if gzappend fails, the gzip file is corrupted.
|
|
||||||
|
|
||||||
This program was written to illustrate the use of the new Z_BLOCK option of
|
|
||||||
zlib 1.2.x's inflate() function. This option returns from inflate() at each
|
|
||||||
block boundary to facilitate locating and modifying the last block bit at
|
|
||||||
the start of the final deflate block. Also whether using Z_BLOCK or not,
|
|
||||||
another required feature of zlib 1.2.x is that inflate() now provides the
|
|
||||||
number of unusued bits in the last input byte used. gzappend will not work
|
|
||||||
with versions of zlib earlier than 1.2.1.
|
|
||||||
|
|
||||||
gzappend first decompresses the gzip file internally, discarding all but
|
|
||||||
the last 32K of uncompressed data, and noting the location of the last block
|
|
||||||
bit and the number of unused bits in the last byte of the compressed data.
|
|
||||||
The gzip trailer containing the CRC-32 and length of the uncompressed data
|
|
||||||
is verified. This trailer will be later overwritten.
|
|
||||||
|
|
||||||
Then the last block bit is cleared by seeking back in the file and rewriting
|
|
||||||
the byte that contains it. Seeking forward, the last byte of the compressed
|
|
||||||
data is saved along with the number of unused bits to initialize deflate.
|
|
||||||
|
|
||||||
A deflate process is initialized, using the last 32K of the uncompressed
|
|
||||||
data from the gzip file to initialize the dictionary. If the total
|
|
||||||
uncompressed data was less than 32K, then all of it is used to initialize
|
|
||||||
the dictionary. The deflate output bit buffer is also initialized with the
|
|
||||||
last bits from the original deflate stream. From here on, the data to
|
|
||||||
append is simply compressed using deflate, and written to the gzip file.
|
|
||||||
When that is complete, the new CRC-32 and uncompressed length are written
|
|
||||||
as the trailer of the gzip file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "zlib.h"
|
|
||||||
|
|
||||||
#define local static
|
|
||||||
#define LGCHUNK 14
|
|
||||||
#define CHUNK (1U << LGCHUNK)
|
|
||||||
#define DSIZE 32768U
|
|
||||||
|
|
||||||
/* print an error message and terminate with extreme prejudice */
|
|
||||||
local void bye(char *msg1, char *msg2)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "gzappend error: %s%s\n", msg1, msg2);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return the greatest common divisor of a and b using Euclid's algorithm,
|
|
||||||
modified to be fast when one argument much greater than the other, and
|
|
||||||
coded to avoid unnecessary swapping */
|
|
||||||
local unsigned gcd(unsigned a, unsigned b)
|
|
||||||
{
|
|
||||||
unsigned c;
|
|
||||||
|
|
||||||
while (a && b)
|
|
||||||
if (a > b) {
|
|
||||||
c = b;
|
|
||||||
while (a - c >= c)
|
|
||||||
c <<= 1;
|
|
||||||
a -= c;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
c = a;
|
|
||||||
while (b - c >= c)
|
|
||||||
c <<= 1;
|
|
||||||
b -= c;
|
|
||||||
}
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* rotate list[0..len-1] left by rot positions, in place */
|
|
||||||
local void rotate(unsigned char *list, unsigned len, unsigned rot)
|
|
||||||
{
|
|
||||||
unsigned char tmp;
|
|
||||||
unsigned cycles;
|
|
||||||
unsigned char *start, *last, *to, *from;
|
|
||||||
|
|
||||||
/* normalize rot and handle degenerate cases */
|
|
||||||
if (len < 2) return;
|
|
||||||
if (rot >= len) rot %= len;
|
|
||||||
if (rot == 0) return;
|
|
||||||
|
|
||||||
/* pointer to last entry in list */
|
|
||||||
last = list + (len - 1);
|
|
||||||
|
|
||||||
/* do simple left shift by one */
|
|
||||||
if (rot == 1) {
|
|
||||||
tmp = *list;
|
|
||||||
memcpy(list, list + 1, len - 1);
|
|
||||||
*last = tmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do simple right shift by one */
|
|
||||||
if (rot == len - 1) {
|
|
||||||
tmp = *last;
|
|
||||||
memmove(list + 1, list, len - 1);
|
|
||||||
*list = tmp;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* otherwise do rotate as a set of cycles in place */
|
|
||||||
cycles = gcd(len, rot); /* number of cycles */
|
|
||||||
do {
|
|
||||||
start = from = list + cycles; /* start index is arbitrary */
|
|
||||||
tmp = *from; /* save entry to be overwritten */
|
|
||||||
for (;;) {
|
|
||||||
to = from; /* next step in cycle */
|
|
||||||
from += rot; /* go right rot positions */
|
|
||||||
if (from > last) from -= len; /* (pointer better not wrap) */
|
|
||||||
if (from == start) break; /* all but one shifted */
|
|
||||||
*to = *from; /* shift left */
|
|
||||||
}
|
|
||||||
*to = tmp; /* complete the circle */
|
|
||||||
} while (--cycles);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* structure for gzip file read operations */
|
|
||||||
typedef struct {
|
|
||||||
int fd; /* file descriptor */
|
|
||||||
int size; /* 1 << size is bytes in buf */
|
|
||||||
unsigned left; /* bytes available at next */
|
|
||||||
unsigned char *buf; /* buffer */
|
|
||||||
z_const unsigned char *next; /* next byte in buffer */
|
|
||||||
char *name; /* file name for error messages */
|
|
||||||
} file;
|
|
||||||
|
|
||||||
/* reload buffer */
|
|
||||||
local int readin(file *in)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
|
|
||||||
len = read(in->fd, in->buf, 1 << in->size);
|
|
||||||
if (len == -1) bye("error reading ", in->name);
|
|
||||||
in->left = (unsigned)len;
|
|
||||||
in->next = in->buf;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read from file in, exit if end-of-file */
|
|
||||||
local int readmore(file *in)
|
|
||||||
{
|
|
||||||
if (readin(in) == 0) bye("unexpected end of ", in->name);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define read1(in) (in->left == 0 ? readmore(in) : 0, \
|
|
||||||
in->left--, *(in->next)++)
|
|
||||||
|
|
||||||
/* skip over n bytes of in */
|
|
||||||
local void skip(file *in, unsigned n)
|
|
||||||
{
|
|
||||||
unsigned bypass;
|
|
||||||
|
|
||||||
if (n > in->left) {
|
|
||||||
n -= in->left;
|
|
||||||
bypass = n & ~((1U << in->size) - 1);
|
|
||||||
if (bypass) {
|
|
||||||
if (lseek(in->fd, (off_t)bypass, SEEK_CUR) == -1)
|
|
||||||
bye("seeking ", in->name);
|
|
||||||
n -= bypass;
|
|
||||||
}
|
|
||||||
readmore(in);
|
|
||||||
if (n > in->left)
|
|
||||||
bye("unexpected end of ", in->name);
|
|
||||||
}
|
|
||||||
in->left -= n;
|
|
||||||
in->next += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read a four-byte unsigned integer, little-endian, from in */
|
|
||||||
unsigned long read4(file *in)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
|
|
||||||
val = read1(in);
|
|
||||||
val += (unsigned)read1(in) << 8;
|
|
||||||
val += (unsigned long)read1(in) << 16;
|
|
||||||
val += (unsigned long)read1(in) << 24;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip over gzip header */
|
|
||||||
local void gzheader(file *in)
|
|
||||||
{
|
|
||||||
int flags;
|
|
||||||
unsigned n;
|
|
||||||
|
|
||||||
if (read1(in) != 31 || read1(in) != 139) bye(in->name, " not a gzip file");
|
|
||||||
if (read1(in) != 8) bye("unknown compression method in", in->name);
|
|
||||||
flags = read1(in);
|
|
||||||
if (flags & 0xe0) bye("unknown header flags set in", in->name);
|
|
||||||
skip(in, 6);
|
|
||||||
if (flags & 4) {
|
|
||||||
n = read1(in);
|
|
||||||
n += (unsigned)(read1(in)) << 8;
|
|
||||||
skip(in, n);
|
|
||||||
}
|
|
||||||
if (flags & 8) while (read1(in) != 0) ;
|
|
||||||
if (flags & 16) while (read1(in) != 0) ;
|
|
||||||
if (flags & 2) skip(in, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decompress gzip file "name", return strm with a deflate stream ready to
|
|
||||||
continue compression of the data in the gzip file, and return a file
|
|
||||||
descriptor pointing to where to write the compressed data -- the deflate
|
|
||||||
stream is initialized to compress using level "level" */
|
|
||||||
local int gzscan(char *name, z_stream *strm, int level)
|
|
||||||
{
|
|
||||||
int ret, lastbit, left, full;
|
|
||||||
unsigned have;
|
|
||||||
unsigned long crc, tot;
|
|
||||||
unsigned char *window;
|
|
||||||
off_t lastoff, end;
|
|
||||||
file gz;
|
|
||||||
|
|
||||||
/* open gzip file */
|
|
||||||
gz.name = name;
|
|
||||||
gz.fd = open(name, O_RDWR, 0);
|
|
||||||
if (gz.fd == -1) bye("cannot open ", name);
|
|
||||||
gz.buf = malloc(CHUNK);
|
|
||||||
if (gz.buf == NULL) bye("out of memory", "");
|
|
||||||
gz.size = LGCHUNK;
|
|
||||||
gz.left = 0;
|
|
||||||
|
|
||||||
/* skip gzip header */
|
|
||||||
gzheader(&gz);
|
|
||||||
|
|
||||||
/* prepare to decompress */
|
|
||||||
window = malloc(DSIZE);
|
|
||||||
if (window == NULL) bye("out of memory", "");
|
|
||||||
strm->zalloc = Z_NULL;
|
|
||||||
strm->zfree = Z_NULL;
|
|
||||||
strm->opaque = Z_NULL;
|
|
||||||
ret = inflateInit2(strm, -15);
|
|
||||||
if (ret != Z_OK) bye("out of memory", " or library mismatch");
|
|
||||||
|
|
||||||
/* decompress the deflate stream, saving append information */
|
|
||||||
lastbit = 0;
|
|
||||||
lastoff = lseek(gz.fd, 0L, SEEK_CUR) - gz.left;
|
|
||||||
left = 0;
|
|
||||||
strm->avail_in = gz.left;
|
|
||||||
strm->next_in = gz.next;
|
|
||||||
crc = crc32(0L, Z_NULL, 0);
|
|
||||||
have = full = 0;
|
|
||||||
do {
|
|
||||||
/* if needed, get more input */
|
|
||||||
if (strm->avail_in == 0) {
|
|
||||||
readmore(&gz);
|
|
||||||
strm->avail_in = gz.left;
|
|
||||||
strm->next_in = gz.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set up output to next available section of sliding window */
|
|
||||||
strm->avail_out = DSIZE - have;
|
|
||||||
strm->next_out = window + have;
|
|
||||||
|
|
||||||
/* inflate and check for errors */
|
|
||||||
ret = inflate(strm, Z_BLOCK);
|
|
||||||
if (ret == Z_STREAM_ERROR) bye("internal stream error!", "");
|
|
||||||
if (ret == Z_MEM_ERROR) bye("out of memory", "");
|
|
||||||
if (ret == Z_DATA_ERROR)
|
|
||||||
bye("invalid compressed data--format violated in", name);
|
|
||||||
|
|
||||||
/* update crc and sliding window pointer */
|
|
||||||
crc = crc32(crc, window + have, DSIZE - have - strm->avail_out);
|
|
||||||
if (strm->avail_out)
|
|
||||||
have = DSIZE - strm->avail_out;
|
|
||||||
else {
|
|
||||||
have = 0;
|
|
||||||
full = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process end of block */
|
|
||||||
if (strm->data_type & 128) {
|
|
||||||
if (strm->data_type & 64)
|
|
||||||
left = strm->data_type & 0x1f;
|
|
||||||
else {
|
|
||||||
lastbit = strm->data_type & 0x1f;
|
|
||||||
lastoff = lseek(gz.fd, 0L, SEEK_CUR) - strm->avail_in;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (ret != Z_STREAM_END);
|
|
||||||
inflateEnd(strm);
|
|
||||||
gz.left = strm->avail_in;
|
|
||||||
gz.next = strm->next_in;
|
|
||||||
|
|
||||||
/* save the location of the end of the compressed data */
|
|
||||||
end = lseek(gz.fd, 0L, SEEK_CUR) - gz.left;
|
|
||||||
|
|
||||||
/* check gzip trailer and save total for deflate */
|
|
||||||
if (crc != read4(&gz))
|
|
||||||
bye("invalid compressed data--crc mismatch in ", name);
|
|
||||||
tot = strm->total_out;
|
|
||||||
if ((tot & 0xffffffffUL) != read4(&gz))
|
|
||||||
bye("invalid compressed data--length mismatch in", name);
|
|
||||||
|
|
||||||
/* if not at end of file, warn */
|
|
||||||
if (gz.left || readin(&gz))
|
|
||||||
fprintf(stderr,
|
|
||||||
"gzappend warning: junk at end of gzip file overwritten\n");
|
|
||||||
|
|
||||||
/* clear last block bit */
|
|
||||||
lseek(gz.fd, lastoff - (lastbit != 0), SEEK_SET);
|
|
||||||
if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name);
|
|
||||||
*gz.buf = (unsigned char)(*gz.buf ^ (1 << ((8 - lastbit) & 7)));
|
|
||||||
lseek(gz.fd, -1L, SEEK_CUR);
|
|
||||||
if (write(gz.fd, gz.buf, 1) != 1) bye("writing after seek to ", name);
|
|
||||||
|
|
||||||
/* if window wrapped, build dictionary from window by rotating */
|
|
||||||
if (full) {
|
|
||||||
rotate(window, DSIZE, have);
|
|
||||||
have = DSIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set up deflate stream with window, crc, total_in, and leftover bits */
|
|
||||||
ret = deflateInit2(strm, level, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
|
||||||
if (ret != Z_OK) bye("out of memory", "");
|
|
||||||
deflateSetDictionary(strm, window, have);
|
|
||||||
strm->adler = crc;
|
|
||||||
strm->total_in = tot;
|
|
||||||
if (left) {
|
|
||||||
lseek(gz.fd, --end, SEEK_SET);
|
|
||||||
if (read(gz.fd, gz.buf, 1) != 1) bye("reading after seek on ", name);
|
|
||||||
deflatePrime(strm, 8 - left, *gz.buf);
|
|
||||||
}
|
|
||||||
lseek(gz.fd, end, SEEK_SET);
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
free(window);
|
|
||||||
free(gz.buf);
|
|
||||||
return gz.fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* append file "name" to gzip file gd using deflate stream strm -- if last
|
|
||||||
is true, then finish off the deflate stream at the end */
|
|
||||||
local void gztack(char *name, int gd, z_stream *strm, int last)
|
|
||||||
{
|
|
||||||
int fd, len, ret;
|
|
||||||
unsigned left;
|
|
||||||
unsigned char *in, *out;
|
|
||||||
|
|
||||||
/* open file to compress and append */
|
|
||||||
fd = 0;
|
|
||||||
if (name != NULL) {
|
|
||||||
fd = open(name, O_RDONLY, 0);
|
|
||||||
if (fd == -1)
|
|
||||||
fprintf(stderr, "gzappend warning: %s not found, skipping ...\n",
|
|
||||||
name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* allocate buffers */
|
|
||||||
in = malloc(CHUNK);
|
|
||||||
out = malloc(CHUNK);
|
|
||||||
if (in == NULL || out == NULL) bye("out of memory", "");
|
|
||||||
|
|
||||||
/* compress input file and append to gzip file */
|
|
||||||
do {
|
|
||||||
/* get more input */
|
|
||||||
len = read(fd, in, CHUNK);
|
|
||||||
if (len == -1) {
|
|
||||||
fprintf(stderr,
|
|
||||||
"gzappend warning: error reading %s, skipping rest ...\n",
|
|
||||||
name);
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
strm->avail_in = (unsigned)len;
|
|
||||||
strm->next_in = in;
|
|
||||||
if (len) strm->adler = crc32(strm->adler, in, (unsigned)len);
|
|
||||||
|
|
||||||
/* compress and write all available output */
|
|
||||||
do {
|
|
||||||
strm->avail_out = CHUNK;
|
|
||||||
strm->next_out = out;
|
|
||||||
ret = deflate(strm, last && len == 0 ? Z_FINISH : Z_NO_FLUSH);
|
|
||||||
left = CHUNK - strm->avail_out;
|
|
||||||
while (left) {
|
|
||||||
len = write(gd, out + CHUNK - strm->avail_out - left, left);
|
|
||||||
if (len == -1) bye("writing gzip file", "");
|
|
||||||
left -= (unsigned)len;
|
|
||||||
}
|
|
||||||
} while (strm->avail_out == 0 && ret != Z_STREAM_END);
|
|
||||||
} while (len != 0);
|
|
||||||
|
|
||||||
/* write trailer after last entry */
|
|
||||||
if (last) {
|
|
||||||
deflateEnd(strm);
|
|
||||||
out[0] = (unsigned char)(strm->adler);
|
|
||||||
out[1] = (unsigned char)(strm->adler >> 8);
|
|
||||||
out[2] = (unsigned char)(strm->adler >> 16);
|
|
||||||
out[3] = (unsigned char)(strm->adler >> 24);
|
|
||||||
out[4] = (unsigned char)(strm->total_in);
|
|
||||||
out[5] = (unsigned char)(strm->total_in >> 8);
|
|
||||||
out[6] = (unsigned char)(strm->total_in >> 16);
|
|
||||||
out[7] = (unsigned char)(strm->total_in >> 24);
|
|
||||||
len = 8;
|
|
||||||
do {
|
|
||||||
ret = write(gd, out + 8 - len, len);
|
|
||||||
if (ret == -1) bye("writing gzip file", "");
|
|
||||||
len -= ret;
|
|
||||||
} while (len);
|
|
||||||
close(gd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
free(out);
|
|
||||||
free(in);
|
|
||||||
if (fd > 0) close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* process the compression level option if present, scan the gzip file, and
|
|
||||||
append the specified files, or append the data from stdin if no other file
|
|
||||||
names are provided on the command line -- the gzip file must be writable
|
|
||||||
and seekable */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int gd, level;
|
|
||||||
z_stream strm;
|
|
||||||
|
|
||||||
/* ignore command name */
|
|
||||||
argc--; argv++;
|
|
||||||
|
|
||||||
/* provide usage if no arguments */
|
|
||||||
if (*argv == NULL) {
|
|
||||||
printf(
|
|
||||||
"gzappend 1.2 (11 Oct 2012) Copyright (C) 2003, 2012 Mark Adler\n"
|
|
||||||
);
|
|
||||||
printf(
|
|
||||||
"usage: gzappend [-level] file.gz [ addthis [ andthis ... ]]\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set compression level */
|
|
||||||
level = Z_DEFAULT_COMPRESSION;
|
|
||||||
if (argv[0][0] == '-') {
|
|
||||||
if (argv[0][1] < '0' || argv[0][1] > '9' || argv[0][2] != 0)
|
|
||||||
bye("invalid compression level", "");
|
|
||||||
level = argv[0][1] - '0';
|
|
||||||
if (*++argv == NULL) bye("no gzip file name after options", "");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* prepare to append to gzip file */
|
|
||||||
gd = gzscan(*argv++, &strm, level);
|
|
||||||
|
|
||||||
/* append files on command line, or from stdin if none */
|
|
||||||
if (*argv == NULL)
|
|
||||||
gztack(NULL, gd, &strm, 1);
|
|
||||||
else
|
|
||||||
do {
|
|
||||||
gztack(*argv, gd, &strm, argv[1] == NULL);
|
|
||||||
} while (*++argv != NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,449 +0,0 @@
|
||||||
/* gzjoin -- command to join gzip files into one gzip file
|
|
||||||
|
|
||||||
Copyright (C) 2004, 2005, 2012 Mark Adler, all rights reserved
|
|
||||||
version 1.2, 14 Aug 2012
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the author be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
Mark Adler madler@alumni.caltech.edu
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Change history:
|
|
||||||
*
|
|
||||||
* 1.0 11 Dec 2004 - First version
|
|
||||||
* 1.1 12 Jun 2005 - Changed ssize_t to long for portability
|
|
||||||
* 1.2 14 Aug 2012 - Clean up for z_const usage
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
gzjoin takes one or more gzip files on the command line and writes out a
|
|
||||||
single gzip file that will uncompress to the concatenation of the
|
|
||||||
uncompressed data from the individual gzip files. gzjoin does this without
|
|
||||||
having to recompress any of the data and without having to calculate a new
|
|
||||||
crc32 for the concatenated uncompressed data. gzjoin does however have to
|
|
||||||
decompress all of the input data in order to find the bits in the compressed
|
|
||||||
data that need to be modified to concatenate the streams.
|
|
||||||
|
|
||||||
gzjoin does not do an integrity check on the input gzip files other than
|
|
||||||
checking the gzip header and decompressing the compressed data. They are
|
|
||||||
otherwise assumed to be complete and correct.
|
|
||||||
|
|
||||||
Each joint between gzip files removes at least 18 bytes of previous trailer
|
|
||||||
and subsequent header, and inserts an average of about three bytes to the
|
|
||||||
compressed data in order to connect the streams. The output gzip file
|
|
||||||
has a minimal ten-byte gzip header with no file name or modification time.
|
|
||||||
|
|
||||||
This program was written to illustrate the use of the Z_BLOCK option of
|
|
||||||
inflate() and the crc32_combine() function. gzjoin will not compile with
|
|
||||||
versions of zlib earlier than 1.2.3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h> /* fputs(), fprintf(), fwrite(), putc() */
|
|
||||||
#include <stdlib.h> /* exit(), malloc(), free() */
|
|
||||||
#include <fcntl.h> /* open() */
|
|
||||||
#include <unistd.h> /* close(), read(), lseek() */
|
|
||||||
#include "zlib.h"
|
|
||||||
/* crc32(), crc32_combine(), inflateInit2(), inflate(), inflateEnd() */
|
|
||||||
|
|
||||||
#define local static
|
|
||||||
|
|
||||||
/* exit with an error (return a value to allow use in an expression) */
|
|
||||||
local int bail(char *why1, char *why2)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "gzjoin error: %s%s, output incomplete\n", why1, why2);
|
|
||||||
exit(1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- simple buffered file input with access to the buffer -- */
|
|
||||||
|
|
||||||
#define CHUNK 32768 /* must be a power of two and fit in unsigned */
|
|
||||||
|
|
||||||
/* bin buffered input file type */
|
|
||||||
typedef struct {
|
|
||||||
char *name; /* name of file for error messages */
|
|
||||||
int fd; /* file descriptor */
|
|
||||||
unsigned left; /* bytes remaining at next */
|
|
||||||
unsigned char *next; /* next byte to read */
|
|
||||||
unsigned char *buf; /* allocated buffer of length CHUNK */
|
|
||||||
} bin;
|
|
||||||
|
|
||||||
/* close a buffered file and free allocated memory */
|
|
||||||
local void bclose(bin *in)
|
|
||||||
{
|
|
||||||
if (in != NULL) {
|
|
||||||
if (in->fd != -1)
|
|
||||||
close(in->fd);
|
|
||||||
if (in->buf != NULL)
|
|
||||||
free(in->buf);
|
|
||||||
free(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open a buffered file for input, return a pointer to type bin, or NULL on
|
|
||||||
failure */
|
|
||||||
local bin *bopen(char *name)
|
|
||||||
{
|
|
||||||
bin *in;
|
|
||||||
|
|
||||||
in = malloc(sizeof(bin));
|
|
||||||
if (in == NULL)
|
|
||||||
return NULL;
|
|
||||||
in->buf = malloc(CHUNK);
|
|
||||||
in->fd = open(name, O_RDONLY, 0);
|
|
||||||
if (in->buf == NULL || in->fd == -1) {
|
|
||||||
bclose(in);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
in->left = 0;
|
|
||||||
in->next = in->buf;
|
|
||||||
in->name = name;
|
|
||||||
return in;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load buffer from file, return -1 on read error, 0 or 1 on success, with
|
|
||||||
1 indicating that end-of-file was reached */
|
|
||||||
local int bload(bin *in)
|
|
||||||
{
|
|
||||||
long len;
|
|
||||||
|
|
||||||
if (in == NULL)
|
|
||||||
return -1;
|
|
||||||
if (in->left != 0)
|
|
||||||
return 0;
|
|
||||||
in->next = in->buf;
|
|
||||||
do {
|
|
||||||
len = (long)read(in->fd, in->buf + in->left, CHUNK - in->left);
|
|
||||||
if (len < 0)
|
|
||||||
return -1;
|
|
||||||
in->left += (unsigned)len;
|
|
||||||
} while (len != 0 && in->left < CHUNK);
|
|
||||||
return len == 0 ? 1 : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* get a byte from the file, bail if end of file */
|
|
||||||
#define bget(in) (in->left ? 0 : bload(in), \
|
|
||||||
in->left ? (in->left--, *(in->next)++) : \
|
|
||||||
bail("unexpected end of file on ", in->name))
|
|
||||||
|
|
||||||
/* get a four-byte little-endian unsigned integer from file */
|
|
||||||
local unsigned long bget4(bin *in)
|
|
||||||
{
|
|
||||||
unsigned long val;
|
|
||||||
|
|
||||||
val = bget(in);
|
|
||||||
val += (unsigned long)(bget(in)) << 8;
|
|
||||||
val += (unsigned long)(bget(in)) << 16;
|
|
||||||
val += (unsigned long)(bget(in)) << 24;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip bytes in file */
|
|
||||||
local void bskip(bin *in, unsigned skip)
|
|
||||||
{
|
|
||||||
/* check pointer */
|
|
||||||
if (in == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* easy case -- skip bytes in buffer */
|
|
||||||
if (skip <= in->left) {
|
|
||||||
in->left -= skip;
|
|
||||||
in->next += skip;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip what's in buffer, discard buffer contents */
|
|
||||||
skip -= in->left;
|
|
||||||
in->left = 0;
|
|
||||||
|
|
||||||
/* seek past multiples of CHUNK bytes */
|
|
||||||
if (skip > CHUNK) {
|
|
||||||
unsigned left;
|
|
||||||
|
|
||||||
left = skip & (CHUNK - 1);
|
|
||||||
if (left == 0) {
|
|
||||||
/* exact number of chunks: seek all the way minus one byte to check
|
|
||||||
for end-of-file with a read */
|
|
||||||
lseek(in->fd, skip - 1, SEEK_CUR);
|
|
||||||
if (read(in->fd, in->buf, 1) != 1)
|
|
||||||
bail("unexpected end of file on ", in->name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip the integral chunks, update skip with remainder */
|
|
||||||
lseek(in->fd, skip - left, SEEK_CUR);
|
|
||||||
skip = left;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* read more input and skip remainder */
|
|
||||||
bload(in);
|
|
||||||
if (skip > in->left)
|
|
||||||
bail("unexpected end of file on ", in->name);
|
|
||||||
in->left -= skip;
|
|
||||||
in->next += skip;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* -- end of buffered input functions -- */
|
|
||||||
|
|
||||||
/* skip the gzip header from file in */
|
|
||||||
local void gzhead(bin *in)
|
|
||||||
{
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
/* verify gzip magic header and compression method */
|
|
||||||
if (bget(in) != 0x1f || bget(in) != 0x8b || bget(in) != 8)
|
|
||||||
bail(in->name, " is not a valid gzip file");
|
|
||||||
|
|
||||||
/* get and verify flags */
|
|
||||||
flags = bget(in);
|
|
||||||
if ((flags & 0xe0) != 0)
|
|
||||||
bail("unknown reserved bits set in ", in->name);
|
|
||||||
|
|
||||||
/* skip modification time, extra flags, and os */
|
|
||||||
bskip(in, 6);
|
|
||||||
|
|
||||||
/* skip extra field if present */
|
|
||||||
if (flags & 4) {
|
|
||||||
unsigned len;
|
|
||||||
|
|
||||||
len = bget(in);
|
|
||||||
len += (unsigned)(bget(in)) << 8;
|
|
||||||
bskip(in, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip file name if present */
|
|
||||||
if (flags & 8)
|
|
||||||
while (bget(in) != 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
/* skip comment if present */
|
|
||||||
if (flags & 16)
|
|
||||||
while (bget(in) != 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
/* skip header crc if present */
|
|
||||||
if (flags & 2)
|
|
||||||
bskip(in, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* write a four-byte little-endian unsigned integer to out */
|
|
||||||
local void put4(unsigned long val, FILE *out)
|
|
||||||
{
|
|
||||||
putc(val & 0xff, out);
|
|
||||||
putc((val >> 8) & 0xff, out);
|
|
||||||
putc((val >> 16) & 0xff, out);
|
|
||||||
putc((val >> 24) & 0xff, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load up zlib stream from buffered input, bail if end of file */
|
|
||||||
local void zpull(z_streamp strm, bin *in)
|
|
||||||
{
|
|
||||||
if (in->left == 0)
|
|
||||||
bload(in);
|
|
||||||
if (in->left == 0)
|
|
||||||
bail("unexpected end of file on ", in->name);
|
|
||||||
strm->avail_in = in->left;
|
|
||||||
strm->next_in = in->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write header for gzip file to out and initialize trailer. */
|
|
||||||
local void gzinit(unsigned long *crc, unsigned long *tot, FILE *out)
|
|
||||||
{
|
|
||||||
fwrite("\x1f\x8b\x08\0\0\0\0\0\0\xff", 1, 10, out);
|
|
||||||
*crc = crc32(0L, Z_NULL, 0);
|
|
||||||
*tot = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Copy the compressed data from name, zeroing the last block bit of the last
|
|
||||||
block if clr is true, and adding empty blocks as needed to get to a byte
|
|
||||||
boundary. If clr is false, then the last block becomes the last block of
|
|
||||||
the output, and the gzip trailer is written. crc and tot maintains the
|
|
||||||
crc and length (modulo 2^32) of the output for the trailer. The resulting
|
|
||||||
gzip file is written to out. gzinit() must be called before the first call
|
|
||||||
of gzcopy() to write the gzip header and to initialize crc and tot. */
|
|
||||||
local void gzcopy(char *name, int clr, unsigned long *crc, unsigned long *tot,
|
|
||||||
FILE *out)
|
|
||||||
{
|
|
||||||
int ret; /* return value from zlib functions */
|
|
||||||
int pos; /* where the "last block" bit is in byte */
|
|
||||||
int last; /* true if processing the last block */
|
|
||||||
bin *in; /* buffered input file */
|
|
||||||
unsigned char *start; /* start of compressed data in buffer */
|
|
||||||
unsigned char *junk; /* buffer for uncompressed data -- discarded */
|
|
||||||
z_off_t len; /* length of uncompressed data (support > 4 GB) */
|
|
||||||
z_stream strm; /* zlib inflate stream */
|
|
||||||
|
|
||||||
/* open gzip file and skip header */
|
|
||||||
in = bopen(name);
|
|
||||||
if (in == NULL)
|
|
||||||
bail("could not open ", name);
|
|
||||||
gzhead(in);
|
|
||||||
|
|
||||||
/* allocate buffer for uncompressed data and initialize raw inflate
|
|
||||||
stream */
|
|
||||||
junk = malloc(CHUNK);
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = 0;
|
|
||||||
strm.next_in = Z_NULL;
|
|
||||||
ret = inflateInit2(&strm, -15);
|
|
||||||
if (junk == NULL || ret != Z_OK)
|
|
||||||
bail("out of memory", "");
|
|
||||||
|
|
||||||
/* inflate and copy compressed data, clear last-block bit if requested */
|
|
||||||
len = 0;
|
|
||||||
zpull(&strm, in);
|
|
||||||
start = in->next;
|
|
||||||
last = start[0] & 1;
|
|
||||||
if (last && clr)
|
|
||||||
start[0] &= ~1;
|
|
||||||
strm.avail_out = 0;
|
|
||||||
for (;;) {
|
|
||||||
/* if input used and output done, write used input and get more */
|
|
||||||
if (strm.avail_in == 0 && strm.avail_out != 0) {
|
|
||||||
fwrite(start, 1, strm.next_in - start, out);
|
|
||||||
start = in->buf;
|
|
||||||
in->left = 0;
|
|
||||||
zpull(&strm, in);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* decompress -- return early when end-of-block reached */
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = junk;
|
|
||||||
ret = inflate(&strm, Z_BLOCK);
|
|
||||||
switch (ret) {
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
bail("out of memory", "");
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
bail("invalid compressed data in ", in->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update length of uncompressed data */
|
|
||||||
len += CHUNK - strm.avail_out;
|
|
||||||
|
|
||||||
/* check for block boundary (only get this when block copied out) */
|
|
||||||
if (strm.data_type & 128) {
|
|
||||||
/* if that was the last block, then done */
|
|
||||||
if (last)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* number of unused bits in last byte */
|
|
||||||
pos = strm.data_type & 7;
|
|
||||||
|
|
||||||
/* find the next last-block bit */
|
|
||||||
if (pos != 0) {
|
|
||||||
/* next last-block bit is in last used byte */
|
|
||||||
pos = 0x100 >> pos;
|
|
||||||
last = strm.next_in[-1] & pos;
|
|
||||||
if (last && clr)
|
|
||||||
in->buf[strm.next_in - in->buf - 1] &= ~pos;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* next last-block bit is in next unused byte */
|
|
||||||
if (strm.avail_in == 0) {
|
|
||||||
/* don't have that byte yet -- get it */
|
|
||||||
fwrite(start, 1, strm.next_in - start, out);
|
|
||||||
start = in->buf;
|
|
||||||
in->left = 0;
|
|
||||||
zpull(&strm, in);
|
|
||||||
}
|
|
||||||
last = strm.next_in[0] & 1;
|
|
||||||
if (last && clr)
|
|
||||||
in->buf[strm.next_in - in->buf] &= ~1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update buffer with unused input */
|
|
||||||
in->left = strm.avail_in;
|
|
||||||
in->next = in->buf + (strm.next_in - in->buf);
|
|
||||||
|
|
||||||
/* copy used input, write empty blocks to get to byte boundary */
|
|
||||||
pos = strm.data_type & 7;
|
|
||||||
fwrite(start, 1, in->next - start - 1, out);
|
|
||||||
last = in->next[-1];
|
|
||||||
if (pos == 0 || !clr)
|
|
||||||
/* already at byte boundary, or last file: write last byte */
|
|
||||||
putc(last, out);
|
|
||||||
else {
|
|
||||||
/* append empty blocks to last byte */
|
|
||||||
last &= ((0x100 >> pos) - 1); /* assure unused bits are zero */
|
|
||||||
if (pos & 1) {
|
|
||||||
/* odd -- append an empty stored block */
|
|
||||||
putc(last, out);
|
|
||||||
if (pos == 1)
|
|
||||||
putc(0, out); /* two more bits in block header */
|
|
||||||
fwrite("\0\0\xff\xff", 1, 4, out);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* even -- append 1, 2, or 3 empty fixed blocks */
|
|
||||||
switch (pos) {
|
|
||||||
case 6:
|
|
||||||
putc(last | 8, out);
|
|
||||||
last = 0;
|
|
||||||
case 4:
|
|
||||||
putc(last | 0x20, out);
|
|
||||||
last = 0;
|
|
||||||
case 2:
|
|
||||||
putc(last | 0x80, out);
|
|
||||||
putc(0, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* update crc and tot */
|
|
||||||
*crc = crc32_combine(*crc, bget4(in), len);
|
|
||||||
*tot += (unsigned long)len;
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
inflateEnd(&strm);
|
|
||||||
free(junk);
|
|
||||||
bclose(in);
|
|
||||||
|
|
||||||
/* write trailer if this is the last gzip file */
|
|
||||||
if (!clr) {
|
|
||||||
put4(*crc, out);
|
|
||||||
put4(*tot, out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* join the gzip files on the command line, write result to stdout */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
unsigned long crc, tot; /* running crc and total uncompressed length */
|
|
||||||
|
|
||||||
/* skip command name */
|
|
||||||
argc--;
|
|
||||||
argv++;
|
|
||||||
|
|
||||||
/* show usage if no arguments */
|
|
||||||
if (argc == 0) {
|
|
||||||
fputs("gzjoin usage: gzjoin f1.gz [f2.gz [f3.gz ...]] > fjoin.gz\n",
|
|
||||||
stderr);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* join gzip files on command line and write to stdout */
|
|
||||||
gzinit(&crc, &tot, stdout);
|
|
||||||
while (argc--)
|
|
||||||
gzcopy(*argv++, argc, &crc, &tot, stdout);
|
|
||||||
|
|
||||||
/* done */
|
|
||||||
return 0;
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,91 +0,0 @@
|
||||||
/* gzlog.h
|
|
||||||
Copyright (C) 2004, 2008, 2012 Mark Adler, all rights reserved
|
|
||||||
version 2.2, 14 Aug 2012
|
|
||||||
|
|
||||||
This software is provided 'as-is', without any express or implied
|
|
||||||
warranty. In no event will the author be held liable for any damages
|
|
||||||
arising from the use of this software.
|
|
||||||
|
|
||||||
Permission is granted to anyone to use this software for any purpose,
|
|
||||||
including commercial applications, and to alter it and redistribute it
|
|
||||||
freely, subject to the following restrictions:
|
|
||||||
|
|
||||||
1. The origin of this software must not be misrepresented; you must not
|
|
||||||
claim that you wrote the original software. If you use this software
|
|
||||||
in a product, an acknowledgment in the product documentation would be
|
|
||||||
appreciated but is not required.
|
|
||||||
2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
misrepresented as being the original software.
|
|
||||||
3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
Mark Adler madler@alumni.caltech.edu
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Version History:
|
|
||||||
1.0 26 Nov 2004 First version
|
|
||||||
2.0 25 Apr 2008 Complete redesign for recovery of interrupted operations
|
|
||||||
Interface changed slightly in that now path is a prefix
|
|
||||||
Compression now occurs as needed during gzlog_write()
|
|
||||||
gzlog_write() now always leaves the log file as valid gzip
|
|
||||||
2.1 8 Jul 2012 Fix argument checks in gzlog_compress() and gzlog_write()
|
|
||||||
2.2 14 Aug 2012 Clean up signed comparisons
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
The gzlog object allows writing short messages to a gzipped log file,
|
|
||||||
opening the log file locked for small bursts, and then closing it. The log
|
|
||||||
object works by appending stored (uncompressed) data to the gzip file until
|
|
||||||
1 MB has been accumulated. At that time, the stored data is compressed, and
|
|
||||||
replaces the uncompressed data in the file. The log file is truncated to
|
|
||||||
its new size at that time. After each write operation, the log file is a
|
|
||||||
valid gzip file that can decompressed to recover what was written.
|
|
||||||
|
|
||||||
The gzlog operations can be interupted at any point due to an application or
|
|
||||||
system crash, and the log file will be recovered the next time the log is
|
|
||||||
opened with gzlog_open().
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef GZLOG_H
|
|
||||||
#define GZLOG_H
|
|
||||||
|
|
||||||
/* gzlog object type */
|
|
||||||
typedef void gzlog;
|
|
||||||
|
|
||||||
/* Open a gzlog object, creating the log file if it does not exist. Return
|
|
||||||
NULL on error. Note that gzlog_open() could take a while to complete if it
|
|
||||||
has to wait to verify that a lock is stale (possibly for five minutes), or
|
|
||||||
if there is significant contention with other instantiations of this object
|
|
||||||
when locking the resource. path is the prefix of the file names created by
|
|
||||||
this object. If path is "foo", then the log file will be "foo.gz", and
|
|
||||||
other auxiliary files will be created and destroyed during the process:
|
|
||||||
"foo.dict" for a compression dictionary, "foo.temp" for a temporary (next)
|
|
||||||
dictionary, "foo.add" for data being added or compressed, "foo.lock" for the
|
|
||||||
lock file, and "foo.repairs" to log recovery operations performed due to
|
|
||||||
interrupted gzlog operations. A gzlog_open() followed by a gzlog_close()
|
|
||||||
will recover a previously interrupted operation, if any. */
|
|
||||||
gzlog *gzlog_open(char *path);
|
|
||||||
|
|
||||||
/* Write to a gzlog object. Return zero on success, -1 if there is a file i/o
|
|
||||||
error on any of the gzlog files (this should not happen if gzlog_open()
|
|
||||||
succeeded, unless the device has run out of space or leftover auxiliary
|
|
||||||
files have permissions or ownership that prevent their use), -2 if there is
|
|
||||||
a memory allocation failure, or -3 if the log argument is invalid (e.g. if
|
|
||||||
it was not created by gzlog_open()). This function will write data to the
|
|
||||||
file uncompressed, until 1 MB has been accumulated, at which time that data
|
|
||||||
will be compressed. The log file will be a valid gzip file upon successful
|
|
||||||
return. */
|
|
||||||
int gzlog_write(gzlog *log, void *data, size_t len);
|
|
||||||
|
|
||||||
/* Force compression of any uncompressed data in the log. This should be used
|
|
||||||
sparingly, if at all. The main application would be when a log file will
|
|
||||||
not be appended to again. If this is used to compress frequently while
|
|
||||||
appending, it will both significantly increase the execution time and
|
|
||||||
reduce the compression ratio. The return codes are the same as for
|
|
||||||
gzlog_write(). */
|
|
||||||
int gzlog_compress(gzlog *log);
|
|
||||||
|
|
||||||
/* Close a gzlog object. Return zero on success, -3 if the log argument is
|
|
||||||
invalid. The log object is freed, and so cannot be referenced again. */
|
|
||||||
int gzlog_close(gzlog *log);
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,545 +0,0 @@
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
|
|
||||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
|
||||||
<title>zlib Usage Example</title>
|
|
||||||
<!-- Copyright (c) 2004, 2005 Mark Adler. -->
|
|
||||||
</head>
|
|
||||||
<body bgcolor="#FFFFFF" text="#000000" link="#0000FF" vlink="#00A000">
|
|
||||||
<h2 align="center"> zlib Usage Example </h2>
|
|
||||||
We often get questions about how the <tt>deflate()</tt> and <tt>inflate()</tt> functions should be used.
|
|
||||||
Users wonder when they should provide more input, when they should use more output,
|
|
||||||
what to do with a <tt>Z_BUF_ERROR</tt>, how to make sure the process terminates properly, and
|
|
||||||
so on. So for those who have read <tt>zlib.h</tt> (a few times), and
|
|
||||||
would like further edification, below is an annotated example in C of simple routines to compress and decompress
|
|
||||||
from an input file to an output file using <tt>deflate()</tt> and <tt>inflate()</tt> respectively. The
|
|
||||||
annotations are interspersed between lines of the code. So please read between the lines.
|
|
||||||
We hope this helps explain some of the intricacies of <em>zlib</em>.
|
|
||||||
<p>
|
|
||||||
Without further adieu, here is the program <a href="zpipe.c"><tt>zpipe.c</tt></a>:
|
|
||||||
<pre><b>
|
|
||||||
/* zpipe.c: example of proper use of zlib's inflate() and deflate()
|
|
||||||
Not copyrighted -- provided to the public domain
|
|
||||||
Version 1.4 11 December 2005 Mark Adler */
|
|
||||||
|
|
||||||
/* Version history:
|
|
||||||
1.0 30 Oct 2004 First version
|
|
||||||
1.1 8 Nov 2004 Add void casting for unused return values
|
|
||||||
Use switch statement for inflate() return values
|
|
||||||
1.2 9 Nov 2004 Add assertions to document zlib guarantees
|
|
||||||
1.3 6 Apr 2005 Remove incorrect assertion in inf()
|
|
||||||
1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions
|
|
||||||
Avoid some compiler warnings for input and output buffers
|
|
||||||
*/
|
|
||||||
</b></pre><!-- -->
|
|
||||||
We now include the header files for the required definitions. From
|
|
||||||
<tt>stdio.h</tt> we use <tt>fopen()</tt>, <tt>fread()</tt>, <tt>fwrite()</tt>,
|
|
||||||
<tt>feof()</tt>, <tt>ferror()</tt>, and <tt>fclose()</tt> for file i/o, and
|
|
||||||
<tt>fputs()</tt> for error messages. From <tt>string.h</tt> we use
|
|
||||||
<tt>strcmp()</tt> for command line argument processing.
|
|
||||||
From <tt>assert.h</tt> we use the <tt>assert()</tt> macro.
|
|
||||||
From <tt>zlib.h</tt>
|
|
||||||
we use the basic compression functions <tt>deflateInit()</tt>,
|
|
||||||
<tt>deflate()</tt>, and <tt>deflateEnd()</tt>, and the basic decompression
|
|
||||||
functions <tt>inflateInit()</tt>, <tt>inflate()</tt>, and
|
|
||||||
<tt>inflateEnd()</tt>.
|
|
||||||
<pre><b>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "zlib.h"
|
|
||||||
</b></pre><!-- -->
|
|
||||||
This is an ugly hack required to avoid corruption of the input and output data on
|
|
||||||
Windows/MS-DOS systems. Without this, those systems would assume that the input and output
|
|
||||||
files are text, and try to convert the end-of-line characters from one standard to
|
|
||||||
another. That would corrupt binary data, and in particular would render the compressed data unusable.
|
|
||||||
This sets the input and output to binary which suppresses the end-of-line conversions.
|
|
||||||
<tt>SET_BINARY_MODE()</tt> will be used later on <tt>stdin</tt> and <tt>stdout</tt>, at the beginning of <tt>main()</tt>.
|
|
||||||
<pre><b>
|
|
||||||
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
|
|
||||||
# include <fcntl.h>
|
|
||||||
# include <io.h>
|
|
||||||
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
|
|
||||||
#else
|
|
||||||
# define SET_BINARY_MODE(file)
|
|
||||||
#endif
|
|
||||||
</b></pre><!-- -->
|
|
||||||
<tt>CHUNK</tt> is simply the buffer size for feeding data to and pulling data
|
|
||||||
from the <em>zlib</em> routines. Larger buffer sizes would be more efficient,
|
|
||||||
especially for <tt>inflate()</tt>. If the memory is available, buffers sizes
|
|
||||||
on the order of 128K or 256K bytes should be used.
|
|
||||||
<pre><b>
|
|
||||||
#define CHUNK 16384
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The <tt>def()</tt> routine compresses data from an input file to an output file. The output data
|
|
||||||
will be in the <em>zlib</em> format, which is different from the <em>gzip</em> or <em>zip</em>
|
|
||||||
formats. The <em>zlib</em> format has a very small header of only two bytes to identify it as
|
|
||||||
a <em>zlib</em> stream and to provide decoding information, and a four-byte trailer with a fast
|
|
||||||
check value to verify the integrity of the uncompressed data after decoding.
|
|
||||||
<pre><b>
|
|
||||||
/* Compress from file source to file dest until EOF on source.
|
|
||||||
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
|
|
||||||
allocated for processing, Z_STREAM_ERROR if an invalid compression
|
|
||||||
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
|
|
||||||
version of the library linked do not match, or Z_ERRNO if there is
|
|
||||||
an error reading or writing the files. */
|
|
||||||
int def(FILE *source, FILE *dest, int level)
|
|
||||||
{
|
|
||||||
</b></pre>
|
|
||||||
Here are the local variables for <tt>def()</tt>. <tt>ret</tt> will be used for <em>zlib</em>
|
|
||||||
return codes. <tt>flush</tt> will keep track of the current flushing state for <tt>deflate()</tt>,
|
|
||||||
which is either no flushing, or flush to completion after the end of the input file is reached.
|
|
||||||
<tt>have</tt> is the amount of data returned from <tt>deflate()</tt>. The <tt>strm</tt> structure
|
|
||||||
is used to pass information to and from the <em>zlib</em> routines, and to maintain the
|
|
||||||
<tt>deflate()</tt> state. <tt>in</tt> and <tt>out</tt> are the input and output buffers for
|
|
||||||
<tt>deflate()</tt>.
|
|
||||||
<pre><b>
|
|
||||||
int ret, flush;
|
|
||||||
unsigned have;
|
|
||||||
z_stream strm;
|
|
||||||
unsigned char in[CHUNK];
|
|
||||||
unsigned char out[CHUNK];
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The first thing we do is to initialize the <em>zlib</em> state for compression using
|
|
||||||
<tt>deflateInit()</tt>. This must be done before the first use of <tt>deflate()</tt>.
|
|
||||||
The <tt>zalloc</tt>, <tt>zfree</tt>, and <tt>opaque</tt> fields in the <tt>strm</tt>
|
|
||||||
structure must be initialized before calling <tt>deflateInit()</tt>. Here they are
|
|
||||||
set to the <em>zlib</em> constant <tt>Z_NULL</tt> to request that <em>zlib</em> use
|
|
||||||
the default memory allocation routines. An application may also choose to provide
|
|
||||||
custom memory allocation routines here. <tt>deflateInit()</tt> will allocate on the
|
|
||||||
order of 256K bytes for the internal state.
|
|
||||||
(See <a href="zlib_tech.html"><em>zlib Technical Details</em></a>.)
|
|
||||||
<p>
|
|
||||||
<tt>deflateInit()</tt> is called with a pointer to the structure to be initialized and
|
|
||||||
the compression level, which is an integer in the range of -1 to 9. Lower compression
|
|
||||||
levels result in faster execution, but less compression. Higher levels result in
|
|
||||||
greater compression, but slower execution. The <em>zlib</em> constant Z_DEFAULT_COMPRESSION,
|
|
||||||
equal to -1,
|
|
||||||
provides a good compromise between compression and speed and is equivalent to level 6.
|
|
||||||
Level 0 actually does no compression at all, and in fact expands the data slightly to produce
|
|
||||||
the <em>zlib</em> format (it is not a byte-for-byte copy of the input).
|
|
||||||
More advanced applications of <em>zlib</em>
|
|
||||||
may use <tt>deflateInit2()</tt> here instead. Such an application may want to reduce how
|
|
||||||
much memory will be used, at some price in compression. Or it may need to request a
|
|
||||||
<em>gzip</em> header and trailer instead of a <em>zlib</em> header and trailer, or raw
|
|
||||||
encoding with no header or trailer at all.
|
|
||||||
<p>
|
|
||||||
We must check the return value of <tt>deflateInit()</tt> against the <em>zlib</em> constant
|
|
||||||
<tt>Z_OK</tt> to make sure that it was able to
|
|
||||||
allocate memory for the internal state, and that the provided arguments were valid.
|
|
||||||
<tt>deflateInit()</tt> will also check that the version of <em>zlib</em> that the <tt>zlib.h</tt>
|
|
||||||
file came from matches the version of <em>zlib</em> actually linked with the program. This
|
|
||||||
is especially important for environments in which <em>zlib</em> is a shared library.
|
|
||||||
<p>
|
|
||||||
Note that an application can initialize multiple, independent <em>zlib</em> streams, which can
|
|
||||||
operate in parallel. The state information maintained in the structure allows the <em>zlib</em>
|
|
||||||
routines to be reentrant.
|
|
||||||
<pre><b>
|
|
||||||
/* allocate deflate state */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
ret = deflateInit(&strm, level);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
</b></pre><!-- -->
|
|
||||||
With the pleasantries out of the way, now we can get down to business. The outer <tt>do</tt>-loop
|
|
||||||
reads all of the input file and exits at the bottom of the loop once end-of-file is reached.
|
|
||||||
This loop contains the only call of <tt>deflate()</tt>. So we must make sure that all of the
|
|
||||||
input data has been processed and that all of the output data has been generated and consumed
|
|
||||||
before we fall out of the loop at the bottom.
|
|
||||||
<pre><b>
|
|
||||||
/* compress until end of file */
|
|
||||||
do {
|
|
||||||
</b></pre>
|
|
||||||
We start off by reading data from the input file. The number of bytes read is put directly
|
|
||||||
into <tt>avail_in</tt>, and a pointer to those bytes is put into <tt>next_in</tt>. We also
|
|
||||||
check to see if end-of-file on the input has been reached. If we are at the end of file, then <tt>flush</tt> is set to the
|
|
||||||
<em>zlib</em> constant <tt>Z_FINISH</tt>, which is later passed to <tt>deflate()</tt> to
|
|
||||||
indicate that this is the last chunk of input data to compress. We need to use <tt>feof()</tt>
|
|
||||||
to check for end-of-file as opposed to seeing if fewer than <tt>CHUNK</tt> bytes have been read. The
|
|
||||||
reason is that if the input file length is an exact multiple of <tt>CHUNK</tt>, we will miss
|
|
||||||
the fact that we got to the end-of-file, and not know to tell <tt>deflate()</tt> to finish
|
|
||||||
up the compressed stream. If we are not yet at the end of the input, then the <em>zlib</em>
|
|
||||||
constant <tt>Z_NO_FLUSH</tt> will be passed to <tt>deflate</tt> to indicate that we are still
|
|
||||||
in the middle of the uncompressed data.
|
|
||||||
<p>
|
|
||||||
If there is an error in reading from the input file, the process is aborted with
|
|
||||||
<tt>deflateEnd()</tt> being called to free the allocated <em>zlib</em> state before returning
|
|
||||||
the error. We wouldn't want a memory leak, now would we? <tt>deflateEnd()</tt> can be called
|
|
||||||
at any time after the state has been initialized. Once that's done, <tt>deflateInit()</tt> (or
|
|
||||||
<tt>deflateInit2()</tt>) would have to be called to start a new compression process. There is
|
|
||||||
no point here in checking the <tt>deflateEnd()</tt> return code. The deallocation can't fail.
|
|
||||||
<pre><b>
|
|
||||||
strm.avail_in = fread(in, 1, CHUNK, source);
|
|
||||||
if (ferror(source)) {
|
|
||||||
(void)deflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
|
|
||||||
strm.next_in = in;
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The inner <tt>do</tt>-loop passes our chunk of input data to <tt>deflate()</tt>, and then
|
|
||||||
keeps calling <tt>deflate()</tt> until it is done producing output. Once there is no more
|
|
||||||
new output, <tt>deflate()</tt> is guaranteed to have consumed all of the input, i.e.,
|
|
||||||
<tt>avail_in</tt> will be zero.
|
|
||||||
<pre><b>
|
|
||||||
/* run deflate() on input until output buffer not full, finish
|
|
||||||
compression if all of source has been read in */
|
|
||||||
do {
|
|
||||||
</b></pre>
|
|
||||||
Output space is provided to <tt>deflate()</tt> by setting <tt>avail_out</tt> to the number
|
|
||||||
of available output bytes and <tt>next_out</tt> to a pointer to that space.
|
|
||||||
<pre><b>
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = out;
|
|
||||||
</b></pre>
|
|
||||||
Now we call the compression engine itself, <tt>deflate()</tt>. It takes as many of the
|
|
||||||
<tt>avail_in</tt> bytes at <tt>next_in</tt> as it can process, and writes as many as
|
|
||||||
<tt>avail_out</tt> bytes to <tt>next_out</tt>. Those counters and pointers are then
|
|
||||||
updated past the input data consumed and the output data written. It is the amount of
|
|
||||||
output space available that may limit how much input is consumed.
|
|
||||||
Hence the inner loop to make sure that
|
|
||||||
all of the input is consumed by providing more output space each time. Since <tt>avail_in</tt>
|
|
||||||
and <tt>next_in</tt> are updated by <tt>deflate()</tt>, we don't have to mess with those
|
|
||||||
between <tt>deflate()</tt> calls until it's all used up.
|
|
||||||
<p>
|
|
||||||
The parameters to <tt>deflate()</tt> are a pointer to the <tt>strm</tt> structure containing
|
|
||||||
the input and output information and the internal compression engine state, and a parameter
|
|
||||||
indicating whether and how to flush data to the output. Normally <tt>deflate</tt> will consume
|
|
||||||
several K bytes of input data before producing any output (except for the header), in order
|
|
||||||
to accumulate statistics on the data for optimum compression. It will then put out a burst of
|
|
||||||
compressed data, and proceed to consume more input before the next burst. Eventually,
|
|
||||||
<tt>deflate()</tt>
|
|
||||||
must be told to terminate the stream, complete the compression with provided input data, and
|
|
||||||
write out the trailer check value. <tt>deflate()</tt> will continue to compress normally as long
|
|
||||||
as the flush parameter is <tt>Z_NO_FLUSH</tt>. Once the <tt>Z_FINISH</tt> parameter is provided,
|
|
||||||
<tt>deflate()</tt> will begin to complete the compressed output stream. However depending on how
|
|
||||||
much output space is provided, <tt>deflate()</tt> may have to be called several times until it
|
|
||||||
has provided the complete compressed stream, even after it has consumed all of the input. The flush
|
|
||||||
parameter must continue to be <tt>Z_FINISH</tt> for those subsequent calls.
|
|
||||||
<p>
|
|
||||||
There are other values of the flush parameter that are used in more advanced applications. You can
|
|
||||||
force <tt>deflate()</tt> to produce a burst of output that encodes all of the input data provided
|
|
||||||
so far, even if it wouldn't have otherwise, for example to control data latency on a link with
|
|
||||||
compressed data. You can also ask that <tt>deflate()</tt> do that as well as erase any history up to
|
|
||||||
that point so that what follows can be decompressed independently, for example for random access
|
|
||||||
applications. Both requests will degrade compression by an amount depending on how often such
|
|
||||||
requests are made.
|
|
||||||
<p>
|
|
||||||
<tt>deflate()</tt> has a return value that can indicate errors, yet we do not check it here. Why
|
|
||||||
not? Well, it turns out that <tt>deflate()</tt> can do no wrong here. Let's go through
|
|
||||||
<tt>deflate()</tt>'s return values and dispense with them one by one. The possible values are
|
|
||||||
<tt>Z_OK</tt>, <tt>Z_STREAM_END</tt>, <tt>Z_STREAM_ERROR</tt>, or <tt>Z_BUF_ERROR</tt>. <tt>Z_OK</tt>
|
|
||||||
is, well, ok. <tt>Z_STREAM_END</tt> is also ok and will be returned for the last call of
|
|
||||||
<tt>deflate()</tt>. This is already guaranteed by calling <tt>deflate()</tt> with <tt>Z_FINISH</tt>
|
|
||||||
until it has no more output. <tt>Z_STREAM_ERROR</tt> is only possible if the stream is not
|
|
||||||
initialized properly, but we did initialize it properly. There is no harm in checking for
|
|
||||||
<tt>Z_STREAM_ERROR</tt> here, for example to check for the possibility that some
|
|
||||||
other part of the application inadvertently clobbered the memory containing the <em>zlib</em> state.
|
|
||||||
<tt>Z_BUF_ERROR</tt> will be explained further below, but
|
|
||||||
suffice it to say that this is simply an indication that <tt>deflate()</tt> could not consume
|
|
||||||
more input or produce more output. <tt>deflate()</tt> can be called again with more output space
|
|
||||||
or more available input, which it will be in this code.
|
|
||||||
<pre><b>
|
|
||||||
ret = deflate(&strm, flush); /* no bad return value */
|
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
||||||
</b></pre>
|
|
||||||
Now we compute how much output <tt>deflate()</tt> provided on the last call, which is the
|
|
||||||
difference between how much space was provided before the call, and how much output space
|
|
||||||
is still available after the call. Then that data, if any, is written to the output file.
|
|
||||||
We can then reuse the output buffer for the next call of <tt>deflate()</tt>. Again if there
|
|
||||||
is a file i/o error, we call <tt>deflateEnd()</tt> before returning to avoid a memory leak.
|
|
||||||
<pre><b>
|
|
||||||
have = CHUNK - strm.avail_out;
|
|
||||||
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
||||||
(void)deflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
</b></pre>
|
|
||||||
The inner <tt>do</tt>-loop is repeated until the last <tt>deflate()</tt> call fails to fill the
|
|
||||||
provided output buffer. Then we know that <tt>deflate()</tt> has done as much as it can with
|
|
||||||
the provided input, and that all of that input has been consumed. We can then fall out of this
|
|
||||||
loop and reuse the input buffer.
|
|
||||||
<p>
|
|
||||||
The way we tell that <tt>deflate()</tt> has no more output is by seeing that it did not fill
|
|
||||||
the output buffer, leaving <tt>avail_out</tt> greater than zero. However suppose that
|
|
||||||
<tt>deflate()</tt> has no more output, but just so happened to exactly fill the output buffer!
|
|
||||||
<tt>avail_out</tt> is zero, and we can't tell that <tt>deflate()</tt> has done all it can.
|
|
||||||
As far as we know, <tt>deflate()</tt>
|
|
||||||
has more output for us. So we call it again. But now <tt>deflate()</tt> produces no output
|
|
||||||
at all, and <tt>avail_out</tt> remains unchanged as <tt>CHUNK</tt>. That <tt>deflate()</tt> call
|
|
||||||
wasn't able to do anything, either consume input or produce output, and so it returns
|
|
||||||
<tt>Z_BUF_ERROR</tt>. (See, I told you I'd cover this later.) However this is not a problem at
|
|
||||||
all. Now we finally have the desired indication that <tt>deflate()</tt> is really done,
|
|
||||||
and so we drop out of the inner loop to provide more input to <tt>deflate()</tt>.
|
|
||||||
<p>
|
|
||||||
With <tt>flush</tt> set to <tt>Z_FINISH</tt>, this final set of <tt>deflate()</tt> calls will
|
|
||||||
complete the output stream. Once that is done, subsequent calls of <tt>deflate()</tt> would return
|
|
||||||
<tt>Z_STREAM_ERROR</tt> if the flush parameter is not <tt>Z_FINISH</tt>, and do no more processing
|
|
||||||
until the state is reinitialized.
|
|
||||||
<p>
|
|
||||||
Some applications of <em>zlib</em> have two loops that call <tt>deflate()</tt>
|
|
||||||
instead of the single inner loop we have here. The first loop would call
|
|
||||||
without flushing and feed all of the data to <tt>deflate()</tt>. The second loop would call
|
|
||||||
<tt>deflate()</tt> with no more
|
|
||||||
data and the <tt>Z_FINISH</tt> parameter to complete the process. As you can see from this
|
|
||||||
example, that can be avoided by simply keeping track of the current flush state.
|
|
||||||
<pre><b>
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
assert(strm.avail_in == 0); /* all input will be used */
|
|
||||||
</b></pre><!-- -->
|
|
||||||
Now we check to see if we have already processed all of the input file. That information was
|
|
||||||
saved in the <tt>flush</tt> variable, so we see if that was set to <tt>Z_FINISH</tt>. If so,
|
|
||||||
then we're done and we fall out of the outer loop. We're guaranteed to get <tt>Z_STREAM_END</tt>
|
|
||||||
from the last <tt>deflate()</tt> call, since we ran it until the last chunk of input was
|
|
||||||
consumed and all of the output was generated.
|
|
||||||
<pre><b>
|
|
||||||
/* done when last data in file processed */
|
|
||||||
} while (flush != Z_FINISH);
|
|
||||||
assert(ret == Z_STREAM_END); /* stream will be complete */
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The process is complete, but we still need to deallocate the state to avoid a memory leak
|
|
||||||
(or rather more like a memory hemorrhage if you didn't do this). Then
|
|
||||||
finally we can return with a happy return value.
|
|
||||||
<pre><b>
|
|
||||||
/* clean up and return */
|
|
||||||
(void)deflateEnd(&strm);
|
|
||||||
return Z_OK;
|
|
||||||
}
|
|
||||||
</b></pre><!-- -->
|
|
||||||
Now we do the same thing for decompression in the <tt>inf()</tt> routine. <tt>inf()</tt>
|
|
||||||
decompresses what is hopefully a valid <em>zlib</em> stream from the input file and writes the
|
|
||||||
uncompressed data to the output file. Much of the discussion above for <tt>def()</tt>
|
|
||||||
applies to <tt>inf()</tt> as well, so the discussion here will focus on the differences between
|
|
||||||
the two.
|
|
||||||
<pre><b>
|
|
||||||
/* Decompress from file source to file dest until stream ends or EOF.
|
|
||||||
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
|
|
||||||
allocated for processing, Z_DATA_ERROR if the deflate data is
|
|
||||||
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
|
|
||||||
the version of the library linked do not match, or Z_ERRNO if there
|
|
||||||
is an error reading or writing the files. */
|
|
||||||
int inf(FILE *source, FILE *dest)
|
|
||||||
{
|
|
||||||
</b></pre>
|
|
||||||
The local variables have the same functionality as they do for <tt>def()</tt>. The
|
|
||||||
only difference is that there is no <tt>flush</tt> variable, since <tt>inflate()</tt>
|
|
||||||
can tell from the <em>zlib</em> stream itself when the stream is complete.
|
|
||||||
<pre><b>
|
|
||||||
int ret;
|
|
||||||
unsigned have;
|
|
||||||
z_stream strm;
|
|
||||||
unsigned char in[CHUNK];
|
|
||||||
unsigned char out[CHUNK];
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The initialization of the state is the same, except that there is no compression level,
|
|
||||||
of course, and two more elements of the structure are initialized. <tt>avail_in</tt>
|
|
||||||
and <tt>next_in</tt> must be initialized before calling <tt>inflateInit()</tt>. This
|
|
||||||
is because the application has the option to provide the start of the zlib stream in
|
|
||||||
order for <tt>inflateInit()</tt> to have access to information about the compression
|
|
||||||
method to aid in memory allocation. In the current implementation of <em>zlib</em>
|
|
||||||
(up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of
|
|
||||||
<tt>inflate()</tt> anyway. However those fields must be initialized since later versions
|
|
||||||
of <em>zlib</em> that provide more compression methods may take advantage of this interface.
|
|
||||||
In any case, no decompression is performed by <tt>inflateInit()</tt>, so the
|
|
||||||
<tt>avail_out</tt> and <tt>next_out</tt> fields do not need to be initialized before calling.
|
|
||||||
<p>
|
|
||||||
Here <tt>avail_in</tt> is set to zero and <tt>next_in</tt> is set to <tt>Z_NULL</tt> to
|
|
||||||
indicate that no input data is being provided.
|
|
||||||
<pre><b>
|
|
||||||
/* allocate inflate state */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = 0;
|
|
||||||
strm.next_in = Z_NULL;
|
|
||||||
ret = inflateInit(&strm);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The outer <tt>do</tt>-loop decompresses input until <tt>inflate()</tt> indicates
|
|
||||||
that it has reached the end of the compressed data and has produced all of the uncompressed
|
|
||||||
output. This is in contrast to <tt>def()</tt> which processes all of the input file.
|
|
||||||
If end-of-file is reached before the compressed data self-terminates, then the compressed
|
|
||||||
data is incomplete and an error is returned.
|
|
||||||
<pre><b>
|
|
||||||
/* decompress until deflate stream ends or end of file */
|
|
||||||
do {
|
|
||||||
</b></pre>
|
|
||||||
We read input data and set the <tt>strm</tt> structure accordingly. If we've reached the
|
|
||||||
end of the input file, then we leave the outer loop and report an error, since the
|
|
||||||
compressed data is incomplete. Note that we may read more data than is eventually consumed
|
|
||||||
by <tt>inflate()</tt>, if the input file continues past the <em>zlib</em> stream.
|
|
||||||
For applications where <em>zlib</em> streams are embedded in other data, this routine would
|
|
||||||
need to be modified to return the unused data, or at least indicate how much of the input
|
|
||||||
data was not used, so the application would know where to pick up after the <em>zlib</em> stream.
|
|
||||||
<pre><b>
|
|
||||||
strm.avail_in = fread(in, 1, CHUNK, source);
|
|
||||||
if (ferror(source)) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
if (strm.avail_in == 0)
|
|
||||||
break;
|
|
||||||
strm.next_in = in;
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The inner <tt>do</tt>-loop has the same function it did in <tt>def()</tt>, which is to
|
|
||||||
keep calling <tt>inflate()</tt> until has generated all of the output it can with the
|
|
||||||
provided input.
|
|
||||||
<pre><b>
|
|
||||||
/* run inflate() on input until output buffer not full */
|
|
||||||
do {
|
|
||||||
</b></pre>
|
|
||||||
Just like in <tt>def()</tt>, the same output space is provided for each call of <tt>inflate()</tt>.
|
|
||||||
<pre><b>
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = out;
|
|
||||||
</b></pre>
|
|
||||||
Now we run the decompression engine itself. There is no need to adjust the flush parameter, since
|
|
||||||
the <em>zlib</em> format is self-terminating. The main difference here is that there are
|
|
||||||
return values that we need to pay attention to. <tt>Z_DATA_ERROR</tt>
|
|
||||||
indicates that <tt>inflate()</tt> detected an error in the <em>zlib</em> compressed data format,
|
|
||||||
which means that either the data is not a <em>zlib</em> stream to begin with, or that the data was
|
|
||||||
corrupted somewhere along the way since it was compressed. The other error to be processed is
|
|
||||||
<tt>Z_MEM_ERROR</tt>, which can occur since memory allocation is deferred until <tt>inflate()</tt>
|
|
||||||
needs it, unlike <tt>deflate()</tt>, whose memory is allocated at the start by <tt>deflateInit()</tt>.
|
|
||||||
<p>
|
|
||||||
Advanced applications may use
|
|
||||||
<tt>deflateSetDictionary()</tt> to prime <tt>deflate()</tt> with a set of likely data to improve the
|
|
||||||
first 32K or so of compression. This is noted in the <em>zlib</em> header, so <tt>inflate()</tt>
|
|
||||||
requests that that dictionary be provided before it can start to decompress. Without the dictionary,
|
|
||||||
correct decompression is not possible. For this routine, we have no idea what the dictionary is,
|
|
||||||
so the <tt>Z_NEED_DICT</tt> indication is converted to a <tt>Z_DATA_ERROR</tt>.
|
|
||||||
<p>
|
|
||||||
<tt>inflate()</tt> can also return <tt>Z_STREAM_ERROR</tt>, which should not be possible here,
|
|
||||||
but could be checked for as noted above for <tt>def()</tt>. <tt>Z_BUF_ERROR</tt> does not need to be
|
|
||||||
checked for here, for the same reasons noted for <tt>def()</tt>. <tt>Z_STREAM_END</tt> will be
|
|
||||||
checked for later.
|
|
||||||
<pre><b>
|
|
||||||
ret = inflate(&strm, Z_NO_FLUSH);
|
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
||||||
switch (ret) {
|
|
||||||
case Z_NEED_DICT:
|
|
||||||
ret = Z_DATA_ERROR; /* and fall through */
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
</b></pre>
|
|
||||||
The output of <tt>inflate()</tt> is handled identically to that of <tt>deflate()</tt>.
|
|
||||||
<pre><b>
|
|
||||||
have = CHUNK - strm.avail_out;
|
|
||||||
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
</b></pre>
|
|
||||||
The inner <tt>do</tt>-loop ends when <tt>inflate()</tt> has no more output as indicated
|
|
||||||
by not filling the output buffer, just as for <tt>deflate()</tt>. In this case, we cannot
|
|
||||||
assert that <tt>strm.avail_in</tt> will be zero, since the deflate stream may end before the file
|
|
||||||
does.
|
|
||||||
<pre><b>
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
</b></pre><!-- -->
|
|
||||||
The outer <tt>do</tt>-loop ends when <tt>inflate()</tt> reports that it has reached the
|
|
||||||
end of the input <em>zlib</em> stream, has completed the decompression and integrity
|
|
||||||
check, and has provided all of the output. This is indicated by the <tt>inflate()</tt>
|
|
||||||
return value <tt>Z_STREAM_END</tt>. The inner loop is guaranteed to leave <tt>ret</tt>
|
|
||||||
equal to <tt>Z_STREAM_END</tt> if the last chunk of the input file read contained the end
|
|
||||||
of the <em>zlib</em> stream. So if the return value is not <tt>Z_STREAM_END</tt>, the
|
|
||||||
loop continues to read more input.
|
|
||||||
<pre><b>
|
|
||||||
/* done when inflate() says it's done */
|
|
||||||
} while (ret != Z_STREAM_END);
|
|
||||||
</b></pre><!-- -->
|
|
||||||
At this point, decompression successfully completed, or we broke out of the loop due to no
|
|
||||||
more data being available from the input file. If the last <tt>inflate()</tt> return value
|
|
||||||
is not <tt>Z_STREAM_END</tt>, then the <em>zlib</em> stream was incomplete and a data error
|
|
||||||
is returned. Otherwise, we return with a happy return value. Of course, <tt>inflateEnd()</tt>
|
|
||||||
is called first to avoid a memory leak.
|
|
||||||
<pre><b>
|
|
||||||
/* clean up and return */
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
</b></pre><!-- -->
|
|
||||||
That ends the routines that directly use <em>zlib</em>. The following routines make this
|
|
||||||
a command-line program by running data through the above routines from <tt>stdin</tt> to
|
|
||||||
<tt>stdout</tt>, and handling any errors reported by <tt>def()</tt> or <tt>inf()</tt>.
|
|
||||||
<p>
|
|
||||||
<tt>zerr()</tt> is used to interpret the possible error codes from <tt>def()</tt>
|
|
||||||
and <tt>inf()</tt>, as detailed in their comments above, and print out an error message.
|
|
||||||
Note that these are only a subset of the possible return values from <tt>deflate()</tt>
|
|
||||||
and <tt>inflate()</tt>.
|
|
||||||
<pre><b>
|
|
||||||
/* report a zlib or i/o error */
|
|
||||||
void zerr(int ret)
|
|
||||||
{
|
|
||||||
fputs("zpipe: ", stderr);
|
|
||||||
switch (ret) {
|
|
||||||
case Z_ERRNO:
|
|
||||||
if (ferror(stdin))
|
|
||||||
fputs("error reading stdin\n", stderr);
|
|
||||||
if (ferror(stdout))
|
|
||||||
fputs("error writing stdout\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_STREAM_ERROR:
|
|
||||||
fputs("invalid compression level\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
fputs("invalid or incomplete deflate data\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
fputs("out of memory\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_VERSION_ERROR:
|
|
||||||
fputs("zlib version mismatch!\n", stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</b></pre><!-- -->
|
|
||||||
Here is the <tt>main()</tt> routine used to test <tt>def()</tt> and <tt>inf()</tt>. The
|
|
||||||
<tt>zpipe</tt> command is simply a compression pipe from <tt>stdin</tt> to <tt>stdout</tt>, if
|
|
||||||
no arguments are given, or it is a decompression pipe if <tt>zpipe -d</tt> is used. If any other
|
|
||||||
arguments are provided, no compression or decompression is performed. Instead a usage
|
|
||||||
message is displayed. Examples are <tt>zpipe < foo.txt > foo.txt.z</tt> to compress, and
|
|
||||||
<tt>zpipe -d < foo.txt.z > foo.txt</tt> to decompress.
|
|
||||||
<pre><b>
|
|
||||||
/* compress or decompress from stdin to stdout */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* avoid end-of-line conversions */
|
|
||||||
SET_BINARY_MODE(stdin);
|
|
||||||
SET_BINARY_MODE(stdout);
|
|
||||||
|
|
||||||
/* do compression if no arguments */
|
|
||||||
if (argc == 1) {
|
|
||||||
ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
zerr(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do decompression if -d specified */
|
|
||||||
else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
|
|
||||||
ret = inf(stdin, stdout);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
zerr(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* otherwise, report usage */
|
|
||||||
else {
|
|
||||||
fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</b></pre>
|
|
||||||
<hr>
|
|
||||||
<i>Copyright (c) 2004, 2005 by Mark Adler<br>Last modified 11 December 2005</i>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,205 +0,0 @@
|
||||||
/* zpipe.c: example of proper use of zlib's inflate() and deflate()
|
|
||||||
Not copyrighted -- provided to the public domain
|
|
||||||
Version 1.4 11 December 2005 Mark Adler */
|
|
||||||
|
|
||||||
/* Version history:
|
|
||||||
1.0 30 Oct 2004 First version
|
|
||||||
1.1 8 Nov 2004 Add void casting for unused return values
|
|
||||||
Use switch statement for inflate() return values
|
|
||||||
1.2 9 Nov 2004 Add assertions to document zlib guarantees
|
|
||||||
1.3 6 Apr 2005 Remove incorrect assertion in inf()
|
|
||||||
1.4 11 Dec 2005 Add hack to avoid MSDOS end-of-line conversions
|
|
||||||
Avoid some compiler warnings for input and output buffers
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include "zlib.h"
|
|
||||||
|
|
||||||
#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
|
|
||||||
# include <fcntl.h>
|
|
||||||
# include <io.h>
|
|
||||||
# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
|
|
||||||
#else
|
|
||||||
# define SET_BINARY_MODE(file)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CHUNK 16384
|
|
||||||
|
|
||||||
/* Compress from file source to file dest until EOF on source.
|
|
||||||
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
|
|
||||||
allocated for processing, Z_STREAM_ERROR if an invalid compression
|
|
||||||
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
|
|
||||||
version of the library linked do not match, or Z_ERRNO if there is
|
|
||||||
an error reading or writing the files. */
|
|
||||||
int def(FILE *source, FILE *dest, int level)
|
|
||||||
{
|
|
||||||
int ret, flush;
|
|
||||||
unsigned have;
|
|
||||||
z_stream strm;
|
|
||||||
unsigned char in[CHUNK];
|
|
||||||
unsigned char out[CHUNK];
|
|
||||||
|
|
||||||
/* allocate deflate state */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
ret = deflateInit(&strm, level);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* compress until end of file */
|
|
||||||
do {
|
|
||||||
strm.avail_in = fread(in, 1, CHUNK, source);
|
|
||||||
if (ferror(source)) {
|
|
||||||
(void)deflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
|
|
||||||
strm.next_in = in;
|
|
||||||
|
|
||||||
/* run deflate() on input until output buffer not full, finish
|
|
||||||
compression if all of source has been read in */
|
|
||||||
do {
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = out;
|
|
||||||
ret = deflate(&strm, flush); /* no bad return value */
|
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
||||||
have = CHUNK - strm.avail_out;
|
|
||||||
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
||||||
(void)deflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
assert(strm.avail_in == 0); /* all input will be used */
|
|
||||||
|
|
||||||
/* done when last data in file processed */
|
|
||||||
} while (flush != Z_FINISH);
|
|
||||||
assert(ret == Z_STREAM_END); /* stream will be complete */
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
(void)deflateEnd(&strm);
|
|
||||||
return Z_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Decompress from file source to file dest until stream ends or EOF.
|
|
||||||
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
|
|
||||||
allocated for processing, Z_DATA_ERROR if the deflate data is
|
|
||||||
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
|
|
||||||
the version of the library linked do not match, or Z_ERRNO if there
|
|
||||||
is an error reading or writing the files. */
|
|
||||||
int inf(FILE *source, FILE *dest)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned have;
|
|
||||||
z_stream strm;
|
|
||||||
unsigned char in[CHUNK];
|
|
||||||
unsigned char out[CHUNK];
|
|
||||||
|
|
||||||
/* allocate inflate state */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = 0;
|
|
||||||
strm.next_in = Z_NULL;
|
|
||||||
ret = inflateInit(&strm);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* decompress until deflate stream ends or end of file */
|
|
||||||
do {
|
|
||||||
strm.avail_in = fread(in, 1, CHUNK, source);
|
|
||||||
if (ferror(source)) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
if (strm.avail_in == 0)
|
|
||||||
break;
|
|
||||||
strm.next_in = in;
|
|
||||||
|
|
||||||
/* run inflate() on input until output buffer not full */
|
|
||||||
do {
|
|
||||||
strm.avail_out = CHUNK;
|
|
||||||
strm.next_out = out;
|
|
||||||
ret = inflate(&strm, Z_NO_FLUSH);
|
|
||||||
assert(ret != Z_STREAM_ERROR); /* state not clobbered */
|
|
||||||
switch (ret) {
|
|
||||||
case Z_NEED_DICT:
|
|
||||||
ret = Z_DATA_ERROR; /* and fall through */
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
have = CHUNK - strm.avail_out;
|
|
||||||
if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return Z_ERRNO;
|
|
||||||
}
|
|
||||||
} while (strm.avail_out == 0);
|
|
||||||
|
|
||||||
/* done when inflate() says it's done */
|
|
||||||
} while (ret != Z_STREAM_END);
|
|
||||||
|
|
||||||
/* clean up and return */
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* report a zlib or i/o error */
|
|
||||||
void zerr(int ret)
|
|
||||||
{
|
|
||||||
fputs("zpipe: ", stderr);
|
|
||||||
switch (ret) {
|
|
||||||
case Z_ERRNO:
|
|
||||||
if (ferror(stdin))
|
|
||||||
fputs("error reading stdin\n", stderr);
|
|
||||||
if (ferror(stdout))
|
|
||||||
fputs("error writing stdout\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_STREAM_ERROR:
|
|
||||||
fputs("invalid compression level\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
fputs("invalid or incomplete deflate data\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
fputs("out of memory\n", stderr);
|
|
||||||
break;
|
|
||||||
case Z_VERSION_ERROR:
|
|
||||||
fputs("zlib version mismatch!\n", stderr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* compress or decompress from stdin to stdout */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* avoid end-of-line conversions */
|
|
||||||
SET_BINARY_MODE(stdin);
|
|
||||||
SET_BINARY_MODE(stdout);
|
|
||||||
|
|
||||||
/* do compression if no arguments */
|
|
||||||
if (argc == 1) {
|
|
||||||
ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
zerr(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* do decompression if -d specified */
|
|
||||||
else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
|
|
||||||
ret = inf(stdin, stdout);
|
|
||||||
if (ret != Z_OK)
|
|
||||||
zerr(ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* otherwise, report usage */
|
|
||||||
else {
|
|
||||||
fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,409 +0,0 @@
|
||||||
/* zran.c -- example of zlib/gzip stream indexing and random access
|
|
||||||
* Copyright (C) 2005, 2012 Mark Adler
|
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
|
||||||
Version 1.1 29 Sep 2012 Mark Adler */
|
|
||||||
|
|
||||||
/* Version History:
|
|
||||||
1.0 29 May 2005 First version
|
|
||||||
1.1 29 Sep 2012 Fix memory reallocation error
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Illustrate the use of Z_BLOCK, inflatePrime(), and inflateSetDictionary()
|
|
||||||
for random access of a compressed file. A file containing a zlib or gzip
|
|
||||||
stream is provided on the command line. The compressed stream is decoded in
|
|
||||||
its entirety, and an index built with access points about every SPAN bytes
|
|
||||||
in the uncompressed output. The compressed file is left open, and can then
|
|
||||||
be read randomly, having to decompress on the average SPAN/2 uncompressed
|
|
||||||
bytes before getting to the desired block of data.
|
|
||||||
|
|
||||||
An access point can be created at the start of any deflate block, by saving
|
|
||||||
the starting file offset and bit of that block, and the 32K bytes of
|
|
||||||
uncompressed data that precede that block. Also the uncompressed offset of
|
|
||||||
that block is saved to provide a referece for locating a desired starting
|
|
||||||
point in the uncompressed stream. build_index() works by decompressing the
|
|
||||||
input zlib or gzip stream a block at a time, and at the end of each block
|
|
||||||
deciding if enough uncompressed data has gone by to justify the creation of
|
|
||||||
a new access point. If so, that point is saved in a data structure that
|
|
||||||
grows as needed to accommodate the points.
|
|
||||||
|
|
||||||
To use the index, an offset in the uncompressed data is provided, for which
|
|
||||||
the latest access point at or preceding that offset is located in the index.
|
|
||||||
The input file is positioned to the specified location in the index, and if
|
|
||||||
necessary the first few bits of the compressed data is read from the file.
|
|
||||||
inflate is initialized with those bits and the 32K of uncompressed data, and
|
|
||||||
the decompression then proceeds until the desired offset in the file is
|
|
||||||
reached. Then the decompression continues to read the desired uncompressed
|
|
||||||
data from the file.
|
|
||||||
|
|
||||||
Another approach would be to generate the index on demand. In that case,
|
|
||||||
requests for random access reads from the compressed data would try to use
|
|
||||||
the index, but if a read far enough past the end of the index is required,
|
|
||||||
then further index entries would be generated and added.
|
|
||||||
|
|
||||||
There is some fair bit of overhead to starting inflation for the random
|
|
||||||
access, mainly copying the 32K byte dictionary. So if small pieces of the
|
|
||||||
file are being accessed, it would make sense to implement a cache to hold
|
|
||||||
some lookahead and avoid many calls to extract() for small lengths.
|
|
||||||
|
|
||||||
Another way to build an index would be to use inflateCopy(). That would
|
|
||||||
not be constrained to have access points at block boundaries, but requires
|
|
||||||
more memory per access point, and also cannot be saved to file due to the
|
|
||||||
use of pointers in the state. The approach here allows for storage of the
|
|
||||||
index in a file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include "zlib.h"
|
|
||||||
|
|
||||||
#define local static
|
|
||||||
|
|
||||||
#define SPAN 1048576L /* desired distance between access points */
|
|
||||||
#define WINSIZE 32768U /* sliding window size */
|
|
||||||
#define CHUNK 16384 /* file input buffer size */
|
|
||||||
|
|
||||||
/* access point entry */
|
|
||||||
struct point {
|
|
||||||
off_t out; /* corresponding offset in uncompressed data */
|
|
||||||
off_t in; /* offset in input file of first full byte */
|
|
||||||
int bits; /* number of bits (1-7) from byte at in - 1, or 0 */
|
|
||||||
unsigned char window[WINSIZE]; /* preceding 32K of uncompressed data */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* access point list */
|
|
||||||
struct access {
|
|
||||||
int have; /* number of list entries filled in */
|
|
||||||
int size; /* number of list entries allocated */
|
|
||||||
struct point *list; /* allocated list */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Deallocate an index built by build_index() */
|
|
||||||
local void free_index(struct access *index)
|
|
||||||
{
|
|
||||||
if (index != NULL) {
|
|
||||||
free(index->list);
|
|
||||||
free(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Add an entry to the access point list. If out of memory, deallocate the
|
|
||||||
existing list and return NULL. */
|
|
||||||
local struct access *addpoint(struct access *index, int bits,
|
|
||||||
off_t in, off_t out, unsigned left, unsigned char *window)
|
|
||||||
{
|
|
||||||
struct point *next;
|
|
||||||
|
|
||||||
/* if list is empty, create it (start with eight points) */
|
|
||||||
if (index == NULL) {
|
|
||||||
index = malloc(sizeof(struct access));
|
|
||||||
if (index == NULL) return NULL;
|
|
||||||
index->list = malloc(sizeof(struct point) << 3);
|
|
||||||
if (index->list == NULL) {
|
|
||||||
free(index);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
index->size = 8;
|
|
||||||
index->have = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if list is full, make it bigger */
|
|
||||||
else if (index->have == index->size) {
|
|
||||||
index->size <<= 1;
|
|
||||||
next = realloc(index->list, sizeof(struct point) * index->size);
|
|
||||||
if (next == NULL) {
|
|
||||||
free_index(index);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
index->list = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fill in entry and increment how many we have */
|
|
||||||
next = index->list + index->have;
|
|
||||||
next->bits = bits;
|
|
||||||
next->in = in;
|
|
||||||
next->out = out;
|
|
||||||
if (left)
|
|
||||||
memcpy(next->window, window + WINSIZE - left, left);
|
|
||||||
if (left < WINSIZE)
|
|
||||||
memcpy(next->window + left, window, WINSIZE - left);
|
|
||||||
index->have++;
|
|
||||||
|
|
||||||
/* return list, possibly reallocated */
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make one entire pass through the compressed stream and build an index, with
|
|
||||||
access points about every span bytes of uncompressed output -- span is
|
|
||||||
chosen to balance the speed of random access against the memory requirements
|
|
||||||
of the list, about 32K bytes per access point. Note that data after the end
|
|
||||||
of the first zlib or gzip stream in the file is ignored. build_index()
|
|
||||||
returns the number of access points on success (>= 1), Z_MEM_ERROR for out
|
|
||||||
of memory, Z_DATA_ERROR for an error in the input file, or Z_ERRNO for a
|
|
||||||
file read error. On success, *built points to the resulting index. */
|
|
||||||
local int build_index(FILE *in, off_t span, struct access **built)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
off_t totin, totout; /* our own total counters to avoid 4GB limit */
|
|
||||||
off_t last; /* totout value of last access point */
|
|
||||||
struct access *index; /* access points being generated */
|
|
||||||
z_stream strm;
|
|
||||||
unsigned char input[CHUNK];
|
|
||||||
unsigned char window[WINSIZE];
|
|
||||||
|
|
||||||
/* initialize inflate */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = 0;
|
|
||||||
strm.next_in = Z_NULL;
|
|
||||||
ret = inflateInit2(&strm, 47); /* automatic zlib or gzip decoding */
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
/* inflate the input, maintain a sliding window, and build an index -- this
|
|
||||||
also validates the integrity of the compressed data using the check
|
|
||||||
information at the end of the gzip or zlib stream */
|
|
||||||
totin = totout = last = 0;
|
|
||||||
index = NULL; /* will be allocated by first addpoint() */
|
|
||||||
strm.avail_out = 0;
|
|
||||||
do {
|
|
||||||
/* get some compressed data from input file */
|
|
||||||
strm.avail_in = fread(input, 1, CHUNK, in);
|
|
||||||
if (ferror(in)) {
|
|
||||||
ret = Z_ERRNO;
|
|
||||||
goto build_index_error;
|
|
||||||
}
|
|
||||||
if (strm.avail_in == 0) {
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
goto build_index_error;
|
|
||||||
}
|
|
||||||
strm.next_in = input;
|
|
||||||
|
|
||||||
/* process all of that, or until end of stream */
|
|
||||||
do {
|
|
||||||
/* reset sliding window if necessary */
|
|
||||||
if (strm.avail_out == 0) {
|
|
||||||
strm.avail_out = WINSIZE;
|
|
||||||
strm.next_out = window;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* inflate until out of input, output, or at end of block --
|
|
||||||
update the total input and output counters */
|
|
||||||
totin += strm.avail_in;
|
|
||||||
totout += strm.avail_out;
|
|
||||||
ret = inflate(&strm, Z_BLOCK); /* return at end of block */
|
|
||||||
totin -= strm.avail_in;
|
|
||||||
totout -= strm.avail_out;
|
|
||||||
if (ret == Z_NEED_DICT)
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
|
|
||||||
goto build_index_error;
|
|
||||||
if (ret == Z_STREAM_END)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* if at end of block, consider adding an index entry (note that if
|
|
||||||
data_type indicates an end-of-block, then all of the
|
|
||||||
uncompressed data from that block has been delivered, and none
|
|
||||||
of the compressed data after that block has been consumed,
|
|
||||||
except for up to seven bits) -- the totout == 0 provides an
|
|
||||||
entry point after the zlib or gzip header, and assures that the
|
|
||||||
index always has at least one access point; we avoid creating an
|
|
||||||
access point after the last block by checking bit 6 of data_type
|
|
||||||
*/
|
|
||||||
if ((strm.data_type & 128) && !(strm.data_type & 64) &&
|
|
||||||
(totout == 0 || totout - last > span)) {
|
|
||||||
index = addpoint(index, strm.data_type & 7, totin,
|
|
||||||
totout, strm.avail_out, window);
|
|
||||||
if (index == NULL) {
|
|
||||||
ret = Z_MEM_ERROR;
|
|
||||||
goto build_index_error;
|
|
||||||
}
|
|
||||||
last = totout;
|
|
||||||
}
|
|
||||||
} while (strm.avail_in != 0);
|
|
||||||
} while (ret != Z_STREAM_END);
|
|
||||||
|
|
||||||
/* clean up and return index (release unused entries in list) */
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
index->list = realloc(index->list, sizeof(struct point) * index->have);
|
|
||||||
index->size = index->have;
|
|
||||||
*built = index;
|
|
||||||
return index->size;
|
|
||||||
|
|
||||||
/* return error */
|
|
||||||
build_index_error:
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
if (index != NULL)
|
|
||||||
free_index(index);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Use the index to read len bytes from offset into buf, return bytes read or
|
|
||||||
negative for error (Z_DATA_ERROR or Z_MEM_ERROR). If data is requested past
|
|
||||||
the end of the uncompressed data, then extract() will return a value less
|
|
||||||
than len, indicating how much as actually read into buf. This function
|
|
||||||
should not return a data error unless the file was modified since the index
|
|
||||||
was generated. extract() may also return Z_ERRNO if there is an error on
|
|
||||||
reading or seeking the input file. */
|
|
||||||
local int extract(FILE *in, struct access *index, off_t offset,
|
|
||||||
unsigned char *buf, int len)
|
|
||||||
{
|
|
||||||
int ret, skip;
|
|
||||||
z_stream strm;
|
|
||||||
struct point *here;
|
|
||||||
unsigned char input[CHUNK];
|
|
||||||
unsigned char discard[WINSIZE];
|
|
||||||
|
|
||||||
/* proceed only if something reasonable to do */
|
|
||||||
if (len < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* find where in stream to start */
|
|
||||||
here = index->list;
|
|
||||||
ret = index->have;
|
|
||||||
while (--ret && here[1].out <= offset)
|
|
||||||
here++;
|
|
||||||
|
|
||||||
/* initialize file and inflate state to start there */
|
|
||||||
strm.zalloc = Z_NULL;
|
|
||||||
strm.zfree = Z_NULL;
|
|
||||||
strm.opaque = Z_NULL;
|
|
||||||
strm.avail_in = 0;
|
|
||||||
strm.next_in = Z_NULL;
|
|
||||||
ret = inflateInit2(&strm, -15); /* raw inflate */
|
|
||||||
if (ret != Z_OK)
|
|
||||||
return ret;
|
|
||||||
ret = fseeko(in, here->in - (here->bits ? 1 : 0), SEEK_SET);
|
|
||||||
if (ret == -1)
|
|
||||||
goto extract_ret;
|
|
||||||
if (here->bits) {
|
|
||||||
ret = getc(in);
|
|
||||||
if (ret == -1) {
|
|
||||||
ret = ferror(in) ? Z_ERRNO : Z_DATA_ERROR;
|
|
||||||
goto extract_ret;
|
|
||||||
}
|
|
||||||
(void)inflatePrime(&strm, here->bits, ret >> (8 - here->bits));
|
|
||||||
}
|
|
||||||
(void)inflateSetDictionary(&strm, here->window, WINSIZE);
|
|
||||||
|
|
||||||
/* skip uncompressed bytes until offset reached, then satisfy request */
|
|
||||||
offset -= here->out;
|
|
||||||
strm.avail_in = 0;
|
|
||||||
skip = 1; /* while skipping to offset */
|
|
||||||
do {
|
|
||||||
/* define where to put uncompressed data, and how much */
|
|
||||||
if (offset == 0 && skip) { /* at offset now */
|
|
||||||
strm.avail_out = len;
|
|
||||||
strm.next_out = buf;
|
|
||||||
skip = 0; /* only do this once */
|
|
||||||
}
|
|
||||||
if (offset > WINSIZE) { /* skip WINSIZE bytes */
|
|
||||||
strm.avail_out = WINSIZE;
|
|
||||||
strm.next_out = discard;
|
|
||||||
offset -= WINSIZE;
|
|
||||||
}
|
|
||||||
else if (offset != 0) { /* last skip */
|
|
||||||
strm.avail_out = (unsigned)offset;
|
|
||||||
strm.next_out = discard;
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* uncompress until avail_out filled, or end of stream */
|
|
||||||
do {
|
|
||||||
if (strm.avail_in == 0) {
|
|
||||||
strm.avail_in = fread(input, 1, CHUNK, in);
|
|
||||||
if (ferror(in)) {
|
|
||||||
ret = Z_ERRNO;
|
|
||||||
goto extract_ret;
|
|
||||||
}
|
|
||||||
if (strm.avail_in == 0) {
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
goto extract_ret;
|
|
||||||
}
|
|
||||||
strm.next_in = input;
|
|
||||||
}
|
|
||||||
ret = inflate(&strm, Z_NO_FLUSH); /* normal inflate */
|
|
||||||
if (ret == Z_NEED_DICT)
|
|
||||||
ret = Z_DATA_ERROR;
|
|
||||||
if (ret == Z_MEM_ERROR || ret == Z_DATA_ERROR)
|
|
||||||
goto extract_ret;
|
|
||||||
if (ret == Z_STREAM_END)
|
|
||||||
break;
|
|
||||||
} while (strm.avail_out != 0);
|
|
||||||
|
|
||||||
/* if reach end of stream, then don't keep trying to get more */
|
|
||||||
if (ret == Z_STREAM_END)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* do until offset reached and requested data read, or stream ends */
|
|
||||||
} while (skip);
|
|
||||||
|
|
||||||
/* compute number of uncompressed bytes read after offset */
|
|
||||||
ret = skip ? 0 : len - strm.avail_out;
|
|
||||||
|
|
||||||
/* clean up and return bytes read or error */
|
|
||||||
extract_ret:
|
|
||||||
(void)inflateEnd(&strm);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Demonstrate the use of build_index() and extract() by processing the file
|
|
||||||
provided on the command line, and the extracting 16K from about 2/3rds of
|
|
||||||
the way through the uncompressed output, and writing that to stdout. */
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int len;
|
|
||||||
off_t offset;
|
|
||||||
FILE *in;
|
|
||||||
struct access *index = NULL;
|
|
||||||
unsigned char buf[CHUNK];
|
|
||||||
|
|
||||||
/* open input file */
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "usage: zran file.gz\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
in = fopen(argv[1], "rb");
|
|
||||||
if (in == NULL) {
|
|
||||||
fprintf(stderr, "zran: could not open %s for reading\n", argv[1]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* build index */
|
|
||||||
len = build_index(in, SPAN, &index);
|
|
||||||
if (len < 0) {
|
|
||||||
fclose(in);
|
|
||||||
switch (len) {
|
|
||||||
case Z_MEM_ERROR:
|
|
||||||
fprintf(stderr, "zran: out of memory\n");
|
|
||||||
break;
|
|
||||||
case Z_DATA_ERROR:
|
|
||||||
fprintf(stderr, "zran: compressed data error in %s\n", argv[1]);
|
|
||||||
break;
|
|
||||||
case Z_ERRNO:
|
|
||||||
fprintf(stderr, "zran: read error on %s\n", argv[1]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(stderr, "zran: error %d while building index\n", len);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
fprintf(stderr, "zran: built index with %d access points\n", len);
|
|
||||||
|
|
||||||
/* use index by reading some bytes from an arbitrary offset */
|
|
||||||
offset = (index->list[index->have - 1].out << 1) / 3;
|
|
||||||
len = extract(in, index, offset, buf, CHUNK);
|
|
||||||
if (len < 0)
|
|
||||||
fprintf(stderr, "zran: extraction failed: %s error\n",
|
|
||||||
len == Z_MEM_ERROR ? "out of memory" : "input corrupted");
|
|
||||||
else {
|
|
||||||
fwrite(buf, 1, len, stdout);
|
|
||||||
fprintf(stderr, "zran: extracted %d bytes at %llu\n", len, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clean up and exit */
|
|
||||||
free_index(index);
|
|
||||||
fclose(in);
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -8,9 +8,7 @@
|
||||||
/* gzclose() is in a separate file so that it is linked in only if it is used.
|
/* gzclose() is in a separate file so that it is linked in only if it is used.
|
||||||
That way the other gzclose functions can be used instead to avoid linking in
|
That way the other gzclose functions can be used instead to avoid linking in
|
||||||
unneeded compression or decompression routines. */
|
unneeded compression or decompression routines. */
|
||||||
int ZEXPORT gzclose(file)
|
int ZEXPORT gzclose(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
#ifndef NO_GZCOMPRESS
|
#ifndef NO_GZCOMPRESS
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* gzguts.h -- zlib internal header definitions for gz* operations
|
/* gzguts.h -- zlib internal header definitions for gz* operations
|
||||||
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
|
* Copyright (C) 2004-2019 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -7,9 +7,8 @@
|
||||||
# ifndef _LARGEFILE_SOURCE
|
# ifndef _LARGEFILE_SOURCE
|
||||||
# define _LARGEFILE_SOURCE 1
|
# define _LARGEFILE_SOURCE 1
|
||||||
# endif
|
# endif
|
||||||
# ifdef _FILE_OFFSET_BITS
|
# undef _FILE_OFFSET_BITS
|
||||||
# undef _FILE_OFFSET_BITS
|
# undef _TIME_BITS
|
||||||
# endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_HIDDEN
|
#ifdef HAVE_HIDDEN
|
||||||
|
@ -39,7 +38,7 @@
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32)
|
||||||
# define WIDECHAR
|
# define WIDECHAR
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -119,8 +118,8 @@
|
||||||
|
|
||||||
/* gz* functions always use library allocation functions */
|
/* gz* functions always use library allocation functions */
|
||||||
#ifndef STDC
|
#ifndef STDC
|
||||||
extern voidp malloc OF((uInt size));
|
extern voidp malloc(uInt size);
|
||||||
extern void free OF((voidpf ptr));
|
extern void free(voidpf ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* get errno and strerror definition */
|
/* get errno and strerror definition */
|
||||||
|
@ -138,10 +137,10 @@
|
||||||
|
|
||||||
/* provide prototypes for these when building zlib without LFS */
|
/* provide prototypes for these when building zlib without LFS */
|
||||||
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
|
#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0
|
||||||
ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
|
ZEXTERN gzFile ZEXPORT gzopen64(const char *, const char *);
|
||||||
ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
|
ZEXTERN z_off64_t ZEXPORT gzseek64(gzFile, z_off64_t, int);
|
||||||
ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
|
ZEXTERN z_off64_t ZEXPORT gztell64(gzFile);
|
||||||
ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
|
ZEXTERN z_off64_t ZEXPORT gzoffset64(gzFile);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* default memLevel */
|
/* default memLevel */
|
||||||
|
@ -190,6 +189,7 @@ typedef struct {
|
||||||
/* just for writing */
|
/* just for writing */
|
||||||
int level; /* compression level */
|
int level; /* compression level */
|
||||||
int strategy; /* compression strategy */
|
int strategy; /* compression strategy */
|
||||||
|
int reset; /* true if a reset is pending after a Z_FINISH */
|
||||||
/* seek request */
|
/* seek request */
|
||||||
z_off64_t skip; /* amount to skip (already rewound if backwards) */
|
z_off64_t skip; /* amount to skip (already rewound if backwards) */
|
||||||
int seek; /* true if seek request pending */
|
int seek; /* true if seek request pending */
|
||||||
|
@ -202,9 +202,9 @@ typedef struct {
|
||||||
typedef gz_state FAR *gz_statep;
|
typedef gz_state FAR *gz_statep;
|
||||||
|
|
||||||
/* shared functions */
|
/* shared functions */
|
||||||
void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *));
|
void ZLIB_INTERNAL gz_error(gz_statep, int, const char *);
|
||||||
#if defined UNDER_CE
|
#if defined UNDER_CE
|
||||||
char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
|
char ZLIB_INTERNAL *gz_strwinerror(DWORD error);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
|
/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t
|
||||||
|
@ -213,6 +213,6 @@ char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error));
|
||||||
#ifdef INT_MAX
|
#ifdef INT_MAX
|
||||||
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
|
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX)
|
||||||
#else
|
#else
|
||||||
unsigned ZLIB_INTERNAL gz_intmax OF((void));
|
unsigned ZLIB_INTERNAL gz_intmax(void);
|
||||||
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
|
# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax())
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/* gzlib.c -- zlib functions common to reading and writing gzip files
|
/* gzlib.c -- zlib functions common to reading and writing gzip files
|
||||||
* Copyright (C) 2004-2017 Mark Adler
|
* Copyright (C) 2004-2019 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gzguts.h"
|
#include "gzguts.h"
|
||||||
|
|
||||||
#if defined(_WIN32) && !defined(__BORLANDC__) && !defined(__MINGW32__)
|
#if defined(_WIN32) && !defined(__BORLANDC__)
|
||||||
# define LSEEK _lseeki64
|
# define LSEEK _lseeki64
|
||||||
#else
|
#else
|
||||||
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
|
#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
|
||||||
|
@ -15,10 +15,6 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Local functions */
|
|
||||||
local void gz_reset OF((gz_statep));
|
|
||||||
local gzFile gz_open OF((const void *, int, const char *));
|
|
||||||
|
|
||||||
#if defined UNDER_CE
|
#if defined UNDER_CE
|
||||||
|
|
||||||
/* Map the Windows error number in ERROR to a locale-dependent error message
|
/* Map the Windows error number in ERROR to a locale-dependent error message
|
||||||
|
@ -30,9 +26,7 @@ local gzFile gz_open OF((const void *, int, const char *));
|
||||||
|
|
||||||
The gz_strwinerror function does not change the current setting of
|
The gz_strwinerror function does not change the current setting of
|
||||||
GetLastError. */
|
GetLastError. */
|
||||||
char ZLIB_INTERNAL *gz_strwinerror (error)
|
char ZLIB_INTERNAL *gz_strwinerror(DWORD error) {
|
||||||
DWORD error;
|
|
||||||
{
|
|
||||||
static char buf[1024];
|
static char buf[1024];
|
||||||
|
|
||||||
wchar_t *msgbuf;
|
wchar_t *msgbuf;
|
||||||
|
@ -72,15 +66,15 @@ char ZLIB_INTERNAL *gz_strwinerror (error)
|
||||||
#endif /* UNDER_CE */
|
#endif /* UNDER_CE */
|
||||||
|
|
||||||
/* Reset gzip file state */
|
/* Reset gzip file state */
|
||||||
local void gz_reset(state)
|
local void gz_reset(gz_statep state) {
|
||||||
gz_statep state;
|
|
||||||
{
|
|
||||||
state->x.have = 0; /* no output data available */
|
state->x.have = 0; /* no output data available */
|
||||||
if (state->mode == GZ_READ) { /* for reading ... */
|
if (state->mode == GZ_READ) { /* for reading ... */
|
||||||
state->eof = 0; /* not at end of file */
|
state->eof = 0; /* not at end of file */
|
||||||
state->past = 0; /* have not read past end yet */
|
state->past = 0; /* have not read past end yet */
|
||||||
state->how = LOOK; /* look for gzip header */
|
state->how = LOOK; /* look for gzip header */
|
||||||
}
|
}
|
||||||
|
else /* for writing ... */
|
||||||
|
state->reset = 0; /* no deflateReset pending */
|
||||||
state->seek = 0; /* no seek request pending */
|
state->seek = 0; /* no seek request pending */
|
||||||
gz_error(state, Z_OK, NULL); /* clear error */
|
gz_error(state, Z_OK, NULL); /* clear error */
|
||||||
state->x.pos = 0; /* no uncompressed data yet */
|
state->x.pos = 0; /* no uncompressed data yet */
|
||||||
|
@ -88,11 +82,7 @@ local void gz_reset(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open a gzip file either by name or file descriptor. */
|
/* Open a gzip file either by name or file descriptor. */
|
||||||
local gzFile gz_open(path, fd, mode)
|
local gzFile gz_open(const void *path, int fd, const char *mode) {
|
||||||
const void *path;
|
|
||||||
int fd;
|
|
||||||
const char *mode;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
z_size_t len;
|
z_size_t len;
|
||||||
int oflag;
|
int oflag;
|
||||||
|
@ -267,26 +257,17 @@ local gzFile gz_open(path, fd, mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
gzFile ZEXPORT gzopen(path, mode)
|
gzFile ZEXPORT gzopen(const char *path, const char *mode) {
|
||||||
const char *path;
|
|
||||||
const char *mode;
|
|
||||||
{
|
|
||||||
return gz_open(path, -1, mode);
|
return gz_open(path, -1, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
gzFile ZEXPORT gzopen64(path, mode)
|
gzFile ZEXPORT gzopen64(const char *path, const char *mode) {
|
||||||
const char *path;
|
|
||||||
const char *mode;
|
|
||||||
{
|
|
||||||
return gz_open(path, -1, mode);
|
return gz_open(path, -1, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
gzFile ZEXPORT gzdopen(fd, mode)
|
gzFile ZEXPORT gzdopen(int fd, const char *mode) {
|
||||||
int fd;
|
|
||||||
const char *mode;
|
|
||||||
{
|
|
||||||
char *path; /* identifier for error messages */
|
char *path; /* identifier for error messages */
|
||||||
gzFile gz;
|
gzFile gz;
|
||||||
|
|
||||||
|
@ -304,19 +285,13 @@ gzFile ZEXPORT gzdopen(fd, mode)
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
#ifdef WIDECHAR
|
#ifdef WIDECHAR
|
||||||
gzFile ZEXPORT gzopen_w(path, mode)
|
gzFile ZEXPORT gzopen_w(const wchar_t *path, const char *mode) {
|
||||||
const wchar_t *path;
|
|
||||||
const char *mode;
|
|
||||||
{
|
|
||||||
return gz_open(path, -2, mode);
|
return gz_open(path, -2, mode);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzbuffer(file, size)
|
int ZEXPORT gzbuffer(gzFile file, unsigned size) {
|
||||||
gzFile file;
|
|
||||||
unsigned size;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure and check integrity */
|
/* get internal structure and check integrity */
|
||||||
|
@ -333,16 +308,14 @@ int ZEXPORT gzbuffer(file, size)
|
||||||
/* check and set requested size */
|
/* check and set requested size */
|
||||||
if ((size << 1) < size)
|
if ((size << 1) < size)
|
||||||
return -1; /* need to be able to double it */
|
return -1; /* need to be able to double it */
|
||||||
if (size < 2)
|
if (size < 8)
|
||||||
size = 2; /* need two bytes to check magic header */
|
size = 8; /* needed to behave well with flushing */
|
||||||
state->want = size;
|
state->want = size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzrewind(file)
|
int ZEXPORT gzrewind(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -363,11 +336,7 @@ int ZEXPORT gzrewind(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_off64_t ZEXPORT gzseek64(file, offset, whence)
|
z_off64_t ZEXPORT gzseek64(gzFile file, z_off64_t offset, int whence) {
|
||||||
gzFile file;
|
|
||||||
z_off64_t offset;
|
|
||||||
int whence;
|
|
||||||
{
|
|
||||||
unsigned n;
|
unsigned n;
|
||||||
z_off64_t ret;
|
z_off64_t ret;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
@ -397,7 +366,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
|
||||||
/* if within raw area while reading, just go there */
|
/* if within raw area while reading, just go there */
|
||||||
if (state->mode == GZ_READ && state->how == COPY &&
|
if (state->mode == GZ_READ && state->how == COPY &&
|
||||||
state->x.pos + offset >= 0) {
|
state->x.pos + offset >= 0) {
|
||||||
ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR);
|
ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
return -1;
|
return -1;
|
||||||
state->x.have = 0;
|
state->x.have = 0;
|
||||||
|
@ -440,11 +409,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_off_t ZEXPORT gzseek(file, offset, whence)
|
z_off_t ZEXPORT gzseek(gzFile file, z_off_t offset, int whence) {
|
||||||
gzFile file;
|
|
||||||
z_off_t offset;
|
|
||||||
int whence;
|
|
||||||
{
|
|
||||||
z_off64_t ret;
|
z_off64_t ret;
|
||||||
|
|
||||||
ret = gzseek64(file, (z_off64_t)offset, whence);
|
ret = gzseek64(file, (z_off64_t)offset, whence);
|
||||||
|
@ -452,9 +417,7 @@ z_off_t ZEXPORT gzseek(file, offset, whence)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_off64_t ZEXPORT gztell64(file)
|
z_off64_t ZEXPORT gztell64(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure and check integrity */
|
/* get internal structure and check integrity */
|
||||||
|
@ -469,9 +432,7 @@ z_off64_t ZEXPORT gztell64(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_off_t ZEXPORT gztell(file)
|
z_off_t ZEXPORT gztell(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
z_off64_t ret;
|
z_off64_t ret;
|
||||||
|
|
||||||
ret = gztell64(file);
|
ret = gztell64(file);
|
||||||
|
@ -479,9 +440,7 @@ z_off_t ZEXPORT gztell(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_off64_t ZEXPORT gzoffset64(file)
|
z_off64_t ZEXPORT gzoffset64(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
z_off64_t offset;
|
z_off64_t offset;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
@ -502,9 +461,7 @@ z_off64_t ZEXPORT gzoffset64(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_off_t ZEXPORT gzoffset(file)
|
z_off_t ZEXPORT gzoffset(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
z_off64_t ret;
|
z_off64_t ret;
|
||||||
|
|
||||||
ret = gzoffset64(file);
|
ret = gzoffset64(file);
|
||||||
|
@ -512,9 +469,7 @@ z_off_t ZEXPORT gzoffset(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzeof(file)
|
int ZEXPORT gzeof(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure and check integrity */
|
/* get internal structure and check integrity */
|
||||||
|
@ -529,10 +484,7 @@ int ZEXPORT gzeof(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
const char * ZEXPORT gzerror(file, errnum)
|
const char * ZEXPORT gzerror(gzFile file, int *errnum) {
|
||||||
gzFile file;
|
|
||||||
int *errnum;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure and check integrity */
|
/* get internal structure and check integrity */
|
||||||
|
@ -550,9 +502,7 @@ const char * ZEXPORT gzerror(file, errnum)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
void ZEXPORT gzclearerr(file)
|
void ZEXPORT gzclearerr(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure and check integrity */
|
/* get internal structure and check integrity */
|
||||||
|
@ -576,11 +526,7 @@ void ZEXPORT gzclearerr(file)
|
||||||
memory). Simply save the error message as a static string. If there is an
|
memory). Simply save the error message as a static string. If there is an
|
||||||
allocation failure constructing the error message, then convert the error to
|
allocation failure constructing the error message, then convert the error to
|
||||||
out of memory. */
|
out of memory. */
|
||||||
void ZLIB_INTERNAL gz_error(state, err, msg)
|
void ZLIB_INTERNAL gz_error(gz_statep state, int err, const char *msg) {
|
||||||
gz_statep state;
|
|
||||||
int err;
|
|
||||||
const char *msg;
|
|
||||||
{
|
|
||||||
/* free previously allocated message and clear */
|
/* free previously allocated message and clear */
|
||||||
if (state->msg != NULL) {
|
if (state->msg != NULL) {
|
||||||
if (state->err != Z_MEM_ERROR)
|
if (state->err != Z_MEM_ERROR)
|
||||||
|
@ -622,8 +568,7 @@ void ZLIB_INTERNAL gz_error(state, err, msg)
|
||||||
available) -- we need to do this to cover cases where 2's complement not
|
available) -- we need to do this to cover cases where 2's complement not
|
||||||
used, since C standard permits 1's complement and sign-bit representations,
|
used, since C standard permits 1's complement and sign-bit representations,
|
||||||
otherwise we could just use ((unsigned)-1) >> 1 */
|
otherwise we could just use ((unsigned)-1) >> 1 */
|
||||||
unsigned ZLIB_INTERNAL gz_intmax()
|
unsigned ZLIB_INTERNAL gz_intmax(void) {
|
||||||
{
|
|
||||||
unsigned p, q;
|
unsigned p, q;
|
||||||
|
|
||||||
p = 1;
|
p = 1;
|
||||||
|
|
|
@ -1,29 +1,16 @@
|
||||||
/* gzread.c -- zlib functions for reading gzip files
|
/* gzread.c -- zlib functions for reading gzip files
|
||||||
* Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler
|
* Copyright (C) 2004-2017 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gzguts.h"
|
#include "gzguts.h"
|
||||||
|
|
||||||
/* Local functions */
|
|
||||||
local int gz_load OF((gz_statep, unsigned char *, unsigned, unsigned *));
|
|
||||||
local int gz_avail OF((gz_statep));
|
|
||||||
local int gz_look OF((gz_statep));
|
|
||||||
local int gz_decomp OF((gz_statep));
|
|
||||||
local int gz_fetch OF((gz_statep));
|
|
||||||
local int gz_skip OF((gz_statep, z_off64_t));
|
|
||||||
local z_size_t gz_read OF((gz_statep, voidp, z_size_t));
|
|
||||||
|
|
||||||
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
|
/* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from
|
||||||
state->fd, and update state->eof, state->err, and state->msg as appropriate.
|
state->fd, and update state->eof, state->err, and state->msg as appropriate.
|
||||||
This function needs to loop on read(), since read() is not guaranteed to
|
This function needs to loop on read(), since read() is not guaranteed to
|
||||||
read the number of bytes requested, depending on the type of descriptor. */
|
read the number of bytes requested, depending on the type of descriptor. */
|
||||||
local int gz_load(state, buf, len, have)
|
local int gz_load(gz_statep state, unsigned char *buf, unsigned len,
|
||||||
gz_statep state;
|
unsigned *have) {
|
||||||
unsigned char *buf;
|
|
||||||
unsigned len;
|
|
||||||
unsigned *have;
|
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
unsigned get, max = ((unsigned)-1 >> 2) + 1;
|
unsigned get, max = ((unsigned)-1 >> 2) + 1;
|
||||||
|
|
||||||
|
@ -53,9 +40,7 @@ local int gz_load(state, buf, len, have)
|
||||||
If strm->avail_in != 0, then the current data is moved to the beginning of
|
If strm->avail_in != 0, then the current data is moved to the beginning of
|
||||||
the input buffer, and then the remainder of the buffer is loaded with the
|
the input buffer, and then the remainder of the buffer is loaded with the
|
||||||
available data from the input file. */
|
available data from the input file. */
|
||||||
local int gz_avail(state)
|
local int gz_avail(gz_statep state) {
|
||||||
gz_statep state;
|
|
||||||
{
|
|
||||||
unsigned got;
|
unsigned got;
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
|
||||||
|
@ -88,9 +73,7 @@ local int gz_avail(state)
|
||||||
case, all further file reads will be directly to either the output buffer or
|
case, all further file reads will be directly to either the output buffer or
|
||||||
a user buffer. If decompressing, the inflate state will be initialized.
|
a user buffer. If decompressing, the inflate state will be initialized.
|
||||||
gz_look() will return 0 on success or -1 on failure. */
|
gz_look() will return 0 on success or -1 on failure. */
|
||||||
local int gz_look(state)
|
local int gz_look(gz_statep state) {
|
||||||
gz_statep state;
|
|
||||||
{
|
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
|
||||||
/* allocate read buffers and inflate memory */
|
/* allocate read buffers and inflate memory */
|
||||||
|
@ -157,11 +140,9 @@ local int gz_look(state)
|
||||||
the output buffer is larger than the input buffer, which also assures
|
the output buffer is larger than the input buffer, which also assures
|
||||||
space for gzungetc() */
|
space for gzungetc() */
|
||||||
state->x.next = state->out;
|
state->x.next = state->out;
|
||||||
if (strm->avail_in) {
|
memcpy(state->x.next, strm->next_in, strm->avail_in);
|
||||||
memcpy(state->x.next, strm->next_in, strm->avail_in);
|
state->x.have = strm->avail_in;
|
||||||
state->x.have = strm->avail_in;
|
strm->avail_in = 0;
|
||||||
strm->avail_in = 0;
|
|
||||||
}
|
|
||||||
state->how = COPY;
|
state->how = COPY;
|
||||||
state->direct = 1;
|
state->direct = 1;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -172,9 +153,7 @@ local int gz_look(state)
|
||||||
data. If the gzip stream completes, state->how is reset to LOOK to look for
|
data. If the gzip stream completes, state->how is reset to LOOK to look for
|
||||||
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
|
the next gzip stream or raw data, once state->x.have is depleted. Returns 0
|
||||||
on success, -1 on failure. */
|
on success, -1 on failure. */
|
||||||
local int gz_decomp(state)
|
local int gz_decomp(gz_statep state) {
|
||||||
gz_statep state;
|
|
||||||
{
|
|
||||||
int ret = Z_OK;
|
int ret = Z_OK;
|
||||||
unsigned had;
|
unsigned had;
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
@ -226,9 +205,7 @@ local int gz_decomp(state)
|
||||||
looked for to determine whether to copy or decompress. Returns -1 on error,
|
looked for to determine whether to copy or decompress. Returns -1 on error,
|
||||||
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
|
otherwise 0. gz_fetch() will leave state->how as COPY or GZIP unless the
|
||||||
end of the input file has been reached and all data has been processed. */
|
end of the input file has been reached and all data has been processed. */
|
||||||
local int gz_fetch(state)
|
local int gz_fetch(gz_statep state) {
|
||||||
gz_statep state;
|
|
||||||
{
|
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -256,10 +233,7 @@ local int gz_fetch(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
|
/* Skip len uncompressed bytes of output. Return -1 on error, 0 on success. */
|
||||||
local int gz_skip(state, len)
|
local int gz_skip(gz_statep state, z_off64_t len) {
|
||||||
gz_statep state;
|
|
||||||
z_off64_t len;
|
|
||||||
{
|
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
/* skip over len bytes or reach end-of-file, whichever comes first */
|
/* skip over len bytes or reach end-of-file, whichever comes first */
|
||||||
|
@ -291,11 +265,7 @@ local int gz_skip(state, len)
|
||||||
input. Return the number of bytes read. If zero is returned, either the
|
input. Return the number of bytes read. If zero is returned, either the
|
||||||
end of file was reached, or there was an error. state->err must be
|
end of file was reached, or there was an error. state->err must be
|
||||||
consulted in that case to determine which. */
|
consulted in that case to determine which. */
|
||||||
local z_size_t gz_read(state, buf, len)
|
local z_size_t gz_read(gz_statep state, voidp buf, z_size_t len) {
|
||||||
gz_statep state;
|
|
||||||
voidp buf;
|
|
||||||
z_size_t len;
|
|
||||||
{
|
|
||||||
z_size_t got;
|
z_size_t got;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
|
||||||
|
@ -314,9 +284,9 @@ local z_size_t gz_read(state, buf, len)
|
||||||
got = 0;
|
got = 0;
|
||||||
do {
|
do {
|
||||||
/* set n to the maximum amount of len that fits in an unsigned int */
|
/* set n to the maximum amount of len that fits in an unsigned int */
|
||||||
n = -1;
|
n = (unsigned)-1;
|
||||||
if (n > len)
|
if (n > len)
|
||||||
n = len;
|
n = (unsigned)len;
|
||||||
|
|
||||||
/* first just try copying data from the output buffer */
|
/* first just try copying data from the output buffer */
|
||||||
if (state->x.have) {
|
if (state->x.have) {
|
||||||
|
@ -372,11 +342,7 @@ local z_size_t gz_read(state, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzread(file, buf, len)
|
int ZEXPORT gzread(gzFile file, voidp buf, unsigned len) {
|
||||||
gzFile file;
|
|
||||||
voidp buf;
|
|
||||||
unsigned len;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -397,7 +363,7 @@ int ZEXPORT gzread(file, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read len or fewer bytes to buf */
|
/* read len or fewer bytes to buf */
|
||||||
len = gz_read(state, buf, len);
|
len = (unsigned)gz_read(state, buf, len);
|
||||||
|
|
||||||
/* check for an error */
|
/* check for an error */
|
||||||
if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
|
if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR)
|
||||||
|
@ -408,12 +374,7 @@ int ZEXPORT gzread(file, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_size_t ZEXPORT gzfread(buf, size, nitems, file)
|
z_size_t ZEXPORT gzfread(voidp buf, z_size_t size, z_size_t nitems, gzFile file) {
|
||||||
voidp buf;
|
|
||||||
z_size_t size;
|
|
||||||
z_size_t nitems;
|
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
z_size_t len;
|
z_size_t len;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
@ -444,10 +405,7 @@ z_size_t ZEXPORT gzfread(buf, size, nitems, file)
|
||||||
#else
|
#else
|
||||||
# undef gzgetc
|
# undef gzgetc
|
||||||
#endif
|
#endif
|
||||||
int ZEXPORT gzgetc(file)
|
int ZEXPORT gzgetc(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned char buf[1];
|
unsigned char buf[1];
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
@ -469,21 +427,15 @@ int ZEXPORT gzgetc(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* nothing there -- try gz_read() */
|
/* nothing there -- try gz_read() */
|
||||||
ret = gz_read(state, buf, 1);
|
return gz_read(state, buf, 1) < 1 ? -1 : buf[0];
|
||||||
return ret < 1 ? -1 : buf[0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT gzgetc_(file)
|
int ZEXPORT gzgetc_(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
return gzgetc(file);
|
return gzgetc(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzungetc(c, file)
|
int ZEXPORT gzungetc(int c, gzFile file) {
|
||||||
int c;
|
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -491,6 +443,10 @@ int ZEXPORT gzungetc(c, file)
|
||||||
return -1;
|
return -1;
|
||||||
state = (gz_statep)file;
|
state = (gz_statep)file;
|
||||||
|
|
||||||
|
/* in case this was just opened, set up the input buffer */
|
||||||
|
if (state->mode == GZ_READ && state->how == LOOK && state->x.have == 0)
|
||||||
|
(void)gz_look(state);
|
||||||
|
|
||||||
/* check that we're reading and that there's no (serious) error */
|
/* check that we're reading and that there's no (serious) error */
|
||||||
if (state->mode != GZ_READ ||
|
if (state->mode != GZ_READ ||
|
||||||
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
(state->err != Z_OK && state->err != Z_BUF_ERROR))
|
||||||
|
@ -540,11 +496,7 @@ int ZEXPORT gzungetc(c, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
char * ZEXPORT gzgets(file, buf, len)
|
char * ZEXPORT gzgets(gzFile file, char *buf, int len) {
|
||||||
gzFile file;
|
|
||||||
char *buf;
|
|
||||||
int len;
|
|
||||||
{
|
|
||||||
unsigned left, n;
|
unsigned left, n;
|
||||||
char *str;
|
char *str;
|
||||||
unsigned char *eol;
|
unsigned char *eol;
|
||||||
|
@ -604,9 +556,7 @@ char * ZEXPORT gzgets(file, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzdirect(file)
|
int ZEXPORT gzdirect(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -624,9 +574,7 @@ int ZEXPORT gzdirect(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzclose_r(file)
|
int ZEXPORT gzclose_r(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
int ret, err;
|
int ret, err;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
/* gzwrite.c -- zlib functions for writing gzip files
|
/* gzwrite.c -- zlib functions for writing gzip files
|
||||||
* Copyright (C) 2004-2017 Mark Adler
|
* Copyright (C) 2004-2019 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "gzguts.h"
|
#include "gzguts.h"
|
||||||
|
|
||||||
/* Local functions */
|
|
||||||
local int gz_init OF((gz_statep));
|
|
||||||
local int gz_comp OF((gz_statep, int));
|
|
||||||
local int gz_zero OF((gz_statep, z_off64_t));
|
|
||||||
local z_size_t gz_write OF((gz_statep, voidpc, z_size_t));
|
|
||||||
|
|
||||||
/* Initialize state for writing a gzip file. Mark initialization by setting
|
/* Initialize state for writing a gzip file. Mark initialization by setting
|
||||||
state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
|
state->size to non-zero. Return -1 on a memory allocation failure, or 0 on
|
||||||
success. */
|
success. */
|
||||||
local int gz_init(state)
|
local int gz_init(gz_statep state) {
|
||||||
gz_statep state;
|
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
|
||||||
|
@ -70,10 +62,7 @@ local int gz_init(state)
|
||||||
deflate() flush value. If flush is Z_FINISH, then the deflate() state is
|
deflate() flush value. If flush is Z_FINISH, then the deflate() state is
|
||||||
reset to start a new gzip stream. If gz->direct is true, then simply write
|
reset to start a new gzip stream. If gz->direct is true, then simply write
|
||||||
to the output file without compressing, and ignore flush. */
|
to the output file without compressing, and ignore flush. */
|
||||||
local int gz_comp(state, flush)
|
local int gz_comp(gz_statep state, int flush) {
|
||||||
gz_statep state;
|
|
||||||
int flush;
|
|
||||||
{
|
|
||||||
int ret, writ;
|
int ret, writ;
|
||||||
unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
|
unsigned have, put, max = ((unsigned)-1 >> 2) + 1;
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
@ -97,6 +86,15 @@ local int gz_comp(state, flush)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check for a pending reset */
|
||||||
|
if (state->reset) {
|
||||||
|
/* don't start a new gzip member unless there is data to write */
|
||||||
|
if (strm->avail_in == 0)
|
||||||
|
return 0;
|
||||||
|
deflateReset(strm);
|
||||||
|
state->reset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* run deflate() on provided input until it produces no more output */
|
/* run deflate() on provided input until it produces no more output */
|
||||||
ret = Z_OK;
|
ret = Z_OK;
|
||||||
do {
|
do {
|
||||||
|
@ -134,7 +132,7 @@ local int gz_comp(state, flush)
|
||||||
|
|
||||||
/* if that completed a deflate stream, allow another to start */
|
/* if that completed a deflate stream, allow another to start */
|
||||||
if (flush == Z_FINISH)
|
if (flush == Z_FINISH)
|
||||||
deflateReset(strm);
|
state->reset = 1;
|
||||||
|
|
||||||
/* all done, no errors */
|
/* all done, no errors */
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -142,10 +140,7 @@ local int gz_comp(state, flush)
|
||||||
|
|
||||||
/* Compress len zeros to output. Return -1 on a write error or memory
|
/* Compress len zeros to output. Return -1 on a write error or memory
|
||||||
allocation failure by gz_comp(), or 0 on success. */
|
allocation failure by gz_comp(), or 0 on success. */
|
||||||
local int gz_zero(state, len)
|
local int gz_zero(gz_statep state, z_off64_t len) {
|
||||||
gz_statep state;
|
|
||||||
z_off64_t len;
|
|
||||||
{
|
|
||||||
int first;
|
int first;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
z_streamp strm = &(state->strm);
|
z_streamp strm = &(state->strm);
|
||||||
|
@ -175,11 +170,7 @@ local int gz_zero(state, len)
|
||||||
|
|
||||||
/* Write len bytes from buf to file. Return the number of bytes written. If
|
/* Write len bytes from buf to file. Return the number of bytes written. If
|
||||||
the returned value is less than len, then there was an error. */
|
the returned value is less than len, then there was an error. */
|
||||||
local z_size_t gz_write(state, buf, len)
|
local z_size_t gz_write(gz_statep state, voidpc buf, z_size_t len) {
|
||||||
gz_statep state;
|
|
||||||
voidpc buf;
|
|
||||||
z_size_t len;
|
|
||||||
{
|
|
||||||
z_size_t put = len;
|
z_size_t put = len;
|
||||||
|
|
||||||
/* if len is zero, avoid unnecessary operations */
|
/* if len is zero, avoid unnecessary operations */
|
||||||
|
@ -209,7 +200,7 @@ local z_size_t gz_write(state, buf, len)
|
||||||
state->in);
|
state->in);
|
||||||
copy = state->size - have;
|
copy = state->size - have;
|
||||||
if (copy > len)
|
if (copy > len)
|
||||||
copy = len;
|
copy = (unsigned)len;
|
||||||
memcpy(state->in + have, buf, copy);
|
memcpy(state->in + have, buf, copy);
|
||||||
state->strm.avail_in += copy;
|
state->strm.avail_in += copy;
|
||||||
state->x.pos += copy;
|
state->x.pos += copy;
|
||||||
|
@ -229,7 +220,7 @@ local z_size_t gz_write(state, buf, len)
|
||||||
do {
|
do {
|
||||||
unsigned n = (unsigned)-1;
|
unsigned n = (unsigned)-1;
|
||||||
if (n > len)
|
if (n > len)
|
||||||
n = len;
|
n = (unsigned)len;
|
||||||
state->strm.avail_in = n;
|
state->strm.avail_in = n;
|
||||||
state->x.pos += n;
|
state->x.pos += n;
|
||||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||||
|
@ -243,11 +234,7 @@ local z_size_t gz_write(state, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzwrite(file, buf, len)
|
int ZEXPORT gzwrite(gzFile file, voidpc buf, unsigned len) {
|
||||||
gzFile file;
|
|
||||||
voidpc buf;
|
|
||||||
unsigned len;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -271,12 +258,8 @@ int ZEXPORT gzwrite(file, buf, len)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
|
z_size_t ZEXPORT gzfwrite(voidpc buf, z_size_t size, z_size_t nitems,
|
||||||
voidpc buf;
|
gzFile file) {
|
||||||
z_size_t size;
|
|
||||||
z_size_t nitems;
|
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
z_size_t len;
|
z_size_t len;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
@ -301,10 +284,7 @@ z_size_t ZEXPORT gzfwrite(buf, size, nitems, file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzputc(file, c)
|
int ZEXPORT gzputc(gzFile file, int c) {
|
||||||
gzFile file;
|
|
||||||
int c;
|
|
||||||
{
|
|
||||||
unsigned have;
|
unsigned have;
|
||||||
unsigned char buf[1];
|
unsigned char buf[1];
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
@ -349,12 +329,8 @@ int ZEXPORT gzputc(file, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzputs(file, str)
|
int ZEXPORT gzputs(gzFile file, const char *s) {
|
||||||
gzFile file;
|
z_size_t len, put;
|
||||||
const char *str;
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
z_size_t len;
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -367,17 +343,20 @@ int ZEXPORT gzputs(file, str)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* write string */
|
/* write string */
|
||||||
len = strlen(str);
|
len = strlen(s);
|
||||||
ret = gz_write(state, str, len);
|
if ((int)len < 0 || (unsigned)len != len) {
|
||||||
return ret == 0 && len != 0 ? -1 : ret;
|
gz_error(state, Z_STREAM_ERROR, "string length does not fit in int");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
put = gz_write(state, s, len);
|
||||||
|
return put < len ? -1 : (int)len;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
#if defined(STDC) || defined(Z_HAVE_STDARG_H)
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
|
int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) {
|
||||||
{
|
|
||||||
int len;
|
int len;
|
||||||
unsigned left;
|
unsigned left;
|
||||||
char *next;
|
char *next;
|
||||||
|
@ -441,15 +420,14 @@ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va)
|
||||||
strm->avail_in = state->size;
|
strm->avail_in = state->size;
|
||||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||||
return state->err;
|
return state->err;
|
||||||
memcpy(state->in, state->in + state->size, left);
|
memmove(state->in, state->in + state->size, left);
|
||||||
strm->next_in = state->in;
|
strm->next_in = state->in;
|
||||||
strm->avail_in = left;
|
strm->avail_in = left;
|
||||||
}
|
}
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
|
int ZEXPORTVA gzprintf(gzFile file, const char *format, ...) {
|
||||||
{
|
|
||||||
va_list va;
|
va_list va;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -462,13 +440,10 @@ int ZEXPORTVA gzprintf(gzFile file, const char *format, ...)
|
||||||
#else /* !STDC && !Z_HAVE_STDARG_H */
|
#else /* !STDC && !Z_HAVE_STDARG_H */
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
int ZEXPORTVA gzprintf(gzFile file, const char *format, int a1, int a2, int a3,
|
||||||
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
|
int a4, int a5, int a6, int a7, int a8, int a9, int a10,
|
||||||
gzFile file;
|
int a11, int a12, int a13, int a14, int a15, int a16,
|
||||||
const char *format;
|
int a17, int a18, int a19, int a20) {
|
||||||
int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
|
||||||
a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
|
|
||||||
{
|
|
||||||
unsigned len, left;
|
unsigned len, left;
|
||||||
char *next;
|
char *next;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
@ -540,7 +515,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||||
strm->avail_in = state->size;
|
strm->avail_in = state->size;
|
||||||
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
if (gz_comp(state, Z_NO_FLUSH) == -1)
|
||||||
return state->err;
|
return state->err;
|
||||||
memcpy(state->in, state->in + state->size, left);
|
memmove(state->in, state->in + state->size, left);
|
||||||
strm->next_in = state->in;
|
strm->next_in = state->in;
|
||||||
strm->avail_in = left;
|
strm->avail_in = left;
|
||||||
}
|
}
|
||||||
|
@ -550,10 +525,7 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzflush(file, flush)
|
int ZEXPORT gzflush(gzFile file, int flush) {
|
||||||
gzFile file;
|
|
||||||
int flush;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
/* get internal structure */
|
/* get internal structure */
|
||||||
|
@ -582,11 +554,7 @@ int ZEXPORT gzflush(file, flush)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzsetparams(file, level, strategy)
|
int ZEXPORT gzsetparams(gzFile file, int level, int strategy) {
|
||||||
gzFile file;
|
|
||||||
int level;
|
|
||||||
int strategy;
|
|
||||||
{
|
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
z_streamp strm;
|
z_streamp strm;
|
||||||
|
|
||||||
|
@ -597,7 +565,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
|
||||||
strm = &(state->strm);
|
strm = &(state->strm);
|
||||||
|
|
||||||
/* check that we're writing and that there's no error */
|
/* check that we're writing and that there's no error */
|
||||||
if (state->mode != GZ_WRITE || state->err != Z_OK)
|
if (state->mode != GZ_WRITE || state->err != Z_OK || state->direct)
|
||||||
return Z_STREAM_ERROR;
|
return Z_STREAM_ERROR;
|
||||||
|
|
||||||
/* if no change is requested, then do nothing */
|
/* if no change is requested, then do nothing */
|
||||||
|
@ -624,9 +592,7 @@ int ZEXPORT gzsetparams(file, level, strategy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -- see zlib.h -- */
|
/* -- see zlib.h -- */
|
||||||
int ZEXPORT gzclose_w(file)
|
int ZEXPORT gzclose_w(gzFile file) {
|
||||||
gzFile file;
|
|
||||||
{
|
|
||||||
int ret = Z_OK;
|
int ret = Z_OK;
|
||||||
gz_statep state;
|
gz_statep state;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* infback.c -- inflate using a call-back interface
|
/* infback.c -- inflate using a call-back interface
|
||||||
* Copyright (C) 1995-2016 Mark Adler
|
* Copyright (C) 1995-2022 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -15,9 +15,6 @@
|
||||||
#include "inflate.h"
|
#include "inflate.h"
|
||||||
#include "inffast.h"
|
#include "inffast.h"
|
||||||
|
|
||||||
/* function prototypes */
|
|
||||||
local void fixedtables OF((struct inflate_state FAR *state));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
strm provides memory allocation functions in zalloc and zfree, or
|
strm provides memory allocation functions in zalloc and zfree, or
|
||||||
Z_NULL to use the library memory allocation functions.
|
Z_NULL to use the library memory allocation functions.
|
||||||
|
@ -25,13 +22,9 @@ local void fixedtables OF((struct inflate_state FAR *state));
|
||||||
windowBits is in the range 8..15, and window is a user-supplied
|
windowBits is in the range 8..15, and window is a user-supplied
|
||||||
window and output buffer that is 2**windowBits bytes.
|
window and output buffer that is 2**windowBits bytes.
|
||||||
*/
|
*/
|
||||||
int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
|
int ZEXPORT inflateBackInit_(z_streamp strm, int windowBits,
|
||||||
z_streamp strm;
|
unsigned char FAR *window, const char *version,
|
||||||
int windowBits;
|
int stream_size) {
|
||||||
unsigned char FAR *window;
|
|
||||||
const char *version;
|
|
||||||
int stream_size;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
|
if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
|
||||||
|
@ -66,6 +59,7 @@ int stream_size;
|
||||||
state->window = window;
|
state->window = window;
|
||||||
state->wnext = 0;
|
state->wnext = 0;
|
||||||
state->whave = 0;
|
state->whave = 0;
|
||||||
|
state->sane = 1;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,9 +73,7 @@ int stream_size;
|
||||||
used for threaded applications, since the rewriting of the tables and virgin
|
used for threaded applications, since the rewriting of the tables and virgin
|
||||||
may not be thread-safe.
|
may not be thread-safe.
|
||||||
*/
|
*/
|
||||||
local void fixedtables(state)
|
local void fixedtables(struct inflate_state FAR *state) {
|
||||||
struct inflate_state FAR *state;
|
|
||||||
{
|
|
||||||
#ifdef BUILDFIXED
|
#ifdef BUILDFIXED
|
||||||
static int virgin = 1;
|
static int virgin = 1;
|
||||||
static code *lenfix, *distfix;
|
static code *lenfix, *distfix;
|
||||||
|
@ -247,13 +239,8 @@ struct inflate_state FAR *state;
|
||||||
inflateBack() can also return Z_STREAM_ERROR if the input parameters
|
inflateBack() can also return Z_STREAM_ERROR if the input parameters
|
||||||
are not correct, i.e. strm is Z_NULL or the state was not initialized.
|
are not correct, i.e. strm is Z_NULL or the state was not initialized.
|
||||||
*/
|
*/
|
||||||
int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
|
int ZEXPORT inflateBack(z_streamp strm, in_func in, void FAR *in_desc,
|
||||||
z_streamp strm;
|
out_func out, void FAR *out_desc) {
|
||||||
in_func in;
|
|
||||||
void FAR *in_desc;
|
|
||||||
out_func out;
|
|
||||||
void FAR *out_desc;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
z_const unsigned char FAR *next; /* next input */
|
z_const unsigned char FAR *next; /* next input */
|
||||||
unsigned char FAR *put; /* next output */
|
unsigned char FAR *put; /* next output */
|
||||||
|
@ -477,6 +464,7 @@ void FAR *out_desc;
|
||||||
}
|
}
|
||||||
Tracev((stderr, "inflate: codes ok\n"));
|
Tracev((stderr, "inflate: codes ok\n"));
|
||||||
state->mode = LEN;
|
state->mode = LEN;
|
||||||
|
/* fallthrough */
|
||||||
|
|
||||||
case LEN:
|
case LEN:
|
||||||
/* use inflate_fast() if we have enough input and output */
|
/* use inflate_fast() if we have enough input and output */
|
||||||
|
@ -604,33 +592,33 @@ void FAR *out_desc;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DONE:
|
case DONE:
|
||||||
/* inflate stream terminated properly -- write leftover output */
|
/* inflate stream terminated properly */
|
||||||
ret = Z_STREAM_END;
|
ret = Z_STREAM_END;
|
||||||
if (left < state->wsize) {
|
|
||||||
if (out(out_desc, state->window, state->wsize - left))
|
|
||||||
ret = Z_BUF_ERROR;
|
|
||||||
}
|
|
||||||
goto inf_leave;
|
goto inf_leave;
|
||||||
|
|
||||||
case BAD:
|
case BAD:
|
||||||
ret = Z_DATA_ERROR;
|
ret = Z_DATA_ERROR;
|
||||||
goto inf_leave;
|
goto inf_leave;
|
||||||
|
|
||||||
default: /* can't happen, but makes compilers happy */
|
default:
|
||||||
|
/* can't happen, but makes compilers happy */
|
||||||
ret = Z_STREAM_ERROR;
|
ret = Z_STREAM_ERROR;
|
||||||
goto inf_leave;
|
goto inf_leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return unused input */
|
/* Write leftover output and return unused input */
|
||||||
inf_leave:
|
inf_leave:
|
||||||
|
if (left < state->wsize) {
|
||||||
|
if (out(out_desc, state->window, state->wsize - left) &&
|
||||||
|
ret == Z_STREAM_END)
|
||||||
|
ret = Z_BUF_ERROR;
|
||||||
|
}
|
||||||
strm->next_in = next;
|
strm->next_in = next;
|
||||||
strm->avail_in = have;
|
strm->avail_in = have;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateBackEnd(strm)
|
int ZEXPORT inflateBackEnd(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
|
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
|
||||||
return Z_STREAM_ERROR;
|
return Z_STREAM_ERROR;
|
||||||
ZFREE(strm, strm->state);
|
ZFREE(strm, strm->state);
|
||||||
|
|
|
@ -47,10 +47,7 @@
|
||||||
requires strm->avail_out >= 258 for each loop to avoid checking for
|
requires strm->avail_out >= 258 for each loop to avoid checking for
|
||||||
output space.
|
output space.
|
||||||
*/
|
*/
|
||||||
void ZLIB_INTERNAL inflate_fast(strm, start)
|
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start) {
|
||||||
z_streamp strm;
|
|
||||||
unsigned start; /* inflate()'s starting value for strm->avail_out */
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
z_const unsigned char FAR *in; /* local strm->next_in */
|
z_const unsigned char FAR *in; /* local strm->next_in */
|
||||||
z_const unsigned char FAR *last; /* have enough input while in < last */
|
z_const unsigned char FAR *last; /* have enough input while in < last */
|
||||||
|
@ -70,7 +67,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||||
code const FAR *dcode; /* local strm->distcode */
|
code const FAR *dcode; /* local strm->distcode */
|
||||||
unsigned lmask; /* mask for first level of length codes */
|
unsigned lmask; /* mask for first level of length codes */
|
||||||
unsigned dmask; /* mask for first level of distance codes */
|
unsigned dmask; /* mask for first level of distance codes */
|
||||||
code here; /* retrieved table entry */
|
code const *here; /* retrieved table entry */
|
||||||
unsigned op; /* code bits, operation, extra bits, or */
|
unsigned op; /* code bits, operation, extra bits, or */
|
||||||
/* window position, window bytes to copy */
|
/* window position, window bytes to copy */
|
||||||
unsigned len; /* match length, unused bytes */
|
unsigned len; /* match length, unused bytes */
|
||||||
|
@ -107,20 +104,20 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||||
hold += (unsigned long)(*in++) << bits;
|
hold += (unsigned long)(*in++) << bits;
|
||||||
bits += 8;
|
bits += 8;
|
||||||
}
|
}
|
||||||
here = lcode[hold & lmask];
|
here = lcode + (hold & lmask);
|
||||||
dolen:
|
dolen:
|
||||||
op = (unsigned)(here.bits);
|
op = (unsigned)(here->bits);
|
||||||
hold >>= op;
|
hold >>= op;
|
||||||
bits -= op;
|
bits -= op;
|
||||||
op = (unsigned)(here.op);
|
op = (unsigned)(here->op);
|
||||||
if (op == 0) { /* literal */
|
if (op == 0) { /* literal */
|
||||||
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ?
|
||||||
"inflate: literal '%c'\n" :
|
"inflate: literal '%c'\n" :
|
||||||
"inflate: literal 0x%02x\n", here.val));
|
"inflate: literal 0x%02x\n", here->val));
|
||||||
*out++ = (unsigned char)(here.val);
|
*out++ = (unsigned char)(here->val);
|
||||||
}
|
}
|
||||||
else if (op & 16) { /* length base */
|
else if (op & 16) { /* length base */
|
||||||
len = (unsigned)(here.val);
|
len = (unsigned)(here->val);
|
||||||
op &= 15; /* number of extra bits */
|
op &= 15; /* number of extra bits */
|
||||||
if (op) {
|
if (op) {
|
||||||
if (bits < op) {
|
if (bits < op) {
|
||||||
|
@ -138,14 +135,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||||
hold += (unsigned long)(*in++) << bits;
|
hold += (unsigned long)(*in++) << bits;
|
||||||
bits += 8;
|
bits += 8;
|
||||||
}
|
}
|
||||||
here = dcode[hold & dmask];
|
here = dcode + (hold & dmask);
|
||||||
dodist:
|
dodist:
|
||||||
op = (unsigned)(here.bits);
|
op = (unsigned)(here->bits);
|
||||||
hold >>= op;
|
hold >>= op;
|
||||||
bits -= op;
|
bits -= op;
|
||||||
op = (unsigned)(here.op);
|
op = (unsigned)(here->op);
|
||||||
if (op & 16) { /* distance base */
|
if (op & 16) { /* distance base */
|
||||||
dist = (unsigned)(here.val);
|
dist = (unsigned)(here->val);
|
||||||
op &= 15; /* number of extra bits */
|
op &= 15; /* number of extra bits */
|
||||||
if (bits < op) {
|
if (bits < op) {
|
||||||
hold += (unsigned long)(*in++) << bits;
|
hold += (unsigned long)(*in++) << bits;
|
||||||
|
@ -264,7 +261,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((op & 64) == 0) { /* 2nd level distance code */
|
else if ((op & 64) == 0) { /* 2nd level distance code */
|
||||||
here = dcode[here.val + (hold & ((1U << op) - 1))];
|
here = dcode + here->val + (hold & ((1U << op) - 1));
|
||||||
goto dodist;
|
goto dodist;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -274,7 +271,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((op & 64) == 0) { /* 2nd level length code */
|
else if ((op & 64) == 0) { /* 2nd level length code */
|
||||||
here = lcode[here.val + (hold & ((1U << op) - 1))];
|
here = lcode + here->val + (hold & ((1U << op) - 1));
|
||||||
goto dolen;
|
goto dolen;
|
||||||
}
|
}
|
||||||
else if (op & 32) { /* end-of-block */
|
else if (op & 32) { /* end-of-block */
|
||||||
|
|
|
@ -8,4 +8,4 @@
|
||||||
subject to change. Applications should only use zlib.h.
|
subject to change. Applications should only use zlib.h.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start));
|
void ZLIB_INTERNAL inflate_fast(z_streamp strm, unsigned start);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* inflate.c -- zlib decompression
|
/* inflate.c -- zlib decompression
|
||||||
* Copyright (C) 1995-2016 Mark Adler
|
* Copyright (C) 1995-2022 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -91,20 +91,7 @@
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* function prototypes */
|
local int inflateStateCheck(z_streamp strm) {
|
||||||
local int inflateStateCheck OF((z_streamp strm));
|
|
||||||
local void fixedtables OF((struct inflate_state FAR *state));
|
|
||||||
local int updatewindow OF((z_streamp strm, const unsigned char FAR *end,
|
|
||||||
unsigned copy));
|
|
||||||
#ifdef BUILDFIXED
|
|
||||||
void makefixed OF((void));
|
|
||||||
#endif
|
|
||||||
local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf,
|
|
||||||
unsigned len));
|
|
||||||
|
|
||||||
local int inflateStateCheck(strm)
|
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
if (strm == Z_NULL ||
|
if (strm == Z_NULL ||
|
||||||
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
|
strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0)
|
||||||
|
@ -116,9 +103,7 @@ z_streamp strm;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateResetKeep(strm)
|
int ZEXPORT inflateResetKeep(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||||
|
@ -130,6 +115,7 @@ z_streamp strm;
|
||||||
state->mode = HEAD;
|
state->mode = HEAD;
|
||||||
state->last = 0;
|
state->last = 0;
|
||||||
state->havedict = 0;
|
state->havedict = 0;
|
||||||
|
state->flags = -1;
|
||||||
state->dmax = 32768U;
|
state->dmax = 32768U;
|
||||||
state->head = Z_NULL;
|
state->head = Z_NULL;
|
||||||
state->hold = 0;
|
state->hold = 0;
|
||||||
|
@ -141,9 +127,7 @@ z_streamp strm;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateReset(strm)
|
int ZEXPORT inflateReset(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||||
|
@ -154,10 +138,7 @@ z_streamp strm;
|
||||||
return inflateResetKeep(strm);
|
return inflateResetKeep(strm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateReset2(strm, windowBits)
|
int ZEXPORT inflateReset2(z_streamp strm, int windowBits) {
|
||||||
z_streamp strm;
|
|
||||||
int windowBits;
|
|
||||||
{
|
|
||||||
int wrap;
|
int wrap;
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
|
@ -167,6 +148,8 @@ int windowBits;
|
||||||
|
|
||||||
/* extract wrap request from windowBits parameter */
|
/* extract wrap request from windowBits parameter */
|
||||||
if (windowBits < 0) {
|
if (windowBits < 0) {
|
||||||
|
if (windowBits < -15)
|
||||||
|
return Z_STREAM_ERROR;
|
||||||
wrap = 0;
|
wrap = 0;
|
||||||
windowBits = -windowBits;
|
windowBits = -windowBits;
|
||||||
}
|
}
|
||||||
|
@ -192,12 +175,8 @@ int windowBits;
|
||||||
return inflateReset(strm);
|
return inflateReset(strm);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
|
int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
|
||||||
z_streamp strm;
|
const char *version, int stream_size) {
|
||||||
int windowBits;
|
|
||||||
const char *version;
|
|
||||||
int stream_size;
|
|
||||||
{
|
|
||||||
int ret;
|
int ret;
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
|
@ -236,22 +215,17 @@ int stream_size;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateInit_(strm, version, stream_size)
|
int ZEXPORT inflateInit_(z_streamp strm, const char *version,
|
||||||
z_streamp strm;
|
int stream_size) {
|
||||||
const char *version;
|
|
||||||
int stream_size;
|
|
||||||
{
|
|
||||||
return inflateInit2_(strm, DEF_WBITS, version, stream_size);
|
return inflateInit2_(strm, DEF_WBITS, version, stream_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflatePrime(strm, bits, value)
|
int ZEXPORT inflatePrime(z_streamp strm, int bits, int value) {
|
||||||
z_streamp strm;
|
|
||||||
int bits;
|
|
||||||
int value;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||||
|
if (bits == 0)
|
||||||
|
return Z_OK;
|
||||||
state = (struct inflate_state FAR *)strm->state;
|
state = (struct inflate_state FAR *)strm->state;
|
||||||
if (bits < 0) {
|
if (bits < 0) {
|
||||||
state->hold = 0;
|
state->hold = 0;
|
||||||
|
@ -275,9 +249,7 @@ int value;
|
||||||
used for threaded applications, since the rewriting of the tables and virgin
|
used for threaded applications, since the rewriting of the tables and virgin
|
||||||
may not be thread-safe.
|
may not be thread-safe.
|
||||||
*/
|
*/
|
||||||
local void fixedtables(state)
|
local void fixedtables(struct inflate_state FAR *state) {
|
||||||
struct inflate_state FAR *state;
|
|
||||||
{
|
|
||||||
#ifdef BUILDFIXED
|
#ifdef BUILDFIXED
|
||||||
static int virgin = 1;
|
static int virgin = 1;
|
||||||
static code *lenfix, *distfix;
|
static code *lenfix, *distfix;
|
||||||
|
@ -339,7 +311,7 @@ struct inflate_state FAR *state;
|
||||||
|
|
||||||
a.out > inffixed.h
|
a.out > inffixed.h
|
||||||
*/
|
*/
|
||||||
void makefixed()
|
void makefixed(void)
|
||||||
{
|
{
|
||||||
unsigned low, size;
|
unsigned low, size;
|
||||||
struct inflate_state state;
|
struct inflate_state state;
|
||||||
|
@ -393,11 +365,7 @@ void makefixed()
|
||||||
output will fall in the output data, making match copies simpler and faster.
|
output will fall in the output data, making match copies simpler and faster.
|
||||||
The advantage may be dependent on the size of the processor's data caches.
|
The advantage may be dependent on the size of the processor's data caches.
|
||||||
*/
|
*/
|
||||||
local int updatewindow(strm, end, copy)
|
local int updatewindow(z_streamp strm, const Bytef *end, unsigned copy) {
|
||||||
z_streamp strm;
|
|
||||||
const Bytef *end;
|
|
||||||
unsigned copy;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
unsigned dist;
|
unsigned dist;
|
||||||
|
|
||||||
|
@ -447,10 +415,10 @@ unsigned copy;
|
||||||
|
|
||||||
/* check function to use adler32() for zlib or crc32() for gzip */
|
/* check function to use adler32() for zlib or crc32() for gzip */
|
||||||
#ifdef GUNZIP
|
#ifdef GUNZIP
|
||||||
# define UPDATE(check, buf, len) \
|
# define UPDATE_CHECK(check, buf, len) \
|
||||||
(state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
|
(state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
|
||||||
#else
|
#else
|
||||||
# define UPDATE(check, buf, len) adler32(check, buf, len)
|
# define UPDATE_CHECK(check, buf, len) adler32(check, buf, len)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* check macros for header crc */
|
/* check macros for header crc */
|
||||||
|
@ -619,10 +587,7 @@ unsigned copy;
|
||||||
will return Z_BUF_ERROR if it has not reached the end of the stream.
|
will return Z_BUF_ERROR if it has not reached the end of the stream.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ZEXPORT inflate(strm, flush)
|
int ZEXPORT inflate(z_streamp strm, int flush) {
|
||||||
z_streamp strm;
|
|
||||||
int flush;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
z_const unsigned char FAR *next; /* next input */
|
z_const unsigned char FAR *next; /* next input */
|
||||||
unsigned char FAR *put; /* next output */
|
unsigned char FAR *put; /* next output */
|
||||||
|
@ -670,7 +635,6 @@ int flush;
|
||||||
state->mode = FLAGS;
|
state->mode = FLAGS;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state->flags = 0; /* expect zlib header */
|
|
||||||
if (state->head != Z_NULL)
|
if (state->head != Z_NULL)
|
||||||
state->head->done = -1;
|
state->head->done = -1;
|
||||||
if (!(state->wrap & 1) || /* check if zlib header allowed */
|
if (!(state->wrap & 1) || /* check if zlib header allowed */
|
||||||
|
@ -697,6 +661,7 @@ int flush;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
state->dmax = 1U << len;
|
state->dmax = 1U << len;
|
||||||
|
state->flags = 0; /* indicate zlib header */
|
||||||
Tracev((stderr, "inflate: zlib header ok\n"));
|
Tracev((stderr, "inflate: zlib header ok\n"));
|
||||||
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
||||||
state->mode = hold & 0x200 ? DICTID : TYPE;
|
state->mode = hold & 0x200 ? DICTID : TYPE;
|
||||||
|
@ -722,6 +687,7 @@ int flush;
|
||||||
CRC2(state->check, hold);
|
CRC2(state->check, hold);
|
||||||
INITBITS();
|
INITBITS();
|
||||||
state->mode = TIME;
|
state->mode = TIME;
|
||||||
|
/* fallthrough */
|
||||||
case TIME:
|
case TIME:
|
||||||
NEEDBITS(32);
|
NEEDBITS(32);
|
||||||
if (state->head != Z_NULL)
|
if (state->head != Z_NULL)
|
||||||
|
@ -730,6 +696,7 @@ int flush;
|
||||||
CRC4(state->check, hold);
|
CRC4(state->check, hold);
|
||||||
INITBITS();
|
INITBITS();
|
||||||
state->mode = OS;
|
state->mode = OS;
|
||||||
|
/* fallthrough */
|
||||||
case OS:
|
case OS:
|
||||||
NEEDBITS(16);
|
NEEDBITS(16);
|
||||||
if (state->head != Z_NULL) {
|
if (state->head != Z_NULL) {
|
||||||
|
@ -740,6 +707,7 @@ int flush;
|
||||||
CRC2(state->check, hold);
|
CRC2(state->check, hold);
|
||||||
INITBITS();
|
INITBITS();
|
||||||
state->mode = EXLEN;
|
state->mode = EXLEN;
|
||||||
|
/* fallthrough */
|
||||||
case EXLEN:
|
case EXLEN:
|
||||||
if (state->flags & 0x0400) {
|
if (state->flags & 0x0400) {
|
||||||
NEEDBITS(16);
|
NEEDBITS(16);
|
||||||
|
@ -753,14 +721,16 @@ int flush;
|
||||||
else if (state->head != Z_NULL)
|
else if (state->head != Z_NULL)
|
||||||
state->head->extra = Z_NULL;
|
state->head->extra = Z_NULL;
|
||||||
state->mode = EXTRA;
|
state->mode = EXTRA;
|
||||||
|
/* fallthrough */
|
||||||
case EXTRA:
|
case EXTRA:
|
||||||
if (state->flags & 0x0400) {
|
if (state->flags & 0x0400) {
|
||||||
copy = state->length;
|
copy = state->length;
|
||||||
if (copy > have) copy = have;
|
if (copy > have) copy = have;
|
||||||
if (copy) {
|
if (copy) {
|
||||||
if (state->head != Z_NULL &&
|
if (state->head != Z_NULL &&
|
||||||
state->head->extra != Z_NULL) {
|
state->head->extra != Z_NULL &&
|
||||||
len = state->head->extra_len - state->length;
|
(len = state->head->extra_len - state->length) <
|
||||||
|
state->head->extra_max) {
|
||||||
zmemcpy(state->head->extra + len, next,
|
zmemcpy(state->head->extra + len, next,
|
||||||
len + copy > state->head->extra_max ?
|
len + copy > state->head->extra_max ?
|
||||||
state->head->extra_max - len : copy);
|
state->head->extra_max - len : copy);
|
||||||
|
@ -775,6 +745,7 @@ int flush;
|
||||||
}
|
}
|
||||||
state->length = 0;
|
state->length = 0;
|
||||||
state->mode = NAME;
|
state->mode = NAME;
|
||||||
|
/* fallthrough */
|
||||||
case NAME:
|
case NAME:
|
||||||
if (state->flags & 0x0800) {
|
if (state->flags & 0x0800) {
|
||||||
if (have == 0) goto inf_leave;
|
if (have == 0) goto inf_leave;
|
||||||
|
@ -796,6 +767,7 @@ int flush;
|
||||||
state->head->name = Z_NULL;
|
state->head->name = Z_NULL;
|
||||||
state->length = 0;
|
state->length = 0;
|
||||||
state->mode = COMMENT;
|
state->mode = COMMENT;
|
||||||
|
/* fallthrough */
|
||||||
case COMMENT:
|
case COMMENT:
|
||||||
if (state->flags & 0x1000) {
|
if (state->flags & 0x1000) {
|
||||||
if (have == 0) goto inf_leave;
|
if (have == 0) goto inf_leave;
|
||||||
|
@ -816,6 +788,7 @@ int flush;
|
||||||
else if (state->head != Z_NULL)
|
else if (state->head != Z_NULL)
|
||||||
state->head->comment = Z_NULL;
|
state->head->comment = Z_NULL;
|
||||||
state->mode = HCRC;
|
state->mode = HCRC;
|
||||||
|
/* fallthrough */
|
||||||
case HCRC:
|
case HCRC:
|
||||||
if (state->flags & 0x0200) {
|
if (state->flags & 0x0200) {
|
||||||
NEEDBITS(16);
|
NEEDBITS(16);
|
||||||
|
@ -839,6 +812,7 @@ int flush;
|
||||||
strm->adler = state->check = ZSWAP32(hold);
|
strm->adler = state->check = ZSWAP32(hold);
|
||||||
INITBITS();
|
INITBITS();
|
||||||
state->mode = DICT;
|
state->mode = DICT;
|
||||||
|
/* fallthrough */
|
||||||
case DICT:
|
case DICT:
|
||||||
if (state->havedict == 0) {
|
if (state->havedict == 0) {
|
||||||
RESTORE();
|
RESTORE();
|
||||||
|
@ -846,8 +820,10 @@ int flush;
|
||||||
}
|
}
|
||||||
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
strm->adler = state->check = adler32(0L, Z_NULL, 0);
|
||||||
state->mode = TYPE;
|
state->mode = TYPE;
|
||||||
|
/* fallthrough */
|
||||||
case TYPE:
|
case TYPE:
|
||||||
if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
|
if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
|
||||||
|
/* fallthrough */
|
||||||
case TYPEDO:
|
case TYPEDO:
|
||||||
if (state->last) {
|
if (state->last) {
|
||||||
BYTEBITS();
|
BYTEBITS();
|
||||||
|
@ -898,8 +874,10 @@ int flush;
|
||||||
INITBITS();
|
INITBITS();
|
||||||
state->mode = COPY_;
|
state->mode = COPY_;
|
||||||
if (flush == Z_TREES) goto inf_leave;
|
if (flush == Z_TREES) goto inf_leave;
|
||||||
|
/* fallthrough */
|
||||||
case COPY_:
|
case COPY_:
|
||||||
state->mode = COPY;
|
state->mode = COPY;
|
||||||
|
/* fallthrough */
|
||||||
case COPY:
|
case COPY:
|
||||||
copy = state->length;
|
copy = state->length;
|
||||||
if (copy) {
|
if (copy) {
|
||||||
|
@ -935,6 +913,7 @@ int flush;
|
||||||
Tracev((stderr, "inflate: table sizes ok\n"));
|
Tracev((stderr, "inflate: table sizes ok\n"));
|
||||||
state->have = 0;
|
state->have = 0;
|
||||||
state->mode = LENLENS;
|
state->mode = LENLENS;
|
||||||
|
/* fallthrough */
|
||||||
case LENLENS:
|
case LENLENS:
|
||||||
while (state->have < state->ncode) {
|
while (state->have < state->ncode) {
|
||||||
NEEDBITS(3);
|
NEEDBITS(3);
|
||||||
|
@ -956,6 +935,7 @@ int flush;
|
||||||
Tracev((stderr, "inflate: code lengths ok\n"));
|
Tracev((stderr, "inflate: code lengths ok\n"));
|
||||||
state->have = 0;
|
state->have = 0;
|
||||||
state->mode = CODELENS;
|
state->mode = CODELENS;
|
||||||
|
/* fallthrough */
|
||||||
case CODELENS:
|
case CODELENS:
|
||||||
while (state->have < state->nlen + state->ndist) {
|
while (state->have < state->nlen + state->ndist) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -1039,8 +1019,10 @@ int flush;
|
||||||
Tracev((stderr, "inflate: codes ok\n"));
|
Tracev((stderr, "inflate: codes ok\n"));
|
||||||
state->mode = LEN_;
|
state->mode = LEN_;
|
||||||
if (flush == Z_TREES) goto inf_leave;
|
if (flush == Z_TREES) goto inf_leave;
|
||||||
|
/* fallthrough */
|
||||||
case LEN_:
|
case LEN_:
|
||||||
state->mode = LEN;
|
state->mode = LEN;
|
||||||
|
/* fallthrough */
|
||||||
case LEN:
|
case LEN:
|
||||||
if (have >= 6 && left >= 258) {
|
if (have >= 6 && left >= 258) {
|
||||||
RESTORE();
|
RESTORE();
|
||||||
|
@ -1090,6 +1072,7 @@ int flush;
|
||||||
}
|
}
|
||||||
state->extra = (unsigned)(here.op) & 15;
|
state->extra = (unsigned)(here.op) & 15;
|
||||||
state->mode = LENEXT;
|
state->mode = LENEXT;
|
||||||
|
/* fallthrough */
|
||||||
case LENEXT:
|
case LENEXT:
|
||||||
if (state->extra) {
|
if (state->extra) {
|
||||||
NEEDBITS(state->extra);
|
NEEDBITS(state->extra);
|
||||||
|
@ -1100,6 +1083,7 @@ int flush;
|
||||||
Tracevv((stderr, "inflate: length %u\n", state->length));
|
Tracevv((stderr, "inflate: length %u\n", state->length));
|
||||||
state->was = state->length;
|
state->was = state->length;
|
||||||
state->mode = DIST;
|
state->mode = DIST;
|
||||||
|
/* fallthrough */
|
||||||
case DIST:
|
case DIST:
|
||||||
for (;;) {
|
for (;;) {
|
||||||
here = state->distcode[BITS(state->distbits)];
|
here = state->distcode[BITS(state->distbits)];
|
||||||
|
@ -1127,6 +1111,7 @@ int flush;
|
||||||
state->offset = (unsigned)here.val;
|
state->offset = (unsigned)here.val;
|
||||||
state->extra = (unsigned)(here.op) & 15;
|
state->extra = (unsigned)(here.op) & 15;
|
||||||
state->mode = DISTEXT;
|
state->mode = DISTEXT;
|
||||||
|
/* fallthrough */
|
||||||
case DISTEXT:
|
case DISTEXT:
|
||||||
if (state->extra) {
|
if (state->extra) {
|
||||||
NEEDBITS(state->extra);
|
NEEDBITS(state->extra);
|
||||||
|
@ -1143,6 +1128,7 @@ int flush;
|
||||||
#endif
|
#endif
|
||||||
Tracevv((stderr, "inflate: distance %u\n", state->offset));
|
Tracevv((stderr, "inflate: distance %u\n", state->offset));
|
||||||
state->mode = MATCH;
|
state->mode = MATCH;
|
||||||
|
/* fallthrough */
|
||||||
case MATCH:
|
case MATCH:
|
||||||
if (left == 0) goto inf_leave;
|
if (left == 0) goto inf_leave;
|
||||||
copy = out - left;
|
copy = out - left;
|
||||||
|
@ -1202,7 +1188,7 @@ int flush;
|
||||||
state->total += out;
|
state->total += out;
|
||||||
if ((state->wrap & 4) && out)
|
if ((state->wrap & 4) && out)
|
||||||
strm->adler = state->check =
|
strm->adler = state->check =
|
||||||
UPDATE(state->check, put - out, out);
|
UPDATE_CHECK(state->check, put - out, out);
|
||||||
out = left;
|
out = left;
|
||||||
if ((state->wrap & 4) && (
|
if ((state->wrap & 4) && (
|
||||||
#ifdef GUNZIP
|
#ifdef GUNZIP
|
||||||
|
@ -1218,10 +1204,11 @@ int flush;
|
||||||
}
|
}
|
||||||
#ifdef GUNZIP
|
#ifdef GUNZIP
|
||||||
state->mode = LENGTH;
|
state->mode = LENGTH;
|
||||||
|
/* fallthrough */
|
||||||
case LENGTH:
|
case LENGTH:
|
||||||
if (state->wrap && state->flags) {
|
if (state->wrap && state->flags) {
|
||||||
NEEDBITS(32);
|
NEEDBITS(32);
|
||||||
if (hold != (state->total & 0xffffffffUL)) {
|
if ((state->wrap & 4) && hold != (state->total & 0xffffffff)) {
|
||||||
strm->msg = (char *)"incorrect length check";
|
strm->msg = (char *)"incorrect length check";
|
||||||
state->mode = BAD;
|
state->mode = BAD;
|
||||||
break;
|
break;
|
||||||
|
@ -1231,6 +1218,7 @@ int flush;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
state->mode = DONE;
|
state->mode = DONE;
|
||||||
|
/* fallthrough */
|
||||||
case DONE:
|
case DONE:
|
||||||
ret = Z_STREAM_END;
|
ret = Z_STREAM_END;
|
||||||
goto inf_leave;
|
goto inf_leave;
|
||||||
|
@ -1240,6 +1228,7 @@ int flush;
|
||||||
case MEM:
|
case MEM:
|
||||||
return Z_MEM_ERROR;
|
return Z_MEM_ERROR;
|
||||||
case SYNC:
|
case SYNC:
|
||||||
|
/* fallthrough */
|
||||||
default:
|
default:
|
||||||
return Z_STREAM_ERROR;
|
return Z_STREAM_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -1265,7 +1254,7 @@ int flush;
|
||||||
state->total += out;
|
state->total += out;
|
||||||
if ((state->wrap & 4) && out)
|
if ((state->wrap & 4) && out)
|
||||||
strm->adler = state->check =
|
strm->adler = state->check =
|
||||||
UPDATE(state->check, strm->next_out - out, out);
|
UPDATE_CHECK(state->check, strm->next_out - out, out);
|
||||||
strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
|
strm->data_type = (int)state->bits + (state->last ? 64 : 0) +
|
||||||
(state->mode == TYPE ? 128 : 0) +
|
(state->mode == TYPE ? 128 : 0) +
|
||||||
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
|
(state->mode == LEN_ || state->mode == COPY_ ? 256 : 0);
|
||||||
|
@ -1274,9 +1263,7 @@ int flush;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateEnd(strm)
|
int ZEXPORT inflateEnd(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
if (inflateStateCheck(strm))
|
if (inflateStateCheck(strm))
|
||||||
return Z_STREAM_ERROR;
|
return Z_STREAM_ERROR;
|
||||||
|
@ -1288,11 +1275,8 @@ z_streamp strm;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)
|
int ZEXPORT inflateGetDictionary(z_streamp strm, Bytef *dictionary,
|
||||||
z_streamp strm;
|
uInt *dictLength) {
|
||||||
Bytef *dictionary;
|
|
||||||
uInt *dictLength;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
/* check state */
|
/* check state */
|
||||||
|
@ -1311,11 +1295,8 @@ uInt *dictLength;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
|
int ZEXPORT inflateSetDictionary(z_streamp strm, const Bytef *dictionary,
|
||||||
z_streamp strm;
|
uInt dictLength) {
|
||||||
const Bytef *dictionary;
|
|
||||||
uInt dictLength;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
unsigned long dictid;
|
unsigned long dictid;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1346,10 +1327,7 @@ uInt dictLength;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateGetHeader(strm, head)
|
int ZEXPORT inflateGetHeader(z_streamp strm, gz_headerp head) {
|
||||||
z_streamp strm;
|
|
||||||
gz_headerp head;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
/* check state */
|
/* check state */
|
||||||
|
@ -1374,11 +1352,8 @@ gz_headerp head;
|
||||||
called again with more data and the *have state. *have is initialized to
|
called again with more data and the *have state. *have is initialized to
|
||||||
zero for the first call.
|
zero for the first call.
|
||||||
*/
|
*/
|
||||||
local unsigned syncsearch(have, buf, len)
|
local unsigned syncsearch(unsigned FAR *have, const unsigned char FAR *buf,
|
||||||
unsigned FAR *have;
|
unsigned len) {
|
||||||
const unsigned char FAR *buf;
|
|
||||||
unsigned len;
|
|
||||||
{
|
|
||||||
unsigned got;
|
unsigned got;
|
||||||
unsigned next;
|
unsigned next;
|
||||||
|
|
||||||
|
@ -1397,10 +1372,9 @@ unsigned len;
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateSync(strm)
|
int ZEXPORT inflateSync(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
unsigned len; /* number of bytes to look at or looked at */
|
unsigned len; /* number of bytes to look at or looked at */
|
||||||
|
int flags; /* temporary to save header status */
|
||||||
unsigned long in, out; /* temporary to save total_in and total_out */
|
unsigned long in, out; /* temporary to save total_in and total_out */
|
||||||
unsigned char buf[4]; /* to restore bit buffer to byte string */
|
unsigned char buf[4]; /* to restore bit buffer to byte string */
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
@ -1433,9 +1407,15 @@ z_streamp strm;
|
||||||
|
|
||||||
/* return no joy or set up to restart inflate() on a new block */
|
/* return no joy or set up to restart inflate() on a new block */
|
||||||
if (state->have != 4) return Z_DATA_ERROR;
|
if (state->have != 4) return Z_DATA_ERROR;
|
||||||
|
if (state->flags == -1)
|
||||||
|
state->wrap = 0; /* if no header yet, treat as raw */
|
||||||
|
else
|
||||||
|
state->wrap &= ~4; /* no point in computing a check value now */
|
||||||
|
flags = state->flags;
|
||||||
in = strm->total_in; out = strm->total_out;
|
in = strm->total_in; out = strm->total_out;
|
||||||
inflateReset(strm);
|
inflateReset(strm);
|
||||||
strm->total_in = in; strm->total_out = out;
|
strm->total_in = in; strm->total_out = out;
|
||||||
|
state->flags = flags;
|
||||||
state->mode = TYPE;
|
state->mode = TYPE;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
@ -1448,9 +1428,7 @@ z_streamp strm;
|
||||||
block. When decompressing, PPP checks that at the end of input packet,
|
block. When decompressing, PPP checks that at the end of input packet,
|
||||||
inflate is waiting for these length bytes.
|
inflate is waiting for these length bytes.
|
||||||
*/
|
*/
|
||||||
int ZEXPORT inflateSyncPoint(strm)
|
int ZEXPORT inflateSyncPoint(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||||
|
@ -1458,10 +1436,7 @@ z_streamp strm;
|
||||||
return state->mode == STORED && state->bits == 0;
|
return state->mode == STORED && state->bits == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateCopy(dest, source)
|
int ZEXPORT inflateCopy(z_streamp dest, z_streamp source) {
|
||||||
z_streamp dest;
|
|
||||||
z_streamp source;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
struct inflate_state FAR *copy;
|
struct inflate_state FAR *copy;
|
||||||
unsigned char FAR *window;
|
unsigned char FAR *window;
|
||||||
|
@ -1505,10 +1480,7 @@ z_streamp source;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateUndermine(strm, subvert)
|
int ZEXPORT inflateUndermine(z_streamp strm, int subvert) {
|
||||||
z_streamp strm;
|
|
||||||
int subvert;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||||
|
@ -1523,24 +1495,19 @@ int subvert;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT inflateValidate(strm, check)
|
int ZEXPORT inflateValidate(z_streamp strm, int check) {
|
||||||
z_streamp strm;
|
|
||||||
int check;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
|
||||||
state = (struct inflate_state FAR *)strm->state;
|
state = (struct inflate_state FAR *)strm->state;
|
||||||
if (check)
|
if (check && state->wrap)
|
||||||
state->wrap |= 4;
|
state->wrap |= 4;
|
||||||
else
|
else
|
||||||
state->wrap &= ~4;
|
state->wrap &= ~4;
|
||||||
return Z_OK;
|
return Z_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
long ZEXPORT inflateMark(strm)
|
long ZEXPORT inflateMark(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
|
|
||||||
if (inflateStateCheck(strm))
|
if (inflateStateCheck(strm))
|
||||||
|
@ -1551,9 +1518,7 @@ z_streamp strm;
|
||||||
(state->mode == MATCH ? state->was - state->length : 0));
|
(state->mode == MATCH ? state->was - state->length : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long ZEXPORT inflateCodesUsed(strm)
|
unsigned long ZEXPORT inflateCodesUsed(z_streamp strm) {
|
||||||
z_streamp strm;
|
|
||||||
{
|
|
||||||
struct inflate_state FAR *state;
|
struct inflate_state FAR *state;
|
||||||
if (inflateStateCheck(strm)) return (unsigned long)-1;
|
if (inflateStateCheck(strm)) return (unsigned long)-1;
|
||||||
state = (struct inflate_state FAR *)strm->state;
|
state = (struct inflate_state FAR *)strm->state;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* inflate.h -- internal inflate state definition
|
/* inflate.h -- internal inflate state definition
|
||||||
* Copyright (C) 1995-2016 Mark Adler
|
* Copyright (C) 1995-2019 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -86,7 +86,8 @@ struct inflate_state {
|
||||||
int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
|
int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
|
||||||
bit 2 true to validate check value */
|
bit 2 true to validate check value */
|
||||||
int havedict; /* true if dictionary provided */
|
int havedict; /* true if dictionary provided */
|
||||||
int flags; /* gzip header method and flags (0 if zlib) */
|
int flags; /* gzip header method and flags, 0 if zlib, or
|
||||||
|
-1 if raw or no header yet */
|
||||||
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
|
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
|
||||||
unsigned long check; /* protected copy of check value */
|
unsigned long check; /* protected copy of check value */
|
||||||
unsigned long total; /* protected copy of output count */
|
unsigned long total; /* protected copy of output count */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* inftrees.c -- generate Huffman trees for efficient decoding
|
/* inftrees.c -- generate Huffman trees for efficient decoding
|
||||||
* Copyright (C) 1995-2017 Mark Adler
|
* Copyright (C) 1995-2023 Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
#define MAXBITS 15
|
#define MAXBITS 15
|
||||||
|
|
||||||
const char inflate_copyright[] =
|
const char inflate_copyright[] =
|
||||||
" inflate 1.2.11 Copyright 1995-2017 Mark Adler ";
|
" inflate 1.3 Copyright 1995-2023 Mark Adler ";
|
||||||
/*
|
/*
|
||||||
If you use the zlib library in a product, an acknowledgment is welcome
|
If you use the zlib library in a product, an acknowledgment is welcome
|
||||||
in the documentation of your product. If for some reason you cannot
|
in the documentation of your product. If for some reason you cannot
|
||||||
|
@ -29,14 +29,9 @@ const char inflate_copyright[] =
|
||||||
table index bits. It will differ if the request is greater than the
|
table index bits. It will differ if the request is greater than the
|
||||||
longest code or if it is less than the shortest code.
|
longest code or if it is less than the shortest code.
|
||||||
*/
|
*/
|
||||||
int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work)
|
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||||
codetype type;
|
unsigned codes, code FAR * FAR *table,
|
||||||
unsigned short FAR *lens;
|
unsigned FAR *bits, unsigned short FAR *work) {
|
||||||
unsigned codes;
|
|
||||||
code FAR * FAR *table;
|
|
||||||
unsigned FAR *bits;
|
|
||||||
unsigned short FAR *work;
|
|
||||||
{
|
|
||||||
unsigned len; /* a code's length in bits */
|
unsigned len; /* a code's length in bits */
|
||||||
unsigned sym; /* index of code symbols */
|
unsigned sym; /* index of code symbols */
|
||||||
unsigned min, max; /* minimum and maximum code lengths */
|
unsigned min, max; /* minimum and maximum code lengths */
|
||||||
|
@ -62,7 +57,7 @@ unsigned short FAR *work;
|
||||||
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
|
35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
|
||||||
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
|
static const unsigned short lext[31] = { /* Length codes 257..285 extra */
|
||||||
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
|
||||||
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202};
|
19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 203};
|
||||||
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
|
static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
|
||||||
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
|
||||||
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
|
||||||
|
|
|
@ -38,7 +38,7 @@ typedef struct {
|
||||||
/* Maximum size of the dynamic table. The maximum number of code structures is
|
/* Maximum size of the dynamic table. The maximum number of code structures is
|
||||||
1444, which is the sum of 852 for literal/length codes and 592 for distance
|
1444, which is the sum of 852 for literal/length codes and 592 for distance
|
||||||
codes. These values were found by exhaustive searches using the program
|
codes. These values were found by exhaustive searches using the program
|
||||||
examples/enough.c found in the zlib distribtution. The arguments to that
|
examples/enough.c found in the zlib distribution. The arguments to that
|
||||||
program are the number of symbols, the initial root table size, and the
|
program are the number of symbols, the initial root table size, and the
|
||||||
maximum bit length of a code. "enough 286 9 15" for literal/length codes
|
maximum bit length of a code. "enough 286 9 15" for literal/length codes
|
||||||
returns returns 852, and "enough 30 6 15" for distance codes returns 592.
|
returns returns 852, and "enough 30 6 15" for distance codes returns 592.
|
||||||
|
@ -57,6 +57,6 @@ typedef enum {
|
||||||
DISTS
|
DISTS
|
||||||
} codetype;
|
} codetype;
|
||||||
|
|
||||||
int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens,
|
int ZLIB_INTERNAL inflate_table(codetype type, unsigned short FAR *lens,
|
||||||
unsigned codes, code FAR * FAR *table,
|
unsigned codes, code FAR * FAR *table,
|
||||||
unsigned FAR *bits, unsigned short FAR *work));
|
unsigned FAR *bits, unsigned short FAR *work);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* trees.c -- output deflated data using Huffman coding
|
/* trees.c -- output deflated data using Huffman coding
|
||||||
* Copyright (C) 1995-2017 Jean-loup Gailly
|
* Copyright (C) 1995-2021 Jean-loup Gailly
|
||||||
* detect_data_type() function provided freely by Cosmin Truta, 2006
|
* detect_data_type() function provided freely by Cosmin Truta, 2006
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
@ -122,39 +122,116 @@ struct static_tree_desc_s {
|
||||||
int max_length; /* max bit length for the codes */
|
int max_length; /* max bit length for the codes */
|
||||||
};
|
};
|
||||||
|
|
||||||
local const static_tree_desc static_l_desc =
|
#ifdef NO_INIT_GLOBAL_POINTERS
|
||||||
|
# define TCONST
|
||||||
|
#else
|
||||||
|
# define TCONST const
|
||||||
|
#endif
|
||||||
|
|
||||||
|
local TCONST static_tree_desc static_l_desc =
|
||||||
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
|
{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
|
||||||
|
|
||||||
local const static_tree_desc static_d_desc =
|
local TCONST static_tree_desc static_d_desc =
|
||||||
{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
|
{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
|
||||||
|
|
||||||
local const static_tree_desc static_bl_desc =
|
local TCONST static_tree_desc static_bl_desc =
|
||||||
{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
|
{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Local (static) routines in this file.
|
* Output a short LSB first on the stream.
|
||||||
|
* IN assertion: there is enough room in pendingBuf.
|
||||||
*/
|
*/
|
||||||
|
#define put_short(s, w) { \
|
||||||
|
put_byte(s, (uch)((w) & 0xff)); \
|
||||||
|
put_byte(s, (uch)((ush)(w) >> 8)); \
|
||||||
|
}
|
||||||
|
|
||||||
local void tr_static_init OF((void));
|
/* ===========================================================================
|
||||||
local void init_block OF((deflate_state *s));
|
* Reverse the first len bits of a code, using straightforward code (a faster
|
||||||
local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
|
* method would use a table)
|
||||||
local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
|
* IN assertion: 1 <= len <= 15
|
||||||
local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
|
*/
|
||||||
local void build_tree OF((deflate_state *s, tree_desc *desc));
|
local unsigned bi_reverse(unsigned code, int len) {
|
||||||
local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
|
register unsigned res = 0;
|
||||||
local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
|
do {
|
||||||
local int build_bl_tree OF((deflate_state *s));
|
res |= code & 1;
|
||||||
local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
|
code >>= 1, res <<= 1;
|
||||||
int blcodes));
|
} while (--len > 0);
|
||||||
local void compress_block OF((deflate_state *s, const ct_data *ltree,
|
return res >> 1;
|
||||||
const ct_data *dtree));
|
}
|
||||||
local int detect_data_type OF((deflate_state *s));
|
|
||||||
local unsigned bi_reverse OF((unsigned value, int length));
|
/* ===========================================================================
|
||||||
local void bi_windup OF((deflate_state *s));
|
* Flush the bit buffer, keeping at most 7 bits in it.
|
||||||
local void bi_flush OF((deflate_state *s));
|
*/
|
||||||
|
local void bi_flush(deflate_state *s) {
|
||||||
|
if (s->bi_valid == 16) {
|
||||||
|
put_short(s, s->bi_buf);
|
||||||
|
s->bi_buf = 0;
|
||||||
|
s->bi_valid = 0;
|
||||||
|
} else if (s->bi_valid >= 8) {
|
||||||
|
put_byte(s, (Byte)s->bi_buf);
|
||||||
|
s->bi_buf >>= 8;
|
||||||
|
s->bi_valid -= 8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Flush the bit buffer and align the output on a byte boundary
|
||||||
|
*/
|
||||||
|
local void bi_windup(deflate_state *s) {
|
||||||
|
if (s->bi_valid > 8) {
|
||||||
|
put_short(s, s->bi_buf);
|
||||||
|
} else if (s->bi_valid > 0) {
|
||||||
|
put_byte(s, (Byte)s->bi_buf);
|
||||||
|
}
|
||||||
|
s->bi_buf = 0;
|
||||||
|
s->bi_valid = 0;
|
||||||
|
#ifdef ZLIB_DEBUG
|
||||||
|
s->bits_sent = (s->bits_sent + 7) & ~7;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Generate the codes for a given tree and bit counts (which need not be
|
||||||
|
* optimal).
|
||||||
|
* IN assertion: the array bl_count contains the bit length statistics for
|
||||||
|
* the given tree and the field len is set for all tree elements.
|
||||||
|
* OUT assertion: the field code is set for all tree elements of non
|
||||||
|
* zero code length.
|
||||||
|
*/
|
||||||
|
local void gen_codes(ct_data *tree, int max_code, ushf *bl_count) {
|
||||||
|
ush next_code[MAX_BITS+1]; /* next code value for each bit length */
|
||||||
|
unsigned code = 0; /* running code value */
|
||||||
|
int bits; /* bit index */
|
||||||
|
int n; /* code index */
|
||||||
|
|
||||||
|
/* The distribution counts are first used to generate the code values
|
||||||
|
* without bit reversal.
|
||||||
|
*/
|
||||||
|
for (bits = 1; bits <= MAX_BITS; bits++) {
|
||||||
|
code = (code + bl_count[bits - 1]) << 1;
|
||||||
|
next_code[bits] = (ush)code;
|
||||||
|
}
|
||||||
|
/* Check that the bit counts in bl_count are consistent. The last code
|
||||||
|
* must be all ones.
|
||||||
|
*/
|
||||||
|
Assert (code + bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1,
|
||||||
|
"inconsistent bit counts");
|
||||||
|
Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
|
||||||
|
|
||||||
|
for (n = 0; n <= max_code; n++) {
|
||||||
|
int len = tree[n].Len;
|
||||||
|
if (len == 0) continue;
|
||||||
|
/* Now reverse the bits */
|
||||||
|
tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
|
||||||
|
|
||||||
|
Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
|
||||||
|
n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len] - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef GEN_TREES_H
|
#ifdef GEN_TREES_H
|
||||||
local void gen_trees_header OF((void));
|
local void gen_trees_header(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ZLIB_DEBUG
|
#ifndef ZLIB_DEBUG
|
||||||
|
@ -167,33 +244,18 @@ local void gen_trees_header OF((void));
|
||||||
send_bits(s, tree[c].Code, tree[c].Len); }
|
send_bits(s, tree[c].Code, tree[c].Len); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Output a short LSB first on the stream.
|
|
||||||
* IN assertion: there is enough room in pendingBuf.
|
|
||||||
*/
|
|
||||||
#define put_short(s, w) { \
|
|
||||||
put_byte(s, (uch)((w) & 0xff)); \
|
|
||||||
put_byte(s, (uch)((ush)(w) >> 8)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Send a value on a given number of bits.
|
* Send a value on a given number of bits.
|
||||||
* IN assertion: length <= 16 and value fits in length bits.
|
* IN assertion: length <= 16 and value fits in length bits.
|
||||||
*/
|
*/
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
local void send_bits OF((deflate_state *s, int value, int length));
|
local void send_bits(deflate_state *s, int value, int length) {
|
||||||
|
|
||||||
local void send_bits(s, value, length)
|
|
||||||
deflate_state *s;
|
|
||||||
int value; /* value to send */
|
|
||||||
int length; /* number of bits */
|
|
||||||
{
|
|
||||||
Tracevv((stderr," l %2d v %4x ", length, value));
|
Tracevv((stderr," l %2d v %4x ", length, value));
|
||||||
Assert(length > 0 && length <= 15, "invalid length");
|
Assert(length > 0 && length <= 15, "invalid length");
|
||||||
s->bits_sent += (ulg)length;
|
s->bits_sent += (ulg)length;
|
||||||
|
|
||||||
/* If not enough room in bi_buf, use (valid) bits from bi_buf and
|
/* If not enough room in bi_buf, use (valid) bits from bi_buf and
|
||||||
* (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
|
* (16 - bi_valid) bits from value, leaving (width - (16 - bi_valid))
|
||||||
* unused bits in value.
|
* unused bits in value.
|
||||||
*/
|
*/
|
||||||
if (s->bi_valid > (int)Buf_size - length) {
|
if (s->bi_valid > (int)Buf_size - length) {
|
||||||
|
@ -229,8 +291,7 @@ local void send_bits(s, value, length)
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Initialize the various 'constant' tables.
|
* Initialize the various 'constant' tables.
|
||||||
*/
|
*/
|
||||||
local void tr_static_init()
|
local void tr_static_init(void) {
|
||||||
{
|
|
||||||
#if defined(GEN_TREES_H) || !defined(STDC)
|
#if defined(GEN_TREES_H) || !defined(STDC)
|
||||||
static int static_init_done = 0;
|
static int static_init_done = 0;
|
||||||
int n; /* iterates over tree elements */
|
int n; /* iterates over tree elements */
|
||||||
|
@ -256,7 +317,7 @@ local void tr_static_init()
|
||||||
length = 0;
|
length = 0;
|
||||||
for (code = 0; code < LENGTH_CODES-1; code++) {
|
for (code = 0; code < LENGTH_CODES-1; code++) {
|
||||||
base_length[code] = length;
|
base_length[code] = length;
|
||||||
for (n = 0; n < (1<<extra_lbits[code]); n++) {
|
for (n = 0; n < (1 << extra_lbits[code]); n++) {
|
||||||
_length_code[length++] = (uch)code;
|
_length_code[length++] = (uch)code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -265,13 +326,13 @@ local void tr_static_init()
|
||||||
* in two different ways: code 284 + 5 bits or code 285, so we
|
* in two different ways: code 284 + 5 bits or code 285, so we
|
||||||
* overwrite length_code[255] to use the best encoding:
|
* overwrite length_code[255] to use the best encoding:
|
||||||
*/
|
*/
|
||||||
_length_code[length-1] = (uch)code;
|
_length_code[length - 1] = (uch)code;
|
||||||
|
|
||||||
/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
|
/* Initialize the mapping dist (0..32K) -> dist code (0..29) */
|
||||||
dist = 0;
|
dist = 0;
|
||||||
for (code = 0 ; code < 16; code++) {
|
for (code = 0 ; code < 16; code++) {
|
||||||
base_dist[code] = dist;
|
base_dist[code] = dist;
|
||||||
for (n = 0; n < (1<<extra_dbits[code]); n++) {
|
for (n = 0; n < (1 << extra_dbits[code]); n++) {
|
||||||
_dist_code[dist++] = (uch)code;
|
_dist_code[dist++] = (uch)code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,11 +340,11 @@ local void tr_static_init()
|
||||||
dist >>= 7; /* from now on, all distances are divided by 128 */
|
dist >>= 7; /* from now on, all distances are divided by 128 */
|
||||||
for ( ; code < D_CODES; code++) {
|
for ( ; code < D_CODES; code++) {
|
||||||
base_dist[code] = dist << 7;
|
base_dist[code] = dist << 7;
|
||||||
for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
|
for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) {
|
||||||
_dist_code[256 + dist++] = (uch)code;
|
_dist_code[256 + dist++] = (uch)code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Assert (dist == 256, "tr_static_init: 256+dist != 512");
|
Assert (dist == 256, "tr_static_init: 256 + dist != 512");
|
||||||
|
|
||||||
/* Construct the codes of the static literal tree */
|
/* Construct the codes of the static literal tree */
|
||||||
for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
|
for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
|
||||||
|
@ -312,7 +373,7 @@ local void tr_static_init()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Genererate the file trees.h describing the static trees.
|
* Generate the file trees.h describing the static trees.
|
||||||
*/
|
*/
|
||||||
#ifdef GEN_TREES_H
|
#ifdef GEN_TREES_H
|
||||||
# ifndef ZLIB_DEBUG
|
# ifndef ZLIB_DEBUG
|
||||||
|
@ -321,10 +382,9 @@ local void tr_static_init()
|
||||||
|
|
||||||
# define SEPARATOR(i, last, width) \
|
# define SEPARATOR(i, last, width) \
|
||||||
((i) == (last)? "\n};\n\n" : \
|
((i) == (last)? "\n};\n\n" : \
|
||||||
((i) % (width) == (width)-1 ? ",\n" : ", "))
|
((i) % (width) == (width) - 1 ? ",\n" : ", "))
|
||||||
|
|
||||||
void gen_trees_header()
|
void gen_trees_header(void) {
|
||||||
{
|
|
||||||
FILE *header = fopen("trees.h", "w");
|
FILE *header = fopen("trees.h", "w");
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -373,12 +433,26 @@ void gen_trees_header()
|
||||||
}
|
}
|
||||||
#endif /* GEN_TREES_H */
|
#endif /* GEN_TREES_H */
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Initialize a new block.
|
||||||
|
*/
|
||||||
|
local void init_block(deflate_state *s) {
|
||||||
|
int n; /* iterates over tree elements */
|
||||||
|
|
||||||
|
/* Initialize the trees. */
|
||||||
|
for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
|
||||||
|
for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
|
||||||
|
for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
|
||||||
|
|
||||||
|
s->dyn_ltree[END_BLOCK].Freq = 1;
|
||||||
|
s->opt_len = s->static_len = 0L;
|
||||||
|
s->sym_next = s->matches = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Initialize the tree data structures for a new zlib stream.
|
* Initialize the tree data structures for a new zlib stream.
|
||||||
*/
|
*/
|
||||||
void ZLIB_INTERNAL _tr_init(s)
|
void ZLIB_INTERNAL _tr_init(deflate_state *s) {
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
tr_static_init();
|
tr_static_init();
|
||||||
|
|
||||||
s->l_desc.dyn_tree = s->dyn_ltree;
|
s->l_desc.dyn_tree = s->dyn_ltree;
|
||||||
|
@ -401,24 +475,6 @@ void ZLIB_INTERNAL _tr_init(s)
|
||||||
init_block(s);
|
init_block(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Initialize a new block.
|
|
||||||
*/
|
|
||||||
local void init_block(s)
|
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
int n; /* iterates over tree elements */
|
|
||||||
|
|
||||||
/* Initialize the trees. */
|
|
||||||
for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
|
|
||||||
for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
|
|
||||||
for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
|
|
||||||
|
|
||||||
s->dyn_ltree[END_BLOCK].Freq = 1;
|
|
||||||
s->opt_len = s->static_len = 0L;
|
|
||||||
s->last_lit = s->matches = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define SMALLEST 1
|
#define SMALLEST 1
|
||||||
/* Index within the heap array of least frequent node in the Huffman tree */
|
/* Index within the heap array of least frequent node in the Huffman tree */
|
||||||
|
|
||||||
|
@ -448,17 +504,13 @@ local void init_block(s)
|
||||||
* when the heap property is re-established (each father smaller than its
|
* when the heap property is re-established (each father smaller than its
|
||||||
* two sons).
|
* two sons).
|
||||||
*/
|
*/
|
||||||
local void pqdownheap(s, tree, k)
|
local void pqdownheap(deflate_state *s, ct_data *tree, int k) {
|
||||||
deflate_state *s;
|
|
||||||
ct_data *tree; /* the tree to restore */
|
|
||||||
int k; /* node to move down */
|
|
||||||
{
|
|
||||||
int v = s->heap[k];
|
int v = s->heap[k];
|
||||||
int j = k << 1; /* left son of k */
|
int j = k << 1; /* left son of k */
|
||||||
while (j <= s->heap_len) {
|
while (j <= s->heap_len) {
|
||||||
/* Set j to the smallest of the two sons: */
|
/* Set j to the smallest of the two sons: */
|
||||||
if (j < s->heap_len &&
|
if (j < s->heap_len &&
|
||||||
smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
|
smaller(tree, s->heap[j + 1], s->heap[j], s->depth)) {
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
/* Exit if v is smaller than both sons */
|
/* Exit if v is smaller than both sons */
|
||||||
|
@ -483,10 +535,7 @@ local void pqdownheap(s, tree, k)
|
||||||
* The length opt_len is updated; static_len is also updated if stree is
|
* The length opt_len is updated; static_len is also updated if stree is
|
||||||
* not null.
|
* not null.
|
||||||
*/
|
*/
|
||||||
local void gen_bitlen(s, desc)
|
local void gen_bitlen(deflate_state *s, tree_desc *desc) {
|
||||||
deflate_state *s;
|
|
||||||
tree_desc *desc; /* the tree descriptor */
|
|
||||||
{
|
|
||||||
ct_data *tree = desc->dyn_tree;
|
ct_data *tree = desc->dyn_tree;
|
||||||
int max_code = desc->max_code;
|
int max_code = desc->max_code;
|
||||||
const ct_data *stree = desc->stat_desc->static_tree;
|
const ct_data *stree = desc->stat_desc->static_tree;
|
||||||
|
@ -507,7 +556,7 @@ local void gen_bitlen(s, desc)
|
||||||
*/
|
*/
|
||||||
tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
|
tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
|
||||||
|
|
||||||
for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
|
for (h = s->heap_max + 1; h < HEAP_SIZE; h++) {
|
||||||
n = s->heap[h];
|
n = s->heap[h];
|
||||||
bits = tree[tree[n].Dad].Len + 1;
|
bits = tree[tree[n].Dad].Len + 1;
|
||||||
if (bits > max_length) bits = max_length, overflow++;
|
if (bits > max_length) bits = max_length, overflow++;
|
||||||
|
@ -518,7 +567,7 @@ local void gen_bitlen(s, desc)
|
||||||
|
|
||||||
s->bl_count[bits]++;
|
s->bl_count[bits]++;
|
||||||
xbits = 0;
|
xbits = 0;
|
||||||
if (n >= base) xbits = extra[n-base];
|
if (n >= base) xbits = extra[n - base];
|
||||||
f = tree[n].Freq;
|
f = tree[n].Freq;
|
||||||
s->opt_len += (ulg)f * (unsigned)(bits + xbits);
|
s->opt_len += (ulg)f * (unsigned)(bits + xbits);
|
||||||
if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);
|
if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits);
|
||||||
|
@ -530,10 +579,10 @@ local void gen_bitlen(s, desc)
|
||||||
|
|
||||||
/* Find the first bit length which could increase: */
|
/* Find the first bit length which could increase: */
|
||||||
do {
|
do {
|
||||||
bits = max_length-1;
|
bits = max_length - 1;
|
||||||
while (s->bl_count[bits] == 0) bits--;
|
while (s->bl_count[bits] == 0) bits--;
|
||||||
s->bl_count[bits]--; /* move one leaf down the tree */
|
s->bl_count[bits]--; /* move one leaf down the tree */
|
||||||
s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
|
s->bl_count[bits + 1] += 2; /* move one overflow item as its brother */
|
||||||
s->bl_count[max_length]--;
|
s->bl_count[max_length]--;
|
||||||
/* The brother of the overflow item also moves one step up,
|
/* The brother of the overflow item also moves one step up,
|
||||||
* but this does not affect bl_count[max_length]
|
* but this does not affect bl_count[max_length]
|
||||||
|
@ -561,48 +610,9 @@ local void gen_bitlen(s, desc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
#ifdef DUMP_BL_TREE
|
||||||
* Generate the codes for a given tree and bit counts (which need not be
|
# include <stdio.h>
|
||||||
* optimal).
|
#endif
|
||||||
* IN assertion: the array bl_count contains the bit length statistics for
|
|
||||||
* the given tree and the field len is set for all tree elements.
|
|
||||||
* OUT assertion: the field code is set for all tree elements of non
|
|
||||||
* zero code length.
|
|
||||||
*/
|
|
||||||
local void gen_codes (tree, max_code, bl_count)
|
|
||||||
ct_data *tree; /* the tree to decorate */
|
|
||||||
int max_code; /* largest code with non zero frequency */
|
|
||||||
ushf *bl_count; /* number of codes at each bit length */
|
|
||||||
{
|
|
||||||
ush next_code[MAX_BITS+1]; /* next code value for each bit length */
|
|
||||||
unsigned code = 0; /* running code value */
|
|
||||||
int bits; /* bit index */
|
|
||||||
int n; /* code index */
|
|
||||||
|
|
||||||
/* The distribution counts are first used to generate the code values
|
|
||||||
* without bit reversal.
|
|
||||||
*/
|
|
||||||
for (bits = 1; bits <= MAX_BITS; bits++) {
|
|
||||||
code = (code + bl_count[bits-1]) << 1;
|
|
||||||
next_code[bits] = (ush)code;
|
|
||||||
}
|
|
||||||
/* Check that the bit counts in bl_count are consistent. The last code
|
|
||||||
* must be all ones.
|
|
||||||
*/
|
|
||||||
Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
|
|
||||||
"inconsistent bit counts");
|
|
||||||
Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
|
|
||||||
|
|
||||||
for (n = 0; n <= max_code; n++) {
|
|
||||||
int len = tree[n].Len;
|
|
||||||
if (len == 0) continue;
|
|
||||||
/* Now reverse the bits */
|
|
||||||
tree[n].Code = (ush)bi_reverse(next_code[len]++, len);
|
|
||||||
|
|
||||||
Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
|
|
||||||
n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Construct one Huffman tree and assigns the code bit strings and lengths.
|
* Construct one Huffman tree and assigns the code bit strings and lengths.
|
||||||
|
@ -612,10 +622,7 @@ local void gen_codes (tree, max_code, bl_count)
|
||||||
* and corresponding code. The length opt_len is updated; static_len is
|
* and corresponding code. The length opt_len is updated; static_len is
|
||||||
* also updated if stree is not null. The field max_code is set.
|
* also updated if stree is not null. The field max_code is set.
|
||||||
*/
|
*/
|
||||||
local void build_tree(s, desc)
|
local void build_tree(deflate_state *s, tree_desc *desc) {
|
||||||
deflate_state *s;
|
|
||||||
tree_desc *desc; /* the tree descriptor */
|
|
||||||
{
|
|
||||||
ct_data *tree = desc->dyn_tree;
|
ct_data *tree = desc->dyn_tree;
|
||||||
const ct_data *stree = desc->stat_desc->static_tree;
|
const ct_data *stree = desc->stat_desc->static_tree;
|
||||||
int elems = desc->stat_desc->elems;
|
int elems = desc->stat_desc->elems;
|
||||||
|
@ -624,7 +631,7 @@ local void build_tree(s, desc)
|
||||||
int node; /* new node being created */
|
int node; /* new node being created */
|
||||||
|
|
||||||
/* Construct the initial heap, with least frequent element in
|
/* Construct the initial heap, with least frequent element in
|
||||||
* heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
|
* heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n + 1].
|
||||||
* heap[0] is not used.
|
* heap[0] is not used.
|
||||||
*/
|
*/
|
||||||
s->heap_len = 0, s->heap_max = HEAP_SIZE;
|
s->heap_len = 0, s->heap_max = HEAP_SIZE;
|
||||||
|
@ -652,7 +659,7 @@ local void build_tree(s, desc)
|
||||||
}
|
}
|
||||||
desc->max_code = max_code;
|
desc->max_code = max_code;
|
||||||
|
|
||||||
/* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
|
/* The elements heap[heap_len/2 + 1 .. heap_len] are leaves of the tree,
|
||||||
* establish sub-heaps of increasing lengths:
|
* establish sub-heaps of increasing lengths:
|
||||||
*/
|
*/
|
||||||
for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
|
for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
|
||||||
|
@ -700,11 +707,7 @@ local void build_tree(s, desc)
|
||||||
* Scan a literal or distance tree to determine the frequencies of the codes
|
* Scan a literal or distance tree to determine the frequencies of the codes
|
||||||
* in the bit length tree.
|
* in the bit length tree.
|
||||||
*/
|
*/
|
||||||
local void scan_tree (s, tree, max_code)
|
local void scan_tree(deflate_state *s, ct_data *tree, int max_code) {
|
||||||
deflate_state *s;
|
|
||||||
ct_data *tree; /* the tree to be scanned */
|
|
||||||
int max_code; /* and its largest code of non zero frequency */
|
|
||||||
{
|
|
||||||
int n; /* iterates over all tree elements */
|
int n; /* iterates over all tree elements */
|
||||||
int prevlen = -1; /* last emitted length */
|
int prevlen = -1; /* last emitted length */
|
||||||
int curlen; /* length of current code */
|
int curlen; /* length of current code */
|
||||||
|
@ -714,10 +717,10 @@ local void scan_tree (s, tree, max_code)
|
||||||
int min_count = 4; /* min repeat count */
|
int min_count = 4; /* min repeat count */
|
||||||
|
|
||||||
if (nextlen == 0) max_count = 138, min_count = 3;
|
if (nextlen == 0) max_count = 138, min_count = 3;
|
||||||
tree[max_code+1].Len = (ush)0xffff; /* guard */
|
tree[max_code + 1].Len = (ush)0xffff; /* guard */
|
||||||
|
|
||||||
for (n = 0; n <= max_code; n++) {
|
for (n = 0; n <= max_code; n++) {
|
||||||
curlen = nextlen; nextlen = tree[n+1].Len;
|
curlen = nextlen; nextlen = tree[n + 1].Len;
|
||||||
if (++count < max_count && curlen == nextlen) {
|
if (++count < max_count && curlen == nextlen) {
|
||||||
continue;
|
continue;
|
||||||
} else if (count < min_count) {
|
} else if (count < min_count) {
|
||||||
|
@ -745,11 +748,7 @@ local void scan_tree (s, tree, max_code)
|
||||||
* Send a literal or distance tree in compressed form, using the codes in
|
* Send a literal or distance tree in compressed form, using the codes in
|
||||||
* bl_tree.
|
* bl_tree.
|
||||||
*/
|
*/
|
||||||
local void send_tree (s, tree, max_code)
|
local void send_tree(deflate_state *s, ct_data *tree, int max_code) {
|
||||||
deflate_state *s;
|
|
||||||
ct_data *tree; /* the tree to be scanned */
|
|
||||||
int max_code; /* and its largest code of non zero frequency */
|
|
||||||
{
|
|
||||||
int n; /* iterates over all tree elements */
|
int n; /* iterates over all tree elements */
|
||||||
int prevlen = -1; /* last emitted length */
|
int prevlen = -1; /* last emitted length */
|
||||||
int curlen; /* length of current code */
|
int curlen; /* length of current code */
|
||||||
|
@ -758,11 +757,11 @@ local void send_tree (s, tree, max_code)
|
||||||
int max_count = 7; /* max repeat count */
|
int max_count = 7; /* max repeat count */
|
||||||
int min_count = 4; /* min repeat count */
|
int min_count = 4; /* min repeat count */
|
||||||
|
|
||||||
/* tree[max_code+1].Len = -1; */ /* guard already set */
|
/* tree[max_code + 1].Len = -1; */ /* guard already set */
|
||||||
if (nextlen == 0) max_count = 138, min_count = 3;
|
if (nextlen == 0) max_count = 138, min_count = 3;
|
||||||
|
|
||||||
for (n = 0; n <= max_code; n++) {
|
for (n = 0; n <= max_code; n++) {
|
||||||
curlen = nextlen; nextlen = tree[n+1].Len;
|
curlen = nextlen; nextlen = tree[n + 1].Len;
|
||||||
if (++count < max_count && curlen == nextlen) {
|
if (++count < max_count && curlen == nextlen) {
|
||||||
continue;
|
continue;
|
||||||
} else if (count < min_count) {
|
} else if (count < min_count) {
|
||||||
|
@ -773,13 +772,13 @@ local void send_tree (s, tree, max_code)
|
||||||
send_code(s, curlen, s->bl_tree); count--;
|
send_code(s, curlen, s->bl_tree); count--;
|
||||||
}
|
}
|
||||||
Assert(count >= 3 && count <= 6, " 3_6?");
|
Assert(count >= 3 && count <= 6, " 3_6?");
|
||||||
send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
|
send_code(s, REP_3_6, s->bl_tree); send_bits(s, count - 3, 2);
|
||||||
|
|
||||||
} else if (count <= 10) {
|
} else if (count <= 10) {
|
||||||
send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
|
send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count - 3, 3);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
|
send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count - 11, 7);
|
||||||
}
|
}
|
||||||
count = 0; prevlen = curlen;
|
count = 0; prevlen = curlen;
|
||||||
if (nextlen == 0) {
|
if (nextlen == 0) {
|
||||||
|
@ -796,9 +795,7 @@ local void send_tree (s, tree, max_code)
|
||||||
* Construct the Huffman tree for the bit lengths and return the index in
|
* Construct the Huffman tree for the bit lengths and return the index in
|
||||||
* bl_order of the last bit length code to send.
|
* bl_order of the last bit length code to send.
|
||||||
*/
|
*/
|
||||||
local int build_bl_tree(s)
|
local int build_bl_tree(deflate_state *s) {
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
int max_blindex; /* index of last bit length code of non zero freq */
|
int max_blindex; /* index of last bit length code of non zero freq */
|
||||||
|
|
||||||
/* Determine the bit length frequencies for literal and distance trees */
|
/* Determine the bit length frequencies for literal and distance trees */
|
||||||
|
@ -807,8 +804,8 @@ local int build_bl_tree(s)
|
||||||
|
|
||||||
/* Build the bit length tree: */
|
/* Build the bit length tree: */
|
||||||
build_tree(s, (tree_desc *)(&(s->bl_desc)));
|
build_tree(s, (tree_desc *)(&(s->bl_desc)));
|
||||||
/* opt_len now includes the length of the tree representations, except
|
/* opt_len now includes the length of the tree representations, except the
|
||||||
* the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
|
* lengths of the bit lengths codes and the 5 + 5 + 4 bits for the counts.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Determine the number of bit length codes to send. The pkzip format
|
/* Determine the number of bit length codes to send. The pkzip format
|
||||||
|
@ -819,7 +816,7 @@ local int build_bl_tree(s)
|
||||||
if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
|
if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
|
||||||
}
|
}
|
||||||
/* Update opt_len to include the bit length tree and counts */
|
/* Update opt_len to include the bit length tree and counts */
|
||||||
s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4;
|
s->opt_len += 3*((ulg)max_blindex + 1) + 5 + 5 + 4;
|
||||||
Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
|
Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
|
||||||
s->opt_len, s->static_len));
|
s->opt_len, s->static_len));
|
||||||
|
|
||||||
|
@ -831,61 +828,54 @@ local int build_bl_tree(s)
|
||||||
* lengths of the bit length codes, the literal tree and the distance tree.
|
* lengths of the bit length codes, the literal tree and the distance tree.
|
||||||
* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
|
* IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
|
||||||
*/
|
*/
|
||||||
local void send_all_trees(s, lcodes, dcodes, blcodes)
|
local void send_all_trees(deflate_state *s, int lcodes, int dcodes,
|
||||||
deflate_state *s;
|
int blcodes) {
|
||||||
int lcodes, dcodes, blcodes; /* number of codes for each tree */
|
|
||||||
{
|
|
||||||
int rank; /* index in bl_order */
|
int rank; /* index in bl_order */
|
||||||
|
|
||||||
Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
|
Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
|
||||||
Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
|
Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
|
||||||
"too many codes");
|
"too many codes");
|
||||||
Tracev((stderr, "\nbl counts: "));
|
Tracev((stderr, "\nbl counts: "));
|
||||||
send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
|
send_bits(s, lcodes - 257, 5); /* not +255 as stated in appnote.txt */
|
||||||
send_bits(s, dcodes-1, 5);
|
send_bits(s, dcodes - 1, 5);
|
||||||
send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
|
send_bits(s, blcodes - 4, 4); /* not -3 as stated in appnote.txt */
|
||||||
for (rank = 0; rank < blcodes; rank++) {
|
for (rank = 0; rank < blcodes; rank++) {
|
||||||
Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
|
Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
|
||||||
send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
|
send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
|
||||||
}
|
}
|
||||||
Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
|
Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
|
||||||
|
|
||||||
send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
|
send_tree(s, (ct_data *)s->dyn_ltree, lcodes - 1); /* literal tree */
|
||||||
Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
|
Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
|
||||||
|
|
||||||
send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
|
send_tree(s, (ct_data *)s->dyn_dtree, dcodes - 1); /* distance tree */
|
||||||
Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
|
Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Send a stored block
|
* Send a stored block
|
||||||
*/
|
*/
|
||||||
void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last)
|
void ZLIB_INTERNAL _tr_stored_block(deflate_state *s, charf *buf,
|
||||||
deflate_state *s;
|
ulg stored_len, int last) {
|
||||||
charf *buf; /* input block */
|
send_bits(s, (STORED_BLOCK<<1) + last, 3); /* send block type */
|
||||||
ulg stored_len; /* length of input block */
|
|
||||||
int last; /* one if this is the last block for a file */
|
|
||||||
{
|
|
||||||
send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */
|
|
||||||
bi_windup(s); /* align on byte boundary */
|
bi_windup(s); /* align on byte boundary */
|
||||||
put_short(s, (ush)stored_len);
|
put_short(s, (ush)stored_len);
|
||||||
put_short(s, (ush)~stored_len);
|
put_short(s, (ush)~stored_len);
|
||||||
zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);
|
if (stored_len)
|
||||||
|
zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len);
|
||||||
s->pending += stored_len;
|
s->pending += stored_len;
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
|
s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
|
||||||
s->compressed_len += (stored_len + 4) << 3;
|
s->compressed_len += (stored_len + 4) << 3;
|
||||||
s->bits_sent += 2*16;
|
s->bits_sent += 2*16;
|
||||||
s->bits_sent += stored_len<<3;
|
s->bits_sent += stored_len << 3;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
|
* Flush the bits in the bit buffer to pending output (leaves at most 7 bits)
|
||||||
*/
|
*/
|
||||||
void ZLIB_INTERNAL _tr_flush_bits(s)
|
void ZLIB_INTERNAL _tr_flush_bits(deflate_state *s) {
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
bi_flush(s);
|
bi_flush(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,9 +883,7 @@ void ZLIB_INTERNAL _tr_flush_bits(s)
|
||||||
* Send one empty static block to give enough lookahead for inflate.
|
* Send one empty static block to give enough lookahead for inflate.
|
||||||
* This takes 10 bits, of which 7 may remain in the bit buffer.
|
* This takes 10 bits, of which 7 may remain in the bit buffer.
|
||||||
*/
|
*/
|
||||||
void ZLIB_INTERNAL _tr_align(s)
|
void ZLIB_INTERNAL _tr_align(deflate_state *s) {
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
send_bits(s, STATIC_TREES<<1, 3);
|
send_bits(s, STATIC_TREES<<1, 3);
|
||||||
send_code(s, END_BLOCK, static_ltree);
|
send_code(s, END_BLOCK, static_ltree);
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
|
@ -904,16 +892,99 @@ void ZLIB_INTERNAL _tr_align(s)
|
||||||
bi_flush(s);
|
bi_flush(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Send the block data compressed using the given Huffman trees
|
||||||
|
*/
|
||||||
|
local void compress_block(deflate_state *s, const ct_data *ltree,
|
||||||
|
const ct_data *dtree) {
|
||||||
|
unsigned dist; /* distance of matched string */
|
||||||
|
int lc; /* match length or unmatched char (if dist == 0) */
|
||||||
|
unsigned sx = 0; /* running index in sym_buf */
|
||||||
|
unsigned code; /* the code to send */
|
||||||
|
int extra; /* number of extra bits to send */
|
||||||
|
|
||||||
|
if (s->sym_next != 0) do {
|
||||||
|
dist = s->sym_buf[sx++] & 0xff;
|
||||||
|
dist += (unsigned)(s->sym_buf[sx++] & 0xff) << 8;
|
||||||
|
lc = s->sym_buf[sx++];
|
||||||
|
if (dist == 0) {
|
||||||
|
send_code(s, lc, ltree); /* send a literal byte */
|
||||||
|
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
|
||||||
|
} else {
|
||||||
|
/* Here, lc is the match length - MIN_MATCH */
|
||||||
|
code = _length_code[lc];
|
||||||
|
send_code(s, code + LITERALS + 1, ltree); /* send length code */
|
||||||
|
extra = extra_lbits[code];
|
||||||
|
if (extra != 0) {
|
||||||
|
lc -= base_length[code];
|
||||||
|
send_bits(s, lc, extra); /* send the extra length bits */
|
||||||
|
}
|
||||||
|
dist--; /* dist is now the match distance - 1 */
|
||||||
|
code = d_code(dist);
|
||||||
|
Assert (code < D_CODES, "bad d_code");
|
||||||
|
|
||||||
|
send_code(s, code, dtree); /* send the distance code */
|
||||||
|
extra = extra_dbits[code];
|
||||||
|
if (extra != 0) {
|
||||||
|
dist -= (unsigned)base_dist[code];
|
||||||
|
send_bits(s, dist, extra); /* send the extra distance bits */
|
||||||
|
}
|
||||||
|
} /* literal or match pair ? */
|
||||||
|
|
||||||
|
/* Check that the overlay between pending_buf and sym_buf is ok: */
|
||||||
|
Assert(s->pending < s->lit_bufsize + sx, "pendingBuf overflow");
|
||||||
|
|
||||||
|
} while (sx < s->sym_next);
|
||||||
|
|
||||||
|
send_code(s, END_BLOCK, ltree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===========================================================================
|
||||||
|
* Check if the data type is TEXT or BINARY, using the following algorithm:
|
||||||
|
* - TEXT if the two conditions below are satisfied:
|
||||||
|
* a) There are no non-portable control characters belonging to the
|
||||||
|
* "block list" (0..6, 14..25, 28..31).
|
||||||
|
* b) There is at least one printable character belonging to the
|
||||||
|
* "allow list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
|
||||||
|
* - BINARY otherwise.
|
||||||
|
* - The following partially-portable control characters form a
|
||||||
|
* "gray list" that is ignored in this detection algorithm:
|
||||||
|
* (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
|
||||||
|
* IN assertion: the fields Freq of dyn_ltree are set.
|
||||||
|
*/
|
||||||
|
local int detect_data_type(deflate_state *s) {
|
||||||
|
/* block_mask is the bit mask of block-listed bytes
|
||||||
|
* set bits 0..6, 14..25, and 28..31
|
||||||
|
* 0xf3ffc07f = binary 11110011111111111100000001111111
|
||||||
|
*/
|
||||||
|
unsigned long block_mask = 0xf3ffc07fUL;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* Check for non-textual ("block-listed") bytes. */
|
||||||
|
for (n = 0; n <= 31; n++, block_mask >>= 1)
|
||||||
|
if ((block_mask & 1) && (s->dyn_ltree[n].Freq != 0))
|
||||||
|
return Z_BINARY;
|
||||||
|
|
||||||
|
/* Check for textual ("allow-listed") bytes. */
|
||||||
|
if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
|
||||||
|
|| s->dyn_ltree[13].Freq != 0)
|
||||||
|
return Z_TEXT;
|
||||||
|
for (n = 32; n < LITERALS; n++)
|
||||||
|
if (s->dyn_ltree[n].Freq != 0)
|
||||||
|
return Z_TEXT;
|
||||||
|
|
||||||
|
/* There are no "block-listed" or "allow-listed" bytes:
|
||||||
|
* this stream either is empty or has tolerated ("gray-listed") bytes only.
|
||||||
|
*/
|
||||||
|
return Z_BINARY;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Determine the best encoding for the current block: dynamic trees, static
|
* Determine the best encoding for the current block: dynamic trees, static
|
||||||
* trees or store, and write out the encoded block.
|
* trees or store, and write out the encoded block.
|
||||||
*/
|
*/
|
||||||
void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
|
void ZLIB_INTERNAL _tr_flush_block(deflate_state *s, charf *buf,
|
||||||
deflate_state *s;
|
ulg stored_len, int last) {
|
||||||
charf *buf; /* input block, or NULL if too old */
|
|
||||||
ulg stored_len; /* length of input block */
|
|
||||||
int last; /* one if this is the last block for a file */
|
|
||||||
{
|
|
||||||
ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
|
ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
|
||||||
int max_blindex = 0; /* index of last bit length code of non zero freq */
|
int max_blindex = 0; /* index of last bit length code of non zero freq */
|
||||||
|
|
||||||
|
@ -942,14 +1013,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
|
||||||
max_blindex = build_bl_tree(s);
|
max_blindex = build_bl_tree(s);
|
||||||
|
|
||||||
/* Determine the best encoding. Compute the block lengths in bytes. */
|
/* Determine the best encoding. Compute the block lengths in bytes. */
|
||||||
opt_lenb = (s->opt_len+3+7)>>3;
|
opt_lenb = (s->opt_len + 3 + 7) >> 3;
|
||||||
static_lenb = (s->static_len+3+7)>>3;
|
static_lenb = (s->static_len + 3 + 7) >> 3;
|
||||||
|
|
||||||
Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
|
Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
|
||||||
opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
|
opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
|
||||||
s->last_lit));
|
s->sym_next / 3));
|
||||||
|
|
||||||
if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
|
#ifndef FORCE_STATIC
|
||||||
|
if (static_lenb <= opt_lenb || s->strategy == Z_FIXED)
|
||||||
|
#endif
|
||||||
|
opt_lenb = static_lenb;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Assert(buf != (char*)0, "lost buf");
|
Assert(buf != (char*)0, "lost buf");
|
||||||
|
@ -959,7 +1033,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
|
||||||
#ifdef FORCE_STORED
|
#ifdef FORCE_STORED
|
||||||
if (buf != (char*)0) { /* force stored block */
|
if (buf != (char*)0) { /* force stored block */
|
||||||
#else
|
#else
|
||||||
if (stored_len+4 <= opt_lenb && buf != (char*)0) {
|
if (stored_len + 4 <= opt_lenb && buf != (char*)0) {
|
||||||
/* 4: two words for the lengths */
|
/* 4: two words for the lengths */
|
||||||
#endif
|
#endif
|
||||||
/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
|
/* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
|
||||||
|
@ -970,21 +1044,17 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
|
||||||
*/
|
*/
|
||||||
_tr_stored_block(s, buf, stored_len, last);
|
_tr_stored_block(s, buf, stored_len, last);
|
||||||
|
|
||||||
#ifdef FORCE_STATIC
|
} else if (static_lenb == opt_lenb) {
|
||||||
} else if (static_lenb >= 0) { /* force static trees */
|
send_bits(s, (STATIC_TREES<<1) + last, 3);
|
||||||
#else
|
|
||||||
} else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
|
|
||||||
#endif
|
|
||||||
send_bits(s, (STATIC_TREES<<1)+last, 3);
|
|
||||||
compress_block(s, (const ct_data *)static_ltree,
|
compress_block(s, (const ct_data *)static_ltree,
|
||||||
(const ct_data *)static_dtree);
|
(const ct_data *)static_dtree);
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
s->compressed_len += 3 + s->static_len;
|
s->compressed_len += 3 + s->static_len;
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
send_bits(s, (DYN_TREES<<1)+last, 3);
|
send_bits(s, (DYN_TREES<<1) + last, 3);
|
||||||
send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
|
send_all_trees(s, s->l_desc.max_code + 1, s->d_desc.max_code + 1,
|
||||||
max_blindex+1);
|
max_blindex + 1);
|
||||||
compress_block(s, (const ct_data *)s->dyn_ltree,
|
compress_block(s, (const ct_data *)s->dyn_ltree,
|
||||||
(const ct_data *)s->dyn_dtree);
|
(const ct_data *)s->dyn_dtree);
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
|
@ -1003,21 +1073,18 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last)
|
||||||
s->compressed_len += 7; /* align on byte boundary */
|
s->compressed_len += 7; /* align on byte boundary */
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
|
Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len >> 3,
|
||||||
s->compressed_len-7*last));
|
s->compressed_len - 7*last));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===========================================================================
|
/* ===========================================================================
|
||||||
* Save the match info and tally the frequency counts. Return true if
|
* Save the match info and tally the frequency counts. Return true if
|
||||||
* the current block must be flushed.
|
* the current block must be flushed.
|
||||||
*/
|
*/
|
||||||
int ZLIB_INTERNAL _tr_tally (s, dist, lc)
|
int ZLIB_INTERNAL _tr_tally(deflate_state *s, unsigned dist, unsigned lc) {
|
||||||
deflate_state *s;
|
s->sym_buf[s->sym_next++] = (uch)dist;
|
||||||
unsigned dist; /* distance of matched string */
|
s->sym_buf[s->sym_next++] = (uch)(dist >> 8);
|
||||||
unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
|
s->sym_buf[s->sym_next++] = (uch)lc;
|
||||||
{
|
|
||||||
s->d_buf[s->last_lit] = (ush)dist;
|
|
||||||
s->l_buf[s->last_lit++] = (uch)lc;
|
|
||||||
if (dist == 0) {
|
if (dist == 0) {
|
||||||
/* lc is the unmatched char */
|
/* lc is the unmatched char */
|
||||||
s->dyn_ltree[lc].Freq++;
|
s->dyn_ltree[lc].Freq++;
|
||||||
|
@ -1029,175 +1096,8 @@ int ZLIB_INTERNAL _tr_tally (s, dist, lc)
|
||||||
(ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
|
(ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
|
||||||
(ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
|
(ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
|
||||||
|
|
||||||
s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
|
s->dyn_ltree[_length_code[lc] + LITERALS + 1].Freq++;
|
||||||
s->dyn_dtree[d_code(dist)].Freq++;
|
s->dyn_dtree[d_code(dist)].Freq++;
|
||||||
}
|
}
|
||||||
|
return (s->sym_next == s->sym_end);
|
||||||
#ifdef TRUNCATE_BLOCK
|
|
||||||
/* Try to guess if it is profitable to stop the current block here */
|
|
||||||
if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
|
|
||||||
/* Compute an upper bound for the compressed length */
|
|
||||||
ulg out_length = (ulg)s->last_lit*8L;
|
|
||||||
ulg in_length = (ulg)((long)s->strstart - s->block_start);
|
|
||||||
int dcode;
|
|
||||||
for (dcode = 0; dcode < D_CODES; dcode++) {
|
|
||||||
out_length += (ulg)s->dyn_dtree[dcode].Freq *
|
|
||||||
(5L+extra_dbits[dcode]);
|
|
||||||
}
|
|
||||||
out_length >>= 3;
|
|
||||||
Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
|
|
||||||
s->last_lit, in_length, out_length,
|
|
||||||
100L - out_length*100L/in_length));
|
|
||||||
if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return (s->last_lit == s->lit_bufsize-1);
|
|
||||||
/* We avoid equality with lit_bufsize because of wraparound at 64K
|
|
||||||
* on 16 bit machines and because stored blocks are restricted to
|
|
||||||
* 64K-1 bytes.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Send the block data compressed using the given Huffman trees
|
|
||||||
*/
|
|
||||||
local void compress_block(s, ltree, dtree)
|
|
||||||
deflate_state *s;
|
|
||||||
const ct_data *ltree; /* literal tree */
|
|
||||||
const ct_data *dtree; /* distance tree */
|
|
||||||
{
|
|
||||||
unsigned dist; /* distance of matched string */
|
|
||||||
int lc; /* match length or unmatched char (if dist == 0) */
|
|
||||||
unsigned lx = 0; /* running index in l_buf */
|
|
||||||
unsigned code; /* the code to send */
|
|
||||||
int extra; /* number of extra bits to send */
|
|
||||||
|
|
||||||
if (s->last_lit != 0) do {
|
|
||||||
dist = s->d_buf[lx];
|
|
||||||
lc = s->l_buf[lx++];
|
|
||||||
if (dist == 0) {
|
|
||||||
send_code(s, lc, ltree); /* send a literal byte */
|
|
||||||
Tracecv(isgraph(lc), (stderr," '%c' ", lc));
|
|
||||||
} else {
|
|
||||||
/* Here, lc is the match length - MIN_MATCH */
|
|
||||||
code = _length_code[lc];
|
|
||||||
send_code(s, code+LITERALS+1, ltree); /* send the length code */
|
|
||||||
extra = extra_lbits[code];
|
|
||||||
if (extra != 0) {
|
|
||||||
lc -= base_length[code];
|
|
||||||
send_bits(s, lc, extra); /* send the extra length bits */
|
|
||||||
}
|
|
||||||
dist--; /* dist is now the match distance - 1 */
|
|
||||||
code = d_code(dist);
|
|
||||||
Assert (code < D_CODES, "bad d_code");
|
|
||||||
|
|
||||||
send_code(s, code, dtree); /* send the distance code */
|
|
||||||
extra = extra_dbits[code];
|
|
||||||
if (extra != 0) {
|
|
||||||
dist -= (unsigned)base_dist[code];
|
|
||||||
send_bits(s, dist, extra); /* send the extra distance bits */
|
|
||||||
}
|
|
||||||
} /* literal or match pair ? */
|
|
||||||
|
|
||||||
/* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
|
|
||||||
Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
|
|
||||||
"pendingBuf overflow");
|
|
||||||
|
|
||||||
} while (lx < s->last_lit);
|
|
||||||
|
|
||||||
send_code(s, END_BLOCK, ltree);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Check if the data type is TEXT or BINARY, using the following algorithm:
|
|
||||||
* - TEXT if the two conditions below are satisfied:
|
|
||||||
* a) There are no non-portable control characters belonging to the
|
|
||||||
* "black list" (0..6, 14..25, 28..31).
|
|
||||||
* b) There is at least one printable character belonging to the
|
|
||||||
* "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
|
|
||||||
* - BINARY otherwise.
|
|
||||||
* - The following partially-portable control characters form a
|
|
||||||
* "gray list" that is ignored in this detection algorithm:
|
|
||||||
* (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
|
|
||||||
* IN assertion: the fields Freq of dyn_ltree are set.
|
|
||||||
*/
|
|
||||||
local int detect_data_type(s)
|
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
/* black_mask is the bit mask of black-listed bytes
|
|
||||||
* set bits 0..6, 14..25, and 28..31
|
|
||||||
* 0xf3ffc07f = binary 11110011111111111100000001111111
|
|
||||||
*/
|
|
||||||
unsigned long black_mask = 0xf3ffc07fUL;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
/* Check for non-textual ("black-listed") bytes. */
|
|
||||||
for (n = 0; n <= 31; n++, black_mask >>= 1)
|
|
||||||
if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0))
|
|
||||||
return Z_BINARY;
|
|
||||||
|
|
||||||
/* Check for textual ("white-listed") bytes. */
|
|
||||||
if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0
|
|
||||||
|| s->dyn_ltree[13].Freq != 0)
|
|
||||||
return Z_TEXT;
|
|
||||||
for (n = 32; n < LITERALS; n++)
|
|
||||||
if (s->dyn_ltree[n].Freq != 0)
|
|
||||||
return Z_TEXT;
|
|
||||||
|
|
||||||
/* There are no "black-listed" or "white-listed" bytes:
|
|
||||||
* this stream either is empty or has tolerated ("gray-listed") bytes only.
|
|
||||||
*/
|
|
||||||
return Z_BINARY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Reverse the first len bits of a code, using straightforward code (a faster
|
|
||||||
* method would use a table)
|
|
||||||
* IN assertion: 1 <= len <= 15
|
|
||||||
*/
|
|
||||||
local unsigned bi_reverse(code, len)
|
|
||||||
unsigned code; /* the value to invert */
|
|
||||||
int len; /* its bit length */
|
|
||||||
{
|
|
||||||
register unsigned res = 0;
|
|
||||||
do {
|
|
||||||
res |= code & 1;
|
|
||||||
code >>= 1, res <<= 1;
|
|
||||||
} while (--len > 0);
|
|
||||||
return res >> 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Flush the bit buffer, keeping at most 7 bits in it.
|
|
||||||
*/
|
|
||||||
local void bi_flush(s)
|
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
if (s->bi_valid == 16) {
|
|
||||||
put_short(s, s->bi_buf);
|
|
||||||
s->bi_buf = 0;
|
|
||||||
s->bi_valid = 0;
|
|
||||||
} else if (s->bi_valid >= 8) {
|
|
||||||
put_byte(s, (Byte)s->bi_buf);
|
|
||||||
s->bi_buf >>= 8;
|
|
||||||
s->bi_valid -= 8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ===========================================================================
|
|
||||||
* Flush the bit buffer and align the output on a byte boundary
|
|
||||||
*/
|
|
||||||
local void bi_windup(s)
|
|
||||||
deflate_state *s;
|
|
||||||
{
|
|
||||||
if (s->bi_valid > 8) {
|
|
||||||
put_short(s, s->bi_buf);
|
|
||||||
} else if (s->bi_valid > 0) {
|
|
||||||
put_byte(s, (Byte)s->bi_buf);
|
|
||||||
}
|
|
||||||
s->bi_buf = 0;
|
|
||||||
s->bi_valid = 0;
|
|
||||||
#ifdef ZLIB_DEBUG
|
|
||||||
s->bits_sent = (s->bits_sent+7) & ~7;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,8 @@
|
||||||
Z_DATA_ERROR if the input data was corrupted, including if the input data is
|
Z_DATA_ERROR if the input data was corrupted, including if the input data is
|
||||||
an incomplete zlib stream.
|
an incomplete zlib stream.
|
||||||
*/
|
*/
|
||||||
int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
|
int ZEXPORT uncompress2(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||||
Bytef *dest;
|
uLong *sourceLen) {
|
||||||
uLongf *destLen;
|
|
||||||
const Bytef *source;
|
|
||||||
uLong *sourceLen;
|
|
||||||
{
|
|
||||||
z_stream stream;
|
z_stream stream;
|
||||||
int err;
|
int err;
|
||||||
const uInt max = (uInt)-1;
|
const uInt max = (uInt)-1;
|
||||||
|
@ -83,11 +79,7 @@ int ZEXPORT uncompress2 (dest, destLen, source, sourceLen)
|
||||||
err;
|
err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZEXPORT uncompress (dest, destLen, source, sourceLen)
|
int ZEXPORT uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
|
||||||
Bytef *dest;
|
uLong sourceLen) {
|
||||||
uLongf *destLen;
|
|
||||||
const Bytef *source;
|
|
||||||
uLong sourceLen;
|
|
||||||
{
|
|
||||||
return uncompress2(dest, destLen, source, &sourceLen);
|
return uncompress2(dest, destLen, source, &sourceLen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,9 @@
|
||||||
# define crc32 z_crc32
|
# define crc32 z_crc32
|
||||||
# define crc32_combine z_crc32_combine
|
# define crc32_combine z_crc32_combine
|
||||||
# define crc32_combine64 z_crc32_combine64
|
# define crc32_combine64 z_crc32_combine64
|
||||||
|
# define crc32_combine_gen z_crc32_combine_gen
|
||||||
|
# define crc32_combine_gen64 z_crc32_combine_gen64
|
||||||
|
# define crc32_combine_op z_crc32_combine_op
|
||||||
# define crc32_z z_crc32_z
|
# define crc32_z z_crc32_z
|
||||||
# define deflate z_deflate
|
# define deflate z_deflate
|
||||||
# define deflateBound z_deflateBound
|
# define deflateBound z_deflateBound
|
||||||
|
@ -238,7 +241,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Z_SOLO
|
#ifdef Z_SOLO
|
||||||
typedef unsigned long z_size_t;
|
# ifdef _WIN64
|
||||||
|
typedef unsigned long long z_size_t;
|
||||||
|
# else
|
||||||
|
typedef unsigned long z_size_t;
|
||||||
|
# endif
|
||||||
#else
|
#else
|
||||||
# define z_longlong long long
|
# define z_longlong long long
|
||||||
# if defined(NO_SIZE_T)
|
# if defined(NO_SIZE_T)
|
||||||
|
@ -349,6 +356,9 @@
|
||||||
# ifdef FAR
|
# ifdef FAR
|
||||||
# undef FAR
|
# undef FAR
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
|
# define WIN32_LEAN_AND_MEAN
|
||||||
|
# endif
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
/* No need for _export, use ZLIB.DEF instead. */
|
/* No need for _export, use ZLIB.DEF instead. */
|
||||||
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
/* For complete Windows compatibility, use WINAPI, not __stdcall. */
|
||||||
|
@ -467,11 +477,18 @@ typedef uLong FAR uLongf;
|
||||||
# undef _LARGEFILE64_SOURCE
|
# undef _LARGEFILE64_SOURCE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)
|
#ifndef Z_HAVE_UNISTD_H
|
||||||
# define Z_HAVE_UNISTD_H
|
# ifdef __WATCOMC__
|
||||||
|
# define Z_HAVE_UNISTD_H
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#ifndef Z_HAVE_UNISTD_H
|
||||||
|
# if defined(_LARGEFILE64_SOURCE) && !defined(_WIN32)
|
||||||
|
# define Z_HAVE_UNISTD_H
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifndef Z_SOLO
|
#ifndef Z_SOLO
|
||||||
# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
|
# if defined(Z_HAVE_UNISTD_H)
|
||||||
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */
|
||||||
# ifdef VMS
|
# ifdef VMS
|
||||||
# include <unixio.h> /* for off_t */
|
# include <unixio.h> /* for off_t */
|
||||||
|
@ -507,7 +524,7 @@ typedef uLong FAR uLongf;
|
||||||
#if !defined(_WIN32) && defined(Z_LARGE64)
|
#if !defined(_WIN32) && defined(Z_LARGE64)
|
||||||
# define z_off64_t off64_t
|
# define z_off64_t off64_t
|
||||||
#else
|
#else
|
||||||
# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)
|
# if defined(_WIN32) && !defined(__GNUC__)
|
||||||
# define z_off64_t __int64
|
# define z_off64_t __int64
|
||||||
# else
|
# else
|
||||||
# define z_off64_t z_off_t
|
# define z_off64_t z_off_t
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -24,13 +24,11 @@ z_const char * const z_errmsg[10] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const char * ZEXPORT zlibVersion()
|
const char * ZEXPORT zlibVersion(void) {
|
||||||
{
|
|
||||||
return ZLIB_VERSION;
|
return ZLIB_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
uLong ZEXPORT zlibCompileFlags()
|
uLong ZEXPORT zlibCompileFlags(void) {
|
||||||
{
|
|
||||||
uLong flags;
|
uLong flags;
|
||||||
|
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
@ -61,9 +59,11 @@ uLong ZEXPORT zlibCompileFlags()
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
flags += 1 << 8;
|
flags += 1 << 8;
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
#if defined(ASMV) || defined(ASMINF)
|
#if defined(ASMV) || defined(ASMINF)
|
||||||
flags += 1 << 9;
|
flags += 1 << 9;
|
||||||
#endif
|
#endif
|
||||||
|
*/
|
||||||
#ifdef ZLIB_WINAPI
|
#ifdef ZLIB_WINAPI
|
||||||
flags += 1 << 10;
|
flags += 1 << 10;
|
||||||
#endif
|
#endif
|
||||||
|
@ -119,9 +119,7 @@ uLong ZEXPORT zlibCompileFlags()
|
||||||
# endif
|
# endif
|
||||||
int ZLIB_INTERNAL z_verbose = verbose;
|
int ZLIB_INTERNAL z_verbose = verbose;
|
||||||
|
|
||||||
void ZLIB_INTERNAL z_error (m)
|
void ZLIB_INTERNAL z_error(char *m) {
|
||||||
char *m;
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s\n", m);
|
fprintf(stderr, "%s\n", m);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
@ -130,14 +128,12 @@ void ZLIB_INTERNAL z_error (m)
|
||||||
/* exported to allow conversion of error code to string for compress() and
|
/* exported to allow conversion of error code to string for compress() and
|
||||||
* uncompress()
|
* uncompress()
|
||||||
*/
|
*/
|
||||||
const char * ZEXPORT zError(err)
|
const char * ZEXPORT zError(int err) {
|
||||||
int err;
|
|
||||||
{
|
|
||||||
return ERR_MSG(err);
|
return ERR_MSG(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(_WIN32_WCE)
|
#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800
|
||||||
/* The Microsoft C Run-Time Library for Windows CE doesn't have
|
/* The older Microsoft C Run-Time Library for Windows CE doesn't have
|
||||||
* errno. We define it as a global variable to simplify porting.
|
* errno. We define it as a global variable to simplify porting.
|
||||||
* Its value is always 0 and should not be used.
|
* Its value is always 0 and should not be used.
|
||||||
*/
|
*/
|
||||||
|
@ -146,22 +142,14 @@ const char * ZEXPORT zError(err)
|
||||||
|
|
||||||
#ifndef HAVE_MEMCPY
|
#ifndef HAVE_MEMCPY
|
||||||
|
|
||||||
void ZLIB_INTERNAL zmemcpy(dest, source, len)
|
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len) {
|
||||||
Bytef* dest;
|
|
||||||
const Bytef* source;
|
|
||||||
uInt len;
|
|
||||||
{
|
|
||||||
if (len == 0) return;
|
if (len == 0) return;
|
||||||
do {
|
do {
|
||||||
*dest++ = *source++; /* ??? to be unrolled */
|
*dest++ = *source++; /* ??? to be unrolled */
|
||||||
} while (--len != 0);
|
} while (--len != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZLIB_INTERNAL zmemcmp(s1, s2, len)
|
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len) {
|
||||||
const Bytef* s1;
|
|
||||||
const Bytef* s2;
|
|
||||||
uInt len;
|
|
||||||
{
|
|
||||||
uInt j;
|
uInt j;
|
||||||
|
|
||||||
for (j = 0; j < len; j++) {
|
for (j = 0; j < len; j++) {
|
||||||
|
@ -170,10 +158,7 @@ int ZLIB_INTERNAL zmemcmp(s1, s2, len)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLIB_INTERNAL zmemzero(dest, len)
|
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len) {
|
||||||
Bytef* dest;
|
|
||||||
uInt len;
|
|
||||||
{
|
|
||||||
if (len == 0) return;
|
if (len == 0) return;
|
||||||
do {
|
do {
|
||||||
*dest++ = 0; /* ??? to be unrolled */
|
*dest++ = 0; /* ??? to be unrolled */
|
||||||
|
@ -214,8 +199,7 @@ local ptr_table table[MAX_PTR];
|
||||||
* a protected system like OS/2. Use Microsoft C instead.
|
* a protected system like OS/2. Use Microsoft C instead.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
|
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
|
||||||
{
|
|
||||||
voidpf buf;
|
voidpf buf;
|
||||||
ulg bsize = (ulg)items*size;
|
ulg bsize = (ulg)items*size;
|
||||||
|
|
||||||
|
@ -240,8 +224,7 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size)
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
|
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
|
||||||
{
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
|
@ -277,14 +260,12 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
|
||||||
# define _hfree hfree
|
# define _hfree hfree
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size)
|
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, uInt items, uInt size) {
|
||||||
{
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
return _halloc((long)items, size);
|
return _halloc((long)items, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
|
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
|
||||||
{
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
_hfree(ptr);
|
_hfree(ptr);
|
||||||
}
|
}
|
||||||
|
@ -297,25 +278,18 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr)
|
||||||
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
|
#ifndef MY_ZCALLOC /* Any system without a special alloc function */
|
||||||
|
|
||||||
#ifndef STDC
|
#ifndef STDC
|
||||||
extern voidp malloc OF((uInt size));
|
extern voidp malloc(uInt size);
|
||||||
extern voidp calloc OF((uInt items, uInt size));
|
extern voidp calloc(uInt items, uInt size);
|
||||||
extern void free OF((voidpf ptr));
|
extern void free(voidpf ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
voidpf ZLIB_INTERNAL zcalloc (opaque, items, size)
|
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items, unsigned size) {
|
||||||
voidpf opaque;
|
|
||||||
unsigned items;
|
|
||||||
unsigned size;
|
|
||||||
{
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
|
return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
|
||||||
(voidpf)calloc(items, size);
|
(voidpf)calloc(items, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLIB_INTERNAL zcfree (opaque, ptr)
|
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr) {
|
||||||
voidpf opaque;
|
|
||||||
voidpf ptr;
|
|
||||||
{
|
|
||||||
(void)opaque;
|
(void)opaque;
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* zutil.h -- internal interface and configuration of the compression library
|
/* zutil.h -- internal interface and configuration of the compression library
|
||||||
* Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler
|
* Copyright (C) 1995-2022 Jean-loup Gailly, Mark Adler
|
||||||
* For conditions of distribution and use, see copyright notice in zlib.h
|
* For conditions of distribution and use, see copyright notice in zlib.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -29,10 +29,6 @@
|
||||||
# include <stdlib.h>
|
# include <stdlib.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef Z_SOLO
|
|
||||||
typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef local
|
#ifndef local
|
||||||
# define local static
|
# define local static
|
||||||
#endif
|
#endif
|
||||||
|
@ -46,6 +42,17 @@ typedef unsigned short ush;
|
||||||
typedef ush FAR ushf;
|
typedef ush FAR ushf;
|
||||||
typedef unsigned long ulg;
|
typedef unsigned long ulg;
|
||||||
|
|
||||||
|
#if !defined(Z_U8) && !defined(Z_SOLO) && defined(STDC)
|
||||||
|
# include <limits.h>
|
||||||
|
# if (ULONG_MAX == 0xffffffffffffffff)
|
||||||
|
# define Z_U8 unsigned long
|
||||||
|
# elif (ULLONG_MAX == 0xffffffffffffffff)
|
||||||
|
# define Z_U8 unsigned long long
|
||||||
|
# elif (UINT_MAX == 0xffffffffffffffff)
|
||||||
|
# define Z_U8 unsigned
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||||
/* (size given to avoid silly warnings with Visual C++) */
|
/* (size given to avoid silly warnings with Visual C++) */
|
||||||
|
|
||||||
|
@ -170,10 +177,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
|
#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX
|
||||||
# if defined(_WIN32_WCE)
|
# if defined(_WIN32_WCE)
|
||||||
# define fdopen(fd,mode) NULL /* No fdopen() */
|
# define fdopen(fd,mode) NULL /* No fdopen() */
|
||||||
# ifndef _PTRDIFF_T_DEFINED
|
|
||||||
typedef int ptrdiff_t;
|
|
||||||
# define _PTRDIFF_T_DEFINED
|
|
||||||
# endif
|
|
||||||
# else
|
# else
|
||||||
# define fdopen(fd,type) _fdopen(fd,type)
|
# define fdopen(fd,type) _fdopen(fd,type)
|
||||||
# endif
|
# endif
|
||||||
|
@ -188,8 +191,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||||
/* provide prototypes for these when building zlib without LFS */
|
/* provide prototypes for these when building zlib without LFS */
|
||||||
#if !defined(_WIN32) && \
|
#if !defined(_WIN32) && \
|
||||||
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
|
(!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0)
|
||||||
ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
|
ZEXTERN uLong ZEXPORT adler32_combine64(uLong, uLong, z_off_t);
|
||||||
ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
|
ZEXTERN uLong ZEXPORT crc32_combine64(uLong, uLong, z_off_t);
|
||||||
|
ZEXTERN uLong ZEXPORT crc32_combine_gen64(z_off_t);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* common defaults */
|
/* common defaults */
|
||||||
|
@ -228,16 +232,16 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||||
# define zmemzero(dest, len) memset(dest, 0, len)
|
# define zmemzero(dest, len) memset(dest, 0, len)
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
|
void ZLIB_INTERNAL zmemcpy(Bytef* dest, const Bytef* source, uInt len);
|
||||||
int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
|
int ZLIB_INTERNAL zmemcmp(const Bytef* s1, const Bytef* s2, uInt len);
|
||||||
void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len));
|
void ZLIB_INTERNAL zmemzero(Bytef* dest, uInt len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Diagnostic functions */
|
/* Diagnostic functions */
|
||||||
#ifdef ZLIB_DEBUG
|
#ifdef ZLIB_DEBUG
|
||||||
# include <stdio.h>
|
# include <stdio.h>
|
||||||
extern int ZLIB_INTERNAL z_verbose;
|
extern int ZLIB_INTERNAL z_verbose;
|
||||||
extern void ZLIB_INTERNAL z_error OF((char *m));
|
extern void ZLIB_INTERNAL z_error(char *m);
|
||||||
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
|
# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
|
||||||
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
|
# define Trace(x) {if (z_verbose>=0) fprintf x ;}
|
||||||
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
|
# define Tracev(x) {if (z_verbose>0) fprintf x ;}
|
||||||
|
@ -254,9 +258,9 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef Z_SOLO
|
#ifndef Z_SOLO
|
||||||
voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,
|
voidpf ZLIB_INTERNAL zcalloc(voidpf opaque, unsigned items,
|
||||||
unsigned size));
|
unsigned size);
|
||||||
void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));
|
void ZLIB_INTERNAL zcfree(voidpf opaque, voidpf ptr);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ZALLOC(strm, items, size) \
|
#define ZALLOC(strm, items, size) \
|
||||||
|
|
Loading…
Reference in New Issue