zlib 0.5.4.2 → 0.6.0.0
raw patch · 27 files changed
+1843/−734 lines, 27 filesdep +HUnitdep +QuickCheckdep +tastydep ~basedep ~bytestring
Dependencies added: HUnit, QuickCheck, tasty, tasty-hunit, tasty-quickcheck, zlib
Dependency ranges changed: base, bytestring
Files
- Codec/Compression/GZip.hs +2/−4
- Codec/Compression/Zlib.hs +2/−4
- Codec/Compression/Zlib/Internal.hs +493/−157
- Codec/Compression/Zlib/Raw.hs +2/−4
- Codec/Compression/Zlib/Stream.hsc +72/−47
- cbits/adler32.c +39/−29
- cbits/compress.c +1/−1
- cbits/crc32.c +33/−50
- cbits/crc32.h +1/−1
- cbits/deflate.c +197/−64
- cbits/deflate.h +8/−4
- cbits/infback.c +12/−4
- cbits/inffast.c +3/−3
- cbits/inffixed.h +3/−3
- cbits/inflate.c +84/−52
- cbits/inftrees.c +15/−39
- cbits/trees.c +18/−36
- cbits/uncompr.c +1/−1
- cbits/zconf.h +142/−59
- cbits/zlib.h +249/−94
- cbits/zutil.c +16/−10
- cbits/zutil.h +41/−62
- test/Test.hs +246/−0
- test/Test/Codec/Compression/Zlib/Internal.hs +57/−0
- test/Test/Codec/Compression/Zlib/Stream.hs +51/−0
- test/Utils.hs +28/−0
- zlib.cabal +27/−6
Codec/Compression/GZip.hs view
@@ -1,11 +1,9 @@ ----------------------------------------------------------------------------- -- |--- Copyright : (c) 2006-2008 Duncan Coutts+-- Copyright : (c) 2006-2014 Duncan Coutts -- License : BSD-style ----- Maintainer : duncan@haskell.org--- Stability : provisional--- Portability : portable (H98 + FFI)+-- Maintainer : duncan@community.haskell.org -- -- Compression and decompression of data streams in the gzip format. --
Codec/Compression/Zlib.hs view
@@ -1,11 +1,9 @@ ----------------------------------------------------------------------------- -- |--- Copyright : (c) 2006-2008 Duncan Coutts+-- Copyright : (c) 2006-2014 Duncan Coutts -- License : BSD-style ----- Maintainer : duncan@haskell.org--- Stability : provisional--- Portability : portable (H98 + FFI)+-- Maintainer : duncan@community.haskell.org -- -- Compression and decompression of data streams in the zlib format. --
Codec/Compression/Zlib/Internal.hs view
@@ -1,29 +1,48 @@-{-# LANGUAGE CPP #-}+{-# LANGUAGE CPP, RankNTypes, DeriveDataTypeable, BangPatterns #-}+{-# LANGUAGE Trustworthy #-} ----------------------------------------------------------------------------- -- |--- Copyright : (c) 2006-2008 Duncan Coutts+-- Copyright : (c) 2006-2014 Duncan Coutts -- License : BSD-style ----- Maintainer : duncan@haskell.org--- Stability : provisional--- Portability : portable (H98 + FFI)+-- Maintainer : duncan@community.haskell.org ----- Pure stream based interface to lower level zlib wrapper+-- Pure and IO stream based interfaces to lower level zlib wrapper -- ----------------------------------------------------------------------------- module Codec.Compression.Zlib.Internal ( - -- * Compression+ -- * Pure interface compress,+ decompress,++ -- * Monadic incremental interface+ -- $incremental-compression++ -- ** Using incremental compression+ -- $using-incremental-compression++ CompressStream(..),+ compressST,+ compressIO,+ foldCompressStream,+ foldCompressStreamWithInput,++ -- ** Using incremental decompression+ -- $using-incremental-decompression++ DecompressStream(..),+ DecompressError(..),+ decompressST,+ decompressIO,+ foldDecompressStream,+ foldDecompressStreamWithInput,++ -- * The compression parameter types CompressParams(..), defaultCompressParams,-- -- * Decompression- decompress, DecompressParams(..), defaultDecompressParams,-- -- * The compression parameter types Stream.Format(..), Stream.gzipFormat, Stream.zlibFormat,@@ -50,19 +69,17 @@ Stream.filteredStrategy, Stream.huffmanOnlyStrategy, - -- * Low-level API to get explicit error reports- decompressWithErrors,- DecompressStream(..),- DecompressError(..),- foldDecompressStream,- fromDecompressStream, ) where import Prelude hiding (length) import Control.Monad (when)-import Control.Exception (assert)+import Control.Exception (Exception, throw, assert)+import Control.Monad.ST.Lazy hiding (stToIO)+import Control.Monad.ST.Strict (stToIO)+import Data.Typeable (Typeable) import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy.Internal as L+import qualified Data.ByteString as S import qualified Data.ByteString.Internal as S import qualified Codec.Compression.Zlib.Stream as Stream@@ -144,20 +161,23 @@ defaultCompressBufferSize = 16 * 1024 - L.chunkOverhead defaultDecompressBufferSize = 32 * 1024 - L.chunkOverhead --- | A sequence of chunks of data produced from decompression.------ The difference from a simple list is that it contains a representation of--- errors as data rather than as exceptions. This allows you to handle error--- conditions explicitly.+-- | The unfolding of the decompression process, where you provide a sequence+-- of compressed data chunks as input and receive a sequence of uncompressed+-- data chunks as output. The process is incremental, in that the demand for+-- input and provision of output are interleaved. ---data DecompressStream = StreamEnd- | StreamChunk S.ByteString DecompressStream-- -- | An error code and a human readable error message.- | StreamError DecompressError String+data DecompressStream m+ = DecompressInputRequired (S.ByteString -> m (DecompressStream m))+ | DecompressOutputAvailable S.ByteString (m (DecompressStream m))+ -- | Includes any trailing unconsumed /input/ data.+ | DecompressStreamEnd S.ByteString+ -- | An error code+ | DecompressStreamError DecompressError -- | The possible error cases when decompressing a stream. --+-- This can be 'show'n to give a human readable error message.+-- data DecompressError = -- | The compressed data stream ended prematurely. This may happen if the -- input data stream was truncated.@@ -170,66 +190,254 @@ -- dictionary, and it's not provided. | DictionaryRequired + -- | If the stream requires a dictionary and you provide one with the+ -- wrong 'DictionaryHash' then you will get this error.+ | DictionaryMismatch+ -- | If the compressed data stream is corrupted in any way then you will -- get this error, for example if the input data just isn't a compressed -- zlib data stream. In particular if the data checksum turns out to be -- wrong then you will get all the decompressed data but this error at the -- end, instead of the normal sucessful 'StreamEnd'.- | DataError+ | DataFormatError String+ deriving (Eq, Typeable) --- | Fold an 'DecompressionStream'. Just like 'foldr' but with an extra error--- case. For example to convert to a list and translate the errors into--- exceptions:+instance Show DecompressError where+ show TruncatedInput = modprefix "premature end of compressed data stream"+ show DictionaryRequired = modprefix "compressed data stream requires custom dictionary"+ show DictionaryMismatch = modprefix "given dictionary does not match the expected one"+ show (DataFormatError detail) = modprefix ("compressed data stream format error (" ++ detail ++ ")")++modprefix :: ShowS+modprefix = ("Codec.Compression.Zlib: " ++)++instance Exception DecompressError++-- | A fold over the 'DecompressStream' in the given monad. ----- > foldDecompressStream (:) [] (\code msg -> error msg)+-- One way to look at this is that it runs the stream, using callback functions+-- for the four stream events. ---foldDecompressStream :: (S.ByteString -> a -> a) -> a- -> (DecompressError -> String -> a)- -> DecompressStream -> a-foldDecompressStream chunk end err = fold+foldDecompressStream :: Monad m+ => ((S.ByteString -> m a) -> m a)+ -> (S.ByteString -> m a -> m a)+ -> (S.ByteString -> m a)+ -> (DecompressError -> m a)+ -> DecompressStream m -> m a+foldDecompressStream input output end err = fold where- fold StreamEnd = end- fold (StreamChunk bs stream) = chunk bs (fold stream)- fold (StreamError code msg) = err code msg+ fold (DecompressInputRequired next) =+ input (\x -> next x >>= fold) --- | Convert a 'DecompressStream' to a lazy 'ByteString'. If any decompression--- errors are encountered then they are thrown as exceptions.+ fold (DecompressOutputAvailable outchunk next) =+ output outchunk (next >>= fold)++ fold (DecompressStreamEnd inchunk) = end inchunk+ fold (DecompressStreamError derr) = err derr++-- | A variant on 'foldCompressStream' that is pure rather than operating in a+-- monad and where the input is provided by a lazy 'L.ByteString'. So we only+-- have to deal with the output, end and error parts, making it like a foldr on+-- a list of output chunks. ----- This is a special case of 'foldDecompressStream'.+-- For example: ---fromDecompressStream :: DecompressStream -> L.ByteString-fromDecompressStream =- foldDecompressStream L.Chunk L.Empty- (\_code msg -> error ("Codec.Compression.Zlib: " ++ msg))+-- > toChunks = foldDecompressStreamWithInput (:) [] throw+--+foldDecompressStreamWithInput :: (S.ByteString -> a -> a)+ -> (L.ByteString -> a)+ -> (DecompressError -> a)+ -> (forall s. DecompressStream (ST s))+ -> L.ByteString+ -> a+foldDecompressStreamWithInput chunk end err = \s lbs ->+ runST (fold s (L.toChunks lbs))+ where+ fold (DecompressInputRequired next) [] =+ next S.empty >>= \strm -> fold strm [] ---TODO: throw DecompressError as an Exception class type and document that it--- does this.+ fold (DecompressInputRequired next) (inchunk:inchunks) =+ next inchunk >>= \s -> fold s inchunks --- | Compress a data stream.+ fold (DecompressOutputAvailable outchunk next) inchunks = do+ r <- next >>= \s -> fold s inchunks+ return $ chunk outchunk r++ fold (DecompressStreamEnd inchunk) inchunks =+ return $ end (L.fromChunks (inchunk:inchunks))++ fold (DecompressStreamError derr) _ =+ return $ err derr+++-- $incremental-compression+-- The pure 'compress' and 'decompress' functions are streaming in the sense+-- that they can produce output without demanding all input, however they need+-- the input data stream as a lazy 'L.ByteString'. Having the input data+-- stream as a lazy 'L.ByteString' often requires using lazy I\/O which is not+-- appropriate in all cicumstances. --+-- For these cases an incremental interface is more appropriate. This interface+-- allows both incremental input and output. Chunks of input data to be+-- supplied one by one (e.g. as they are obtained from an input source like a+-- file or network source). Output is also produced chunk by chunk.+--+-- The incremental input and output is managed via the 'CompressStream' and+-- 'DecompressStream' types. They represents the unfolding of the process of+-- compressing and decompressing. They operates in either the 'ST' or 'IO'+-- monads. They can be lifted into other incremental abstractions like pipes or+-- conduits, or they can be used directly in the following style.++-- $using-incremental-compression+--+-- In a loop:+--+-- * Inspect the status of the stream+--+-- * When it is 'CompressInputRequired' then you should call the action,+-- passing a chunk of input (or 'BS.empty' when no more input is available)+-- to get the next state of the stream and continue the loop.+--+-- * When it is 'CompressOutputAvailable' then do something with the given+-- chunk of output, and call the action to get the next state of the stream+-- and continue the loop.+--+-- * When it is 'CompressStreamEnd' then terminate the loop.+--+-- Note that you cannot stop as soon as you have no more input, you need to+-- carry on until all the output has been collected, i.e. until you get to+-- 'CompressStreamEnd'.+--+-- Here is an example where we get input from one file handle and send the+-- compressed output to another file handle.+--+-- > go :: Handle -> Handle -> CompressStream IO -> IO ()+-- > go inh outh (CompressInputRequired next) = do+-- > inchunk <- BS.hGet inh 4096+-- > go inh outh =<< next inchunk+-- > go inh outh (CompressOutputAvailable outchunk next) =+-- > BS.hPut outh outchunk+-- > go inh outh =<< next+-- > go _ _ CompressStreamEnd = return ()+--+-- The same can be achieved with 'foldCompressStream':+--+-- > foldCompressStream+-- > (\next -> do inchunk <- BS.hGet inh 4096; next inchunk)+-- > (\outchunk next -> do BS.hPut outh outchunk; next)+-- > (return ())++-- $using-incremental-decompression+--+-- The use of 'DecompressStream' is very similar to 'CompressStream' but with+-- a few differences:+--+-- * There is the extra possibility of a 'DecompressStreamError'+--+-- * There can be extra trailing data after a compressed stream, and the+-- 'DecompressStreamEnd' includes that.+--+-- Otherwise the same loop style applies, and there are fold functions.++-- | The unfolding of the compression process, where you provide a sequence+-- of uncompressed data chunks as input and receive a sequence of compressed+-- data chunks as output. The process is incremental, in that the demand for+-- input and provision of output are interleaved.+--+data CompressStream m+ = CompressInputRequired (S.ByteString -> m (CompressStream m))+ | CompressOutputAvailable S.ByteString (m (CompressStream m))+ | CompressStreamEnd++-- | A fold over the 'CompressStream' in the given monad.+--+-- One way to look at this is that it runs the stream, using callback functions+-- for the three stream events.+--+foldCompressStream :: Monad m+ => ((S.ByteString -> m a) -> m a)+ -> (S.ByteString -> m a -> m a)+ -> m a+ -> CompressStream m -> m a+foldCompressStream input output end = fold+ where+ fold (CompressInputRequired next) =+ input (\x -> next x >>= fold)++ fold (CompressOutputAvailable outchunk next) =+ output outchunk (next >>= fold)++ fold CompressStreamEnd =+ end++-- | A variant on 'foldCompressStream' that is pure rather than operating in a+-- monad and where the input is provided by a lazy 'L.ByteString'. So we only+-- have to deal with the output and end parts, making it just like a foldr on a+-- list of output chunks.+--+-- For example:+--+-- > toChunks = foldCompressStreamWithInput (:) []+--+foldCompressStreamWithInput :: (S.ByteString -> a -> a)+ -> a+ -> (forall s. CompressStream (ST s))+ -> L.ByteString+ -> a+foldCompressStreamWithInput chunk end = \s lbs ->+ runST (fold s (L.toChunks lbs))+ where+ fold (CompressInputRequired next) [] =+ next S.empty >>= \strm -> fold strm []++ fold (CompressInputRequired next) (inchunk:inchunks) =+ next inchunk >>= \s -> fold s inchunks++ fold (CompressOutputAvailable outchunk next) inchunks = do+ r <- next >>= \s -> fold s inchunks+ return $ chunk outchunk r++ fold CompressStreamEnd _inchunks =+ return end+++-- | Compress a data stream provided as a lazy 'L.ByteString'.+-- -- There are no expected error conditions. All input data streams are valid. It -- is possible for unexpected errors to occur, such as running out of memory, -- or finding the wrong version of the zlib C library, these are thrown as -- exceptions. ---compress- :: Stream.Format- -> CompressParams- -> L.ByteString- -> L.ByteString-compress format- (CompressParams compLevel method bits memLevel strategy initChunkSize mdict)- input =- L.fromChunks $ Stream.run $ do- Stream.deflateInit format compLevel method bits memLevel strategy- setDictionary mdict- case L.toChunks input of- [] -> fillBuffers 20 [] --gzip header is 20 bytes, others even smaller- S.PS inFPtr offset length : chunks -> do- Stream.pushInputBuffer inFPtr offset length- r <- fillBuffers initChunkSize chunks- return r+compress :: Stream.Format -> CompressParams -> L.ByteString -> L.ByteString +-- | Incremental compression in the 'ST' monad. Using 'ST' makes it possible+-- to write pure /lazy/ functions while making use of incremental compression.+--+compressST :: Stream.Format -> CompressParams -> CompressStream (ST s)++-- | Incremental compression in the 'IO' monad.+--+compressIO :: Stream.Format -> CompressParams -> CompressStream IO++compress format params = compressStreamToLBS (compressStream format params)+compressST format params = compressStreamToST (compressStream format params)+compressIO format params = compressStreamToIO (compressStream format params)++compressStream :: Stream.Format -> CompressParams -> CompressStream Stream+compressStream format (CompressParams compLevel method bits memLevel+ strategy initChunkSize mdict) =++ CompressInputRequired $ \chunk -> do+ Stream.deflateInit format compLevel method bits memLevel strategy+ setDictionary mdict+ case chunk of+ _ | S.null chunk ->+ fillBuffers 20 --gzip header is 20 bytes, others even smaller++ S.PS inFPtr offset length -> do+ Stream.pushInputBuffer inFPtr offset length+ fillBuffers initChunkSize+ where -- we flick between two states: -- * where one or other buffer is empty@@ -237,10 +445,8 @@ -- * where both buffers are non-empty -- - in which case we compress until a buffer is empty - fillBuffers :: Int- -> [S.ByteString]- -> Stream [S.ByteString]- fillBuffers outChunkSize inChunks = do+ fillBuffers :: Int -> Stream (CompressStream Stream)+ fillBuffers outChunkSize = do #ifdef DEBUG Stream.consistencyCheck #endif@@ -260,27 +466,26 @@ Stream.pushOutputBuffer outFPtr 0 outChunkSize if inputBufferEmpty- then case inChunks of- [] -> drainBuffers []- S.PS inFPtr offset length : inChunks' -> do+ then return $ CompressInputRequired $ \chunk ->+ case chunk of+ _ | S.null chunk -> drainBuffers True+ S.PS inFPtr offset length -> do Stream.pushInputBuffer inFPtr offset length- drainBuffers inChunks'- else drainBuffers inChunks+ drainBuffers False+ else drainBuffers False - drainBuffers ::- [S.ByteString]- -> Stream [S.ByteString]- drainBuffers inChunks = do+ drainBuffers :: Bool -> Stream (CompressStream Stream)+ drainBuffers lastChunk = do inputBufferEmpty' <- Stream.inputBufferEmpty outputBufferFull' <- Stream.outputBufferFull assert(not outputBufferFull'- && (null inChunks || not inputBufferEmpty')) $ return ()+ && (lastChunk || not inputBufferEmpty')) $ return () -- this invariant guarantees we can always make forward progress -- and that therefore a BufferError is impossible - let flush = if null inChunks then Stream.Finish else Stream.NoFlush+ let flush = if lastChunk then Stream.Finish else Stream.NoFlush status <- Stream.deflate flush case status of@@ -288,10 +493,10 @@ outputBufferFull <- Stream.outputBufferFull if outputBufferFull then do (outFPtr, offset, length) <- Stream.popOutputBuffer- outChunks <- Stream.unsafeInterleave- (fillBuffers defaultCompressBufferSize inChunks)- return (S.PS outFPtr offset length : outChunks)- else do fillBuffers defaultCompressBufferSize inChunks+ let chunk = S.PS outFPtr offset length+ return $ CompressOutputAvailable chunk $ do+ fillBuffers defaultCompressBufferSize+ else do fillBuffers defaultCompressBufferSize Stream.StreamEnd -> do inputBufferEmpty <- Stream.inputBufferEmpty@@ -299,10 +504,11 @@ outputBufferBytesAvailable <- Stream.outputBufferBytesAvailable if outputBufferBytesAvailable > 0 then do (outFPtr, offset, length) <- Stream.popOutputBuffer+ let chunk = S.PS outFPtr offset length Stream.finalise- return [S.PS outFPtr offset length]+ return $ CompressOutputAvailable chunk (return CompressStreamEnd) else do Stream.finalise- return []+ return CompressStreamEnd Stream.Error code msg -> case code of Stream.BufferError -> fail "BufferError should be impossible!"@@ -322,42 +528,41 @@ setDictionary _ = return () --- | Decompress a data stream.+-- | Decompress a data stream provided as a lazy 'L.ByteString'. ----- It will throw an exception if any error is encountered in the input data. If--- you need more control over error handling then use 'decompressWithErrors'.+-- It will throw an exception if any error is encountered in the input data.+-- If you need more control over error handling then use one the incremental+-- versions, 'decompressST' or 'decompressIO'. ---decompress- :: Stream.Format- -> DecompressParams- -> L.ByteString- -> L.ByteString-decompress format params = fromDecompressStream- . decompressWithErrors format params+decompress :: Stream.Format -> DecompressParams -> L.ByteString -> L.ByteString --- | Like 'decompress' but returns a 'DecompressStream' data structure that--- contains an explicit representation of the error conditions that one may--- encounter when decompressing.+-- | Incremental decompression in the 'ST' monad. Using 'ST' makes it possible+-- to write pure /lazy/ functions while making use of incremental decompression. ----- Note that in addition to errors in the input data, it is possible for other--- unexpected errors to occur, such as out of memory, or finding the wrong--- version of the zlib C library, these are still thrown as exceptions (because--- representing them as data would make this function impure).+decompressST :: Stream.Format -> DecompressParams -> DecompressStream (ST s)++-- | Incremental decompression in the 'IO' monad. ---decompressWithErrors- :: Stream.Format- -> DecompressParams- -> L.ByteString- -> DecompressStream-decompressWithErrors format (DecompressParams bits initChunkSize mdict) input =- Stream.run $ do- Stream.inflateInit format bits- case L.toChunks input of- [] -> fillBuffers 4 [] --always an error anyway- S.PS inFPtr offset length : chunks -> do- Stream.pushInputBuffer inFPtr offset length- fillBuffers initChunkSize chunks+decompressIO :: Stream.Format -> DecompressParams -> DecompressStream IO +decompress format params = decompressStreamToLBS (decompressStream format params)+decompressST format params = decompressStreamToST (decompressStream format params)+decompressIO format params = decompressStreamToIO (decompressStream format params)+++decompressStream :: Stream.Format -> DecompressParams -> DecompressStream Stream+decompressStream format (DecompressParams bits initChunkSize mdict) =++ DecompressInputRequired $ \chunk -> do+ Stream.inflateInit format bits+ case chunk of+ _ | S.null chunk ->+ fillBuffers 4 --always an error anyway++ S.PS inFPtr offset length -> do+ Stream.pushInputBuffer inFPtr offset length+ fillBuffers initChunkSize+ where -- we flick between two states: -- * where one or other buffer is empty@@ -366,9 +571,8 @@ -- - in which case we compress until a buffer is empty fillBuffers :: Int- -> [S.ByteString]- -> Stream DecompressStream- fillBuffers outChunkSize inChunks = do+ -> Stream (DecompressStream Stream)+ fillBuffers outChunkSize = do #ifdef DEBUG Stream.consistencyCheck #endif@@ -388,23 +592,22 @@ Stream.pushOutputBuffer outFPtr 0 outChunkSize if inputBufferEmpty- then case inChunks of- [] -> drainBuffers []- S.PS inFPtr offset length : inChunks' -> do+ then return $ DecompressInputRequired $ \chunk ->+ case chunk of+ _ | S.null chunk -> drainBuffers True+ S.PS inFPtr offset length -> do Stream.pushInputBuffer inFPtr offset length- drainBuffers inChunks'- else drainBuffers inChunks+ drainBuffers False+ else drainBuffers False - drainBuffers ::- [S.ByteString]- -> Stream DecompressStream- drainBuffers inChunks = do+ drainBuffers :: Bool -> Stream (DecompressStream Stream)+ drainBuffers lastChunk = do inputBufferEmpty' <- Stream.inputBufferEmpty outputBufferFull' <- Stream.outputBufferFull assert(not outputBufferFull'- && (null inChunks || not inputBufferEmpty')) $ return ()+ && (lastChunk || not inputBufferEmpty')) $ return () -- this invariant guarantees we can always make forward progress or at -- least if a BufferError does occur that it must be due to a premature EOF @@ -415,55 +618,188 @@ outputBufferFull <- Stream.outputBufferFull if outputBufferFull then do (outFPtr, offset, length) <- Stream.popOutputBuffer- outChunks <- Stream.unsafeInterleave- (fillBuffers defaultDecompressBufferSize inChunks)- return $ StreamChunk (S.PS outFPtr offset length) outChunks- else do fillBuffers defaultDecompressBufferSize inChunks+ let chunk = S.PS outFPtr offset length+ return $ DecompressOutputAvailable chunk $ do+ fillBuffers defaultDecompressBufferSize+ else do fillBuffers defaultDecompressBufferSize - Stream.StreamEnd -> inChunks `seq` finish StreamEnd- -- The decompressor tells us we're done, but that doesn't mean we have- -- consumed all the input (there could be trailing data). But more- -- subtle than that, the decompressor will actually never demand the- -- tail of the input (in the usual case where it's empty) because- -- the zlib and gzip formats know their own length. So we force the- -- tail of the input here because this can be important for closing- -- file handles etc.+ Stream.StreamEnd -> do+ -- The decompressor tells us we're done.+ -- Note that there may be input bytes still available if the stream is+ -- embeded in some other data stream, so we return any trailing data.+ inputBufferEmpty <- Stream.inputBufferEmpty+ if inputBufferEmpty+ then do finish (DecompressStreamEnd S.empty)+ else do (inFPtr, offset, length) <- Stream.remainingInputBuffer+ let inchunk = S.PS inFPtr offset length+ finish (DecompressStreamEnd inchunk) Stream.Error code msg -> case code of- Stream.BufferError -> finish (StreamError TruncatedInput msg')- where msg' = "premature end of compressed stream"+ Stream.BufferError -> finish (DecompressStreamError TruncatedInput) Stream.NeedDict adler -> do err <- setDictionary adler mdict case err of Just streamErr -> finish streamErr- Nothing -> drainBuffers inChunks- Stream.DataError -> finish (StreamError DataError msg)+ Nothing -> drainBuffers lastChunk+ Stream.DataError -> finish (DecompressStreamError (DataFormatError msg)) _ -> fail msg -- Note even if we end with an error we still try to flush the last chunk if -- there is one. The user just has to decide what they want to trust. finish end = do- -- Note that there may be input bytes still available if the stream- -- is embeded in some other data stream. Here we just silently discard- -- any trailing data. outputBufferBytesAvailable <- Stream.outputBufferBytesAvailable if outputBufferBytesAvailable > 0 then do (outFPtr, offset, length) <- Stream.popOutputBuffer Stream.finalise- return (StreamChunk (S.PS outFPtr offset length) end)+ return (DecompressOutputAvailable (S.PS outFPtr offset length) (return end)) else do Stream.finalise return end setDictionary :: Stream.DictionaryHash -> Maybe S.ByteString- -> Stream (Maybe DecompressStream)+ -> Stream (Maybe (DecompressStream Stream)) setDictionary _adler Nothing =- return $ Just (StreamError DictionaryRequired "custom dictionary needed")+ return $ Just (DecompressStreamError DictionaryRequired) setDictionary _adler (Just dict) = do status <- Stream.inflateSetDictionary dict case status of Stream.Ok -> return Nothing- Stream.Error Stream.StreamError _ ->- return $ Just (StreamError DictionaryRequired "provided dictionary not valid") Stream.Error Stream.DataError _ ->- return $ Just (StreamError DictionaryRequired "given dictionary does not match the expected one")+ return $ Just (DecompressStreamError DictionaryMismatch) _ -> fail "error when setting inflate dictionary"+++compressStreamToLBS :: CompressStream Stream -> L.ByteString -> L.ByteString+compressStreamToLBS = \strm inchunks ->+ runST (do zstate <- strictToLazyST $ Stream.mkState+ go strm zstate inchunks)+ where+ go :: CompressStream Stream -> Stream.State s+ -> L.ByteString -> ST s L.ByteString+ go (CompressInputRequired next) zstate L.Empty = do+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next S.empty) zstate+ go strm' zstate' L.Empty++ go (CompressInputRequired next) zstate (L.Chunk inchunk inchunks') = do+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next inchunk) zstate+ go strm' zstate' inchunks'++ go (CompressOutputAvailable outchunk next) zstate inchunks = do+ (strm', zstate') <- strictToLazyST $ Stream.runStream next zstate+ outchunks <- go strm' zstate' inchunks+ return (L.Chunk outchunk outchunks)++ go CompressStreamEnd _ _ = return L.Empty++compressStreamToIO :: CompressStream Stream -> CompressStream IO+compressStreamToIO =+ \(CompressInputRequired next) ->+ CompressInputRequired $ \chunk -> do+ zstate <- stToIO Stream.mkState+ (strm', zstate') <- stToIO $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')+ where+ go :: CompressStream Stream -> Stream.State RealWorld -> CompressStream IO+ go (CompressInputRequired next) zstate =+ CompressInputRequired $ \chunk -> do+ (strm', zstate') <- stToIO $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')++ go (CompressOutputAvailable chunk next) zstate =+ CompressOutputAvailable chunk $ do+ (strm', zstate') <- stToIO $ Stream.runStream next zstate+ return (go strm' zstate')++ go CompressStreamEnd _ = CompressStreamEnd++compressStreamToST :: CompressStream Stream -> CompressStream (ST s)+compressStreamToST =+ \(CompressInputRequired next) ->+ CompressInputRequired $ \chunk -> do+ zstate <- strictToLazyST $ Stream.mkState+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')+ where+ go :: CompressStream Stream -> Stream.State s -> CompressStream (ST s)+ go (CompressInputRequired next) zstate =+ CompressInputRequired $ \chunk -> do+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')++ go (CompressOutputAvailable chunk next) zstate =+ CompressOutputAvailable chunk $ do+ (strm', zstate') <- strictToLazyST $ Stream.runStream next zstate+ return (go strm' zstate')++ go CompressStreamEnd _ = CompressStreamEnd+++decompressStreamToLBS :: DecompressStream Stream -> L.ByteString -> L.ByteString+decompressStreamToLBS = \strm inchunks ->+ runST (do zstate <- strictToLazyST Stream.mkState+ go strm zstate inchunks)+ where+ go :: DecompressStream Stream -> Stream.State s+ -> L.ByteString -> ST s L.ByteString+ go (DecompressInputRequired next) zstate L.Empty = do+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next S.empty) zstate+ go strm' zstate' L.Empty++ go (DecompressInputRequired next) zstate (L.Chunk inchunk inchunks') = do+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next inchunk) zstate+ go strm' zstate' inchunks'++ go (DecompressOutputAvailable outchunk next) zstate inchunks = do+ (strm', zstate') <- strictToLazyST $ Stream.runStream next zstate+ outchunks <- go strm' zstate' inchunks+ return (L.Chunk outchunk outchunks)++ -- the decompressor will actually never demand the tail of the input (in+ -- the usual case where it's empty) because the zlib and gzip formats know+ -- their own length. So we force the tail of the input here because this+ -- can be important for closing file handles etc.+ go (DecompressStreamEnd _) _ !_inchunks = return L.Empty+ go (DecompressStreamError err) _ _ = throw err++decompressStreamToIO :: DecompressStream Stream -> DecompressStream IO+decompressStreamToIO =+ \(DecompressInputRequired next) ->+ DecompressInputRequired $ \chunk -> do+ zstate <- stToIO Stream.mkState+ (strm', zstate') <- stToIO $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')+ where+ go :: DecompressStream Stream -> Stream.State RealWorld -> DecompressStream IO+ go (DecompressInputRequired next) zstate =+ DecompressInputRequired $ \chunk -> do+ (strm', zstate') <- stToIO $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')++ go (DecompressOutputAvailable chunk next) zstate =+ DecompressOutputAvailable chunk $ do+ (strm', zstate') <- stToIO $ Stream.runStream next zstate+ return (go strm' zstate')++ go (DecompressStreamEnd chunk) _ = DecompressStreamEnd chunk+ go (DecompressStreamError err) _ = DecompressStreamError err++decompressStreamToST :: DecompressStream Stream -> DecompressStream (ST s)+decompressStreamToST =+ \(DecompressInputRequired next) ->+ DecompressInputRequired $ \chunk -> do+ zstate <- strictToLazyST Stream.mkState+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')+ where+ go :: DecompressStream Stream -> Stream.State s -> DecompressStream (ST s)+ go (DecompressInputRequired next) zstate =+ DecompressInputRequired $ \chunk -> do+ (strm', zstate') <- strictToLazyST $ Stream.runStream (next chunk) zstate+ return (go strm' zstate')++ go (DecompressOutputAvailable chunk next) zstate =+ DecompressOutputAvailable chunk $ do+ (strm', zstate') <- strictToLazyST $ Stream.runStream next zstate+ return (go strm' zstate')++ go (DecompressStreamEnd chunk) _ = DecompressStreamEnd chunk+ go (DecompressStreamError err) _ = DecompressStreamError err
Codec/Compression/Zlib/Raw.hs view
@@ -1,11 +1,9 @@ ----------------------------------------------------------------------------- -- |--- Copyright : (c) 2006-2008 Duncan Coutts+-- Copyright : (c) 2006-2014 Duncan Coutts -- License : BSD-style ----- Maintainer : duncan@haskell.org--- Stability : provisional--- Portability : portable (H98 + FFI)+-- Maintainer : duncan@community.haskell.org -- -- Compression and decompression of data streams in the raw deflate format. --
Codec/Compression/Zlib/Stream.hsc view
@@ -1,12 +1,10 @@-{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE ForeignFunctionInterface, DeriveDataTypeable, DeriveGeneric #-} ----------------------------------------------------------------------------- -- |--- Copyright : (c) 2006-2008 Duncan Coutts+-- Copyright : (c) 2006-2014 Duncan Coutts -- License : BSD-style ----- Maintainer : duncan@haskell.org--- Stability : provisional--- Portability : portable (H98 + FFI)+-- Maintainer : duncan@community.haskell.org -- -- Zlib wrapper layer --@@ -15,8 +13,9 @@ -- * The Zlib state monad Stream,- run,- unsafeInterleave,+ State,+ mkState,+ runStream, unsafeLiftIO, finalise, @@ -63,6 +62,7 @@ -- ** Input buffer pushInputBuffer, inputBufferEmpty,+ remainingInputBuffer, -- ** Output buffer pushOutputBuffer,@@ -90,9 +90,9 @@ ) where import Foreign- ( Word8, Ptr, nullPtr, plusPtr, peekByteOff, pokeByteOff, mallocBytes- , ForeignPtr, FinalizerPtr, newForeignPtr_, addForeignPtrFinalizer- , withForeignPtr, touchForeignPtr )+ ( Word8, Ptr, nullPtr, plusPtr, peekByteOff, pokeByteOff+ , ForeignPtr, FinalizerPtr, mallocForeignPtrBytes, addForeignPtrFinalizer+ , withForeignPtr, touchForeignPtr, minusPtr ) #if __GLASGOW_HASKELL__ >= 702 import Foreign.ForeignPtr.Unsafe ( unsafeForeignPtrToPtr ) import System.IO.Unsafe ( unsafePerformIO )@@ -107,10 +107,17 @@ import Data.ByteString.Internal (nullForeignPtr) import qualified Data.ByteString.Unsafe as B import Data.ByteString (ByteString)-import System.IO.Unsafe (unsafeInterleaveIO) import Control.Applicative (Applicative(..)) import Control.Monad (ap,liftM)+#if __GLASGOW_HASKELL__ >= 702+import Control.Monad.ST.Strict hiding (unsafeIOToST)+import Control.Monad.ST.Unsafe+#else+import Control.Monad.ST.Strict+#endif import Control.Exception (assert)+import Data.Typeable (Typeable)+import GHC.Generics (Generic) #ifdef DEBUG import System.IO (hPutStrLn, stderr) #endif@@ -146,6 +153,19 @@ inputBufferEmpty = getInAvail >>= return . (==0) +remainingInputBuffer :: Stream (ForeignPtr Word8, Int, Int)+remainingInputBuffer = do++ inBuf <- getInBuf+ inNext <- getInNext+ inAvail <- getInAvail++ -- there really should be something to pop, otherwise it's silly+ assert (inAvail > 0) $ return ()++ return (inBuf, inNext `minusPtr` unsafeForeignPtrToPtr inBuf, inAvail)++ pushOutputBuffer :: ForeignPtr Word8 -> Int -> Int -> Stream () pushOutputBuffer outBuf' offset length = do @@ -341,38 +361,40 @@ failZ :: String -> Stream a failZ msg = Z (\_ _ _ _ _ -> fail ("Codec.Compression.Zlib: " ++ msg)) -{-# NOINLINE run #-}-run :: Stream a -> a-run (Z m) = unsafePerformIO $ do- ptr <- mallocBytes (#{const sizeof(z_stream)})- #{poke z_stream, msg} ptr nullPtr- #{poke z_stream, zalloc} ptr nullPtr- #{poke z_stream, zfree} ptr nullPtr- #{poke z_stream, opaque} ptr nullPtr- #{poke z_stream, next_in} ptr nullPtr- #{poke z_stream, next_out} ptr nullPtr- #{poke z_stream, avail_in} ptr (0 :: CUInt)- #{poke z_stream, avail_out} ptr (0 :: CUInt)- stream <- newForeignPtr_ ptr- (_,_,_,_,a) <- m stream nullForeignPtr nullForeignPtr 0 0- return a+data State s = State !(ForeignPtr StreamState)+ !(ForeignPtr Word8)+ !(ForeignPtr Word8)+ {-# UNPACK #-} !Int+ {-# UNPACK #-} !Int --- This is marked as unsafe because run uses unsafePerformIO so anything--- lifted here will end up being unsafePerformIO'd.+mkState :: ST s (State s)+mkState = unsafeIOToST $ do+ stream <- mallocForeignPtrBytes (#{const sizeof(z_stream)})+ withForeignPtr stream $ \ptr -> do+ #{poke z_stream, msg} ptr nullPtr+ #{poke z_stream, zalloc} ptr nullPtr+ #{poke z_stream, zfree} ptr nullPtr+ #{poke z_stream, opaque} ptr nullPtr+ #{poke z_stream, next_in} ptr nullPtr+ #{poke z_stream, next_out} ptr nullPtr+ #{poke z_stream, avail_in} ptr (0 :: CUInt)+ #{poke z_stream, avail_out} ptr (0 :: CUInt)+ return (State stream nullForeignPtr nullForeignPtr 0 0)++runStream :: Stream a -> State s -> ST s (a, State s)+runStream (Z m) (State stream inBuf outBuf outOffset outLength) =+ unsafeIOToST $+ m stream inBuf outBuf outOffset outLength >>=+ \(inBuf', outBuf', outOffset', outLength', a) ->+ return (a, State stream inBuf' outBuf' outOffset' outLength')++-- This is marked as unsafe because runStream uses unsafeIOToST so anything+-- lifted here can end up being unsafePerformIO'd. unsafeLiftIO :: IO a -> Stream a unsafeLiftIO m = Z $ \_stream inBuf outBuf outOffset outLength -> do a <- m return (inBuf, outBuf, outOffset, outLength, a) --- It's unsafe because we discard the values here, so if you mutate anything--- between running this and forcing the result then you'll get an inconsistent--- stream state.-unsafeInterleave :: Stream a -> Stream a-unsafeInterleave (Z m) = Z $ \stream inBuf outBuf outOffset outLength -> do- res <- unsafeInterleaveIO (m stream inBuf outBuf outOffset outLength)- let select (_,_,_,_,a) = a- return (inBuf, outBuf, outOffset, outLength, select res)- getStreamState :: Stream (ForeignPtr StreamState) getStreamState = Z $ \stream inBuf outBuf outOffset outLength -> do return (inBuf, outBuf, outOffset, outLength, stream)@@ -523,7 +545,7 @@ -- variations. -- data Format = GZip | Zlib | Raw | GZipOrZlib- deriving Eq+ deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Generic) {-# DEPRECATED GZip "Use gzipFormat. Format constructors will be hidden in version 0.7" #-} {-# DEPRECATED Zlib "Use zlibFormat. Format constructors will be hidden in version 0.7" #-}@@ -568,6 +590,7 @@ -- | The compression method -- data Method = Deflated+ deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Generic) {-# DEPRECATED Deflated "Use deflateMethod. Method constructors will be hidden in version 0.7" #-} @@ -591,6 +614,7 @@ | BestSpeed | BestCompression | CompressionLevel Int+ deriving (Eq, Show, Typeable, Generic) {-# DEPRECATED DefaultCompression "Use defaultCompression. CompressionLevel constructors will be hidden in version 0.7" #-} {-# DEPRECATED NoCompression "Use noCompression. CompressionLevel constructors will be hidden in version 0.7" #-}@@ -646,10 +670,11 @@ -- data WindowBits = WindowBits Int | DefaultWindowBits -- This constructor must be last to make- -- the Ord instance work. The Ord instance- -- is defined with and used by the tests.- -- It makse sense because the default value- -- is is also the max value at 15.+ -- the Ord instance work. The Ord instance+ -- is defined with and used by the tests.+ -- It makse sense because the default value+ -- is is also the max value at 15.+ deriving (Eq, Show, Typeable, Generic) {-# DEPRECATED DefaultWindowBits "Use defaultWindowBits. WindowBits constructors will be hidden in version 0.7" #-} --FIXME: cannot deprecate constructor named the same as the type@@ -705,6 +730,7 @@ | MinMemoryLevel | MaxMemoryLevel | MemoryLevel Int+ deriving (Eq, Show, Typeable, Generic) {-# DEPRECATED DefaultMemoryLevel "Use defaultMemoryLevel. MemoryLevel constructors will be hidden in version 0.7" #-} {-# DEPRECATED MinMemoryLevel "Use minMemoryLevel. MemoryLevel constructors will be hidden in version 0.7" #-}@@ -754,6 +780,7 @@ DefaultStrategy | Filtered | HuffmanOnly+ deriving (Eq, Ord, Enum, Bounded, Show, Typeable, Generic) {- -- -- only available in zlib 1.2 and later, uncomment if you need it.@@ -820,10 +847,8 @@ setInNext :: Ptr Word8 -> Stream () setInNext val = withStreamPtr (\ptr -> #{poke z_stream, next_in} ptr val) -#ifdef DEBUG getInNext :: Stream (Ptr Word8) getInNext = withStreamPtr (#{peek z_stream, next_in})-#endif setOutFree :: Int -> Stream () setOutFree val = withStreamPtr $ \ptr ->@@ -902,7 +927,7 @@ || format == GZipOrZlib -> fail $ "version 1.1.x of the zlib C library does not support the" ++ " 'gzip' format via the in-memory api, only the 'raw' and "- ++ " 'zlib' formats."+ ++ " 'zlib' formats." _ -> return () ----------------------@@ -942,8 +967,8 @@ foreign import ccall unsafe "zlib.h deflateInit2_" c_deflateInit2_ :: StreamState -> CInt -> CInt -> CInt -> CInt -> CInt- -> Ptr CChar -> CInt- -> IO CInt+ -> Ptr CChar -> CInt+ -> IO CInt c_deflateInit2 :: StreamState -> CInt -> CInt -> CInt -> CInt -> CInt -> IO CInt
cbits/adler32.c view
@@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream- * Copyright (C) 1995-2007 Mark Adler+ * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,9 +9,9 @@ #define local static -local uLong adler32_combine_(uLong adler1, uLong adler2, z_off64_t len2);+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); -#define BASE 65521UL /* largest prime smaller than 65536 */+#define BASE 65521 /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ @@ -21,39 +21,44 @@ #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); -/* use NO_DIVIDE if your processor does not do division in hardware */+/* use NO_DIVIDE if your processor does not do division in hardware --+ try it both ways to see which is faster */ #ifdef NO_DIVIDE-# define MOD(a) \+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15+ (thank you to John Reiser for pointing this out) */+# define CHOP(a) \ do { \- if (a >= (BASE << 16)) a -= (BASE << 16); \- if (a >= (BASE << 15)) a -= (BASE << 15); \- if (a >= (BASE << 14)) a -= (BASE << 14); \- if (a >= (BASE << 13)) a -= (BASE << 13); \- if (a >= (BASE << 12)) a -= (BASE << 12); \- if (a >= (BASE << 11)) a -= (BASE << 11); \- if (a >= (BASE << 10)) a -= (BASE << 10); \- if (a >= (BASE << 9)) a -= (BASE << 9); \- if (a >= (BASE << 8)) a -= (BASE << 8); \- if (a >= (BASE << 7)) a -= (BASE << 7); \- if (a >= (BASE << 6)) a -= (BASE << 6); \- if (a >= (BASE << 5)) a -= (BASE << 5); \- if (a >= (BASE << 4)) a -= (BASE << 4); \- if (a >= (BASE << 3)) a -= (BASE << 3); \- if (a >= (BASE << 2)) a -= (BASE << 2); \- if (a >= (BASE << 1)) a -= (BASE << 1); \+ unsigned long tmp = a >> 16; \+ a &= 0xffffUL; \+ a += (tmp << 4) - tmp; \+ } while (0)+# define MOD28(a) \+ do { \+ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0)-# define MOD4(a) \+# define MOD(a) \ do { \- if (a >= (BASE << 4)) a -= (BASE << 4); \- if (a >= (BASE << 3)) a -= (BASE << 3); \- if (a >= (BASE << 2)) a -= (BASE << 2); \- if (a >= (BASE << 1)) a -= (BASE << 1); \+ CHOP(a); \+ MOD28(a); \+ } while (0)+# define MOD63(a) \+ do { /* this assumes a is not negative */ \+ z_off64_t tmp = a >> 32; \+ a &= 0xffffffffL; \+ a += (tmp << 8) - (tmp << 5) + tmp; \+ tmp = a >> 16; \+ a &= 0xffffL; \+ a += (tmp << 4) - tmp; \+ tmp = a >> 16; \+ a &= 0xffffL; \+ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE-# define MOD4(a) a %= BASE+# define MOD28(a) a %= BASE+# define MOD63(a) a %= BASE #endif /* ========================================================================= */@@ -92,7 +97,7 @@ } if (adler >= BASE) adler -= BASE;- MOD4(sum2); /* only added so many BASE's */+ MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } @@ -137,8 +142,13 @@ unsigned long sum2; unsigned rem; + /* for negative len, return invalid adler32 as a clue for debugging */+ if (len2 < 0)+ return 0xffffffffUL;+ /* the derivation of this formula is left as an exercise for the reader */- rem = (unsigned)(len2 % BASE);+ MOD63(len2); /* assumes len2 >= 0 */+ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2);
cbits/compress.c view
@@ -29,7 +29,7 @@ z_stream stream; int err; - stream.next_in = (Bytef*)source;+ stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; #ifdef MAXSEG_64K /* Check for source > 64K on 16-bit machine: */
cbits/crc32.c view
@@ -1,5 +1,5 @@ /* crc32.c -- compute the CRC-32 of a data stream- * Copyright (C) 1995-2006, 2010 Mark Adler+ * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster@@ -17,6 +17,8 @@ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32().++ DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH@@ -30,31 +32,11 @@ #define local static -/* Find a four-byte integer type for crc32_little() and crc32_big(). */-#ifndef NOBYFOUR-# ifdef STDC /* need ANSI C limits.h to determine sizes */-# include <limits.h>-# define BYFOUR-# if (UINT_MAX == 0xffffffffUL)- typedef unsigned int u4;-# else-# if (ULONG_MAX == 0xffffffffUL)- typedef unsigned long u4;-# else-# if (USHRT_MAX == 0xffffffffUL)- typedef unsigned short u4;-# else-# undef BYFOUR /* can't find a four-byte integer type! */-# endif-# endif-# endif-# endif /* STDC */-#endif /* !NOBYFOUR */- /* Definitions for doing the crc four data bytes at a time. */+#if !defined(NOBYFOUR) && defined(Z_U4)+# define BYFOUR+#endif #ifdef BYFOUR-# define REV(w) ((((w)>>24)&0xff)+(((w)>>8)&0xff00)+ \- (((w)&0xff00)<<8)+(((w)&0xff)<<24)) local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, unsigned)); local unsigned long crc32_big OF((unsigned long,@@ -68,16 +50,16 @@ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));-local uLong crc32_combine_(uLong crc1, uLong crc2, z_off64_t len2);+local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1;-local unsigned long FAR crc_table[TBLS][256];+local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH- local void write_table OF((FILE *, const unsigned long FAR *));+ local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:@@ -107,9 +89,9 @@ */ local void make_crc_table() {- unsigned long c;+ z_crc_t c; int n, k;- unsigned long poly; /* polynomial exclusive-or pattern */+ z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};@@ -121,13 +103,13 @@ first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */- poly = 0UL;- for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)- poly |= 1UL << (31 - p[n]);+ poly = 0;+ for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++)+ poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) {- c = (unsigned long)n;+ c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c;@@ -138,11 +120,11 @@ and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n];- crc_table[4][n] = REV(c);+ crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c;- crc_table[k + 4][n] = REV(c);+ crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */@@ -164,7 +146,7 @@ if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n");- fprintf(out, "local const unsigned long FAR ");+ fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR@@ -184,12 +166,13 @@ #ifdef MAKECRCH local void write_table(out, table) FILE *out;- const unsigned long FAR *table;+ const z_crc_t FAR *table; { int n; for (n = 0; n < 256; n++)- fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ",+ (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */@@ -204,13 +187,13 @@ /* ========================================================================= * This function can be used by asm versions of crc32() */-const unsigned long FAR * ZEXPORT get_crc_table()+const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */- return (const unsigned long FAR *)crc_table;+ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */@@ -232,7 +215,7 @@ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) {- u4 endian;+ z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian)))@@ -266,17 +249,17 @@ const unsigned char FAR *buf; unsigned len; {- register u4 c;- register const u4 FAR *buf4;+ register z_crc_t c;+ register const z_crc_t FAR *buf4; - c = (u4)crc;+ c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } - buf4 = (const u4 FAR *)(const void FAR *)buf;+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32;@@ -306,17 +289,17 @@ const unsigned char FAR *buf; unsigned len; {- register u4 c;- register const u4 FAR *buf4;+ register z_crc_t c;+ register const z_crc_t FAR *buf4; - c = REV((u4)crc);+ c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } - buf4 = (const u4 FAR *)(const void FAR *)buf;+ buf4 = (const z_crc_t FAR *)(const void FAR *)buf; buf4--; while (len >= 32) { DOBIG32;@@ -333,7 +316,7 @@ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c;- return (unsigned long)(REV(c));+ return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */
cbits/crc32.h view
@@ -2,7 +2,7 @@ * Generated automatically by crc32.c */ -local const unsigned long FAR crc_table[TBLS][256] =+local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
cbits/deflate.c view
@@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm- * Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler+ * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -37,7 +37,7 @@ * REFERENCES * * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".- * Available in http://www.ietf.org/rfc/rfc1951.txt+ * Available in http://tools.ietf.org/html/rfc1951 * * A description of the Rabin and Karp algorithm is given in the book * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.@@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] =- " deflate 1.2.5 Copyright 1995-2010 Jean-loup Gailly and Mark Adler ";+ " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; /* 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@@ -155,6 +155,9 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ #endif +/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */+#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0))+ /* =========================================================================== * Update a hash value with the given input byte * IN assertion: all calls to to UPDATE_HASH are made with consecutive@@ -235,10 +238,19 @@ strm->msg = Z_NULL; if (strm->zalloc == (alloc_func)0) {+#ifdef Z_SOLO+ return Z_STREAM_ERROR;+#else strm->zalloc = zcalloc; strm->opaque = (voidpf)0;+#endif }- if (strm->zfree == (free_func)0) strm->zfree = zcfree;+ if (strm->zfree == (free_func)0)+#ifdef Z_SOLO+ return Z_STREAM_ERROR;+#else+ strm->zfree = zcfree;+#endif #ifdef FASTEST if (level != 0) level = 1;@@ -293,7 +305,7 @@ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || s->pending_buf == Z_NULL) { s->status = FINISH_STATE;- strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);+ strm->msg = ERR_MSG(Z_MEM_ERROR); deflateEnd (strm); return Z_MEM_ERROR; }@@ -314,43 +326,70 @@ uInt dictLength; { deflate_state *s;- uInt length = dictLength;- uInt n;- IPos hash_head = 0;+ uInt str, n;+ int wrap;+ unsigned avail;+ z_const unsigned char *next; - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||- strm->state->wrap == 2 ||- (strm->state->wrap == 1 && strm->state->status != INIT_STATE))+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) return Z_STREAM_ERROR;- s = strm->state;- if (s->wrap)+ wrap = s->wrap;+ if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead)+ return Z_STREAM_ERROR;++ /* when using zlib wrappers, compute Adler-32 for provided dictionary */+ if (wrap == 1) strm->adler = adler32(strm->adler, dictionary, dictLength);+ s->wrap = 0; /* avoid computing Adler-32 in read_buf */ - if (length < MIN_MATCH) return Z_OK;- if (length > s->w_size) {- length = s->w_size;- dictionary += dictLength - length; /* use the tail of the dictionary */+ /* if dictionary would fill window, just replace the history */+ if (dictLength >= s->w_size) {+ if (wrap == 0) { /* already empty otherwise */+ CLEAR_HASH(s);+ s->strstart = 0;+ s->block_start = 0L;+ s->insert = 0;+ }+ dictionary += dictLength - s->w_size; /* use the tail */+ dictLength = s->w_size; }- zmemcpy(s->window, dictionary, length);- s->strstart = length;- s->block_start = (long)length; - /* Insert all strings in the hash table (except for the last two bytes).- * s->lookahead stays null, so s->ins_h will be recomputed at the next- * call of fill_window.- */- s->ins_h = s->window[0];- UPDATE_HASH(s, s->ins_h, s->window[1]);- for (n = 0; n <= length - MIN_MATCH; n++) {- INSERT_STRING(s, n, hash_head);+ /* insert dictionary into window and hash */+ avail = strm->avail_in;+ next = strm->next_in;+ strm->avail_in = dictLength;+ strm->next_in = (z_const Bytef *)dictionary;+ fill_window(s);+ while (s->lookahead >= MIN_MATCH) {+ str = s->strstart;+ n = s->lookahead - (MIN_MATCH-1);+ do {+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);+#ifndef FASTEST+ s->prev[str & s->w_mask] = s->head[s->ins_h];+#endif+ s->head[s->ins_h] = (Pos)str;+ str++;+ } while (--n);+ s->strstart = str;+ s->lookahead = MIN_MATCH-1;+ fill_window(s); }- if (hash_head) hash_head = 0; /* to make compiler happy */+ s->strstart += s->lookahead;+ s->block_start = (long)s->strstart;+ s->insert = s->lookahead;+ s->lookahead = 0;+ s->match_length = s->prev_length = MIN_MATCH-1;+ s->match_available = 0;+ strm->next_in = next;+ strm->avail_in = avail;+ s->wrap = wrap; return Z_OK; } /* ========================================================================= */-int ZEXPORT deflateReset (strm)+int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s;@@ -380,12 +419,23 @@ s->last_flush = Z_NO_FLUSH; _tr_init(s);- lm_init(s); return Z_OK; } /* ========================================================================= */+int ZEXPORT deflateReset (strm)+ z_streamp strm;+{+ int ret;++ ret = deflateResetKeep(strm);+ if (ret == Z_OK)+ lm_init(strm->state);+ return ret;+}++/* ========================================================================= */ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head;@@ -397,14 +447,42 @@ } /* ========================================================================= */+int ZEXPORT deflatePending (strm, pending, bits)+ unsigned *pending;+ int *bits;+ z_streamp strm;+{+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;+ if (pending != Z_NULL)+ *pending = strm->state->pending;+ if (bits != Z_NULL)+ *bits = strm->state->bi_valid;+ return Z_OK;+}++/* ========================================================================= */ int ZEXPORT deflatePrime (strm, bits, value) z_streamp strm; int bits; int value; {+ deflate_state *s;+ int put;+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;- strm->state->bi_valid = bits;- strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));+ s = strm->state;+ if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3))+ return Z_BUF_ERROR;+ do {+ put = Buf_size - s->bi_valid;+ if (put > bits)+ put = bits;+ s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid);+ s->bi_valid += put;+ _tr_flush_bits(s);+ value >>= put;+ bits -= put;+ } while (bits); return Z_OK; } @@ -435,6 +513,8 @@ strm->total_in != 0) { /* Flush the last buffer: */ err = deflate(strm, Z_BLOCK);+ if (err == Z_BUF_ERROR && s->pending == 0)+ err = Z_OK; } if (s->level != level) { s->level = level;@@ -562,19 +642,22 @@ local void flush_pending(strm) z_streamp strm; {- unsigned len = strm->state->pending;+ unsigned len;+ deflate_state *s = strm->state; + _tr_flush_bits(s);+ len = s->pending; if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; - zmemcpy(strm->next_out, strm->state->pending_out, len);+ zmemcpy(strm->next_out, s->pending_out, len); strm->next_out += len;- strm->state->pending_out += len;+ s->pending_out += len; strm->total_out += len; strm->avail_out -= len;- strm->state->pending -= len;- if (strm->state->pending == 0) {- strm->state->pending_out = strm->state->pending_buf;+ s->pending -= len;+ if (s->pending == 0) {+ s->pending_out = s->pending_buf; } } @@ -801,7 +884,7 @@ * flushes. For repeated and useless calls with Z_FINISH, we keep * returning Z_STREAM_END instead of Z_BUF_ERROR. */- } else if (strm->avail_in == 0 && flush <= old_flush &&+ } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && flush != Z_FINISH) { ERR_RETURN(strm, Z_BUF_ERROR); }@@ -850,6 +933,7 @@ if (s->lookahead == 0) { s->strstart = 0; s->block_start = 0L;+ s->insert = 0; } } }@@ -945,12 +1029,12 @@ ss = source->state; - zmemcpy(dest, source, sizeof(z_stream));+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); if (ds == Z_NULL) return Z_MEM_ERROR; dest->state = (struct internal_state FAR *) ds;- zmemcpy(ds, ss, sizeof(deflate_state));+ zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); ds->strm = dest; ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));@@ -966,8 +1050,8 @@ } /* following zmemcpy do not work for 16-bit MSDOS */ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));- zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));- zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));+ zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos));+ zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);@@ -1001,15 +1085,15 @@ strm->avail_in -= len; + zmemcpy(buf, strm->next_in, len); if (strm->state->wrap == 1) {- strm->adler = adler32(strm->adler, strm->next_in, len);+ strm->adler = adler32(strm->adler, buf, len); } #ifdef GZIP else if (strm->state->wrap == 2) {- strm->adler = crc32(strm->adler, strm->next_in, len);+ strm->adler = crc32(strm->adler, buf, len); } #endif- zmemcpy(buf, strm->next_in, len); strm->next_in += len; strm->total_in += len; @@ -1036,6 +1120,7 @@ s->strstart = 0; s->block_start = 0L; s->lookahead = 0;+ s->insert = 0; s->match_length = s->prev_length = MIN_MATCH-1; s->match_available = 0; s->ins_h = 0;@@ -1310,6 +1395,8 @@ unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; + Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");+ do { more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); @@ -1362,7 +1449,7 @@ #endif more += wsize; }- if (s->strm->avail_in == 0) return;+ if (s->strm->avail_in == 0) break; /* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&@@ -1381,12 +1468,24 @@ s->lookahead += n; /* Initialize the hash value now that we have some input: */- if (s->lookahead >= MIN_MATCH) {- s->ins_h = s->window[s->strstart];- UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);+ if (s->lookahead + s->insert >= MIN_MATCH) {+ uInt str = s->strstart - s->insert;+ s->ins_h = s->window[str];+ UPDATE_HASH(s, s->ins_h, s->window[str + 1]); #if MIN_MATCH != 3 Call UPDATE_HASH() MIN_MATCH-3 more times #endif+ while (s->insert) {+ UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]);+#ifndef FASTEST+ s->prev[str & s->w_mask] = s->head[s->ins_h];+#endif+ s->head[s->ins_h] = (Pos)str;+ str++;+ s->insert--;+ if (s->lookahead + s->insert < MIN_MATCH)+ break;+ } } /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, * but this is not important since only literal bytes will be emitted.@@ -1427,6 +1526,9 @@ s->high_water += init; } }++ Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,+ "not enough room for search"); } /* ===========================================================================@@ -1506,8 +1608,14 @@ FLUSH_BLOCK(s, 0); } }- FLUSH_BLOCK(s, flush == Z_FINISH);- return flush == Z_FINISH ? finish_done : block_done;+ s->insert = 0;+ if (flush == Z_FINISH) {+ FLUSH_BLOCK(s, 1);+ return finish_done;+ }+ if ((long)s->strstart > s->block_start)+ FLUSH_BLOCK(s, 0);+ return block_done; } /* ===========================================================================@@ -1603,8 +1711,14 @@ } if (bflush) FLUSH_BLOCK(s, 0); }- FLUSH_BLOCK(s, flush == Z_FINISH);- return flush == Z_FINISH ? finish_done : block_done;+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;+ if (flush == Z_FINISH) {+ FLUSH_BLOCK(s, 1);+ return finish_done;+ }+ if (s->last_lit)+ FLUSH_BLOCK(s, 0);+ return block_done; } #ifndef FASTEST@@ -1728,8 +1842,14 @@ _tr_tally_lit(s, s->window[s->strstart-1], bflush); s->match_available = 0; }- FLUSH_BLOCK(s, flush == Z_FINISH);- return flush == Z_FINISH ? finish_done : block_done;+ s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1;+ if (flush == Z_FINISH) {+ FLUSH_BLOCK(s, 1);+ return finish_done;+ }+ if (s->last_lit)+ FLUSH_BLOCK(s, 0);+ return block_done; } #endif /* FASTEST */ @@ -1749,11 +1869,11 @@ for (;;) { /* Make sure that we always have enough lookahead, except * at the end of the input file. We need MAX_MATCH bytes- * for the longest encodable run.+ * for the longest run, plus one for the unrolled loop. */- if (s->lookahead < MAX_MATCH) {+ if (s->lookahead <= MAX_MATCH) { fill_window(s);- if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {+ if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { return need_more; } if (s->lookahead == 0) break; /* flush the current block */@@ -1776,6 +1896,7 @@ if (s->match_length > s->lookahead) s->match_length = s->lookahead; }+ Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); } /* Emit match if have run of MIN_MATCH or longer, else emit literal */@@ -1796,8 +1917,14 @@ } if (bflush) FLUSH_BLOCK(s, 0); }- FLUSH_BLOCK(s, flush == Z_FINISH);- return flush == Z_FINISH ? finish_done : block_done;+ s->insert = 0;+ if (flush == Z_FINISH) {+ FLUSH_BLOCK(s, 1);+ return finish_done;+ }+ if (s->last_lit)+ FLUSH_BLOCK(s, 0);+ return block_done; } /* ===========================================================================@@ -1829,6 +1956,12 @@ s->strstart++; if (bflush) FLUSH_BLOCK(s, 0); }- FLUSH_BLOCK(s, flush == Z_FINISH);- return flush == Z_FINISH ? finish_done : block_done;+ s->insert = 0;+ if (flush == Z_FINISH) {+ FLUSH_BLOCK(s, 1);+ return finish_done;+ }+ if (s->last_lit)+ FLUSH_BLOCK(s, 0);+ return block_done; }
cbits/deflate.h view
@@ -1,5 +1,5 @@ /* deflate.h -- internal compression state- * Copyright (C) 1995-2010 Jean-loup Gailly+ * Copyright (C) 1995-2012 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -48,6 +48,9 @@ #define MAX_BITS 15 /* All codes must not exceed MAX_BITS bits */ +#define Buf_size 16+/* size of bit buffer in bi_buf */+ #define INIT_STATE 42 #define EXTRA_STATE 69 #define NAME_STATE 73@@ -101,7 +104,7 @@ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ uInt gzindex; /* where in extra, name, or comment */- Byte method; /* STORED (for zip only) or DEFLATED */+ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ /* used by deflate.c: */@@ -188,7 +191,7 @@ int nice_match; /* Stop searching when current match exceeds this */ /* used by trees.c: */- /* Didn't use ct_data typedef below to supress compiler warning */+ /* Didn't use ct_data typedef below to suppress compiler warning */ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */@@ -244,7 +247,7 @@ ulg opt_len; /* bit length of current block with optimal trees */ ulg static_len; /* bit length of current block with static trees */ uInt matches; /* number of string matches in current block */- int last_eob_len; /* bit length of EOB code for last block */+ uInt insert; /* bytes at end of window left to insert */ #ifdef DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */@@ -294,6 +297,7 @@ int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, int last));+void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, int last));
cbits/infback.c view
@@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface- * Copyright (C) 1995-2009 Mark Adler+ * Copyright (C) 1995-2011 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -42,10 +42,19 @@ return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) {+#ifdef Z_SOLO+ return Z_STREAM_ERROR;+#else strm->zalloc = zcalloc; strm->opaque = (voidpf)0;+#endif }- if (strm->zfree == (free_func)0) strm->zfree = zcfree;+ if (strm->zfree == (free_func)0)+#ifdef Z_SOLO+ return Z_STREAM_ERROR;+#else+ strm->zfree = zcfree;+#endif state = (struct inflate_state FAR *)ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR;@@ -246,7 +255,7 @@ void FAR *out_desc; { struct inflate_state FAR *state;- unsigned char FAR *next; /* next input */+ z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */@@ -394,7 +403,6 @@ PULLBYTE(); } if (here.val < 16) {- NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; }
cbits/inffast.c view
@@ -1,5 +1,5 @@ /* inffast.c -- fast decoding- * Copyright (C) 1995-2008, 2010 Mark Adler+ * Copyright (C) 1995-2008, 2010, 2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -69,8 +69,8 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state;- unsigned char FAR *in; /* local strm->next_in */- unsigned char FAR *last; /* while in < last, enough input available */+ z_const unsigned char FAR *in; /* local strm->next_in */+ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */
cbits/inffixed.h view
@@ -2,9 +2,9 @@ * Generated automatically by makefixed(). */ - /* WARNING: this file should *not* be used by applications. It- is part of the implementation of the compression library and- is subject to change. Applications should only use zlib.h.+ /* WARNING: this file should *not* be used by applications.+ It is part of the implementation of this library and is+ subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = {
cbits/inflate.c view
@@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression- * Copyright (C) 1995-2010 Mark Adler+ * Copyright (C) 1995-2012 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -93,14 +93,15 @@ /* function prototypes */ local void fixedtables OF((struct inflate_state FAR *state));-local int updatewindow OF((z_streamp strm, unsigned out));+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, unsigned char FAR *buf,+local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); -int ZEXPORT inflateReset(strm)+int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state;@@ -109,15 +110,13 @@ state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL;- strm->adler = 1; /* to support ill-conceived Java test suite */+ if (state->wrap) /* to support ill-conceived Java test suite */+ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL;- state->wsize = 0;- state->whave = 0;- state->wnext = 0; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes;@@ -127,6 +126,19 @@ return Z_OK; } +int ZEXPORT inflateReset(strm)+z_streamp strm;+{+ struct inflate_state FAR *state;++ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;+ state = (struct inflate_state FAR *)strm->state;+ state->wsize = 0;+ state->whave = 0;+ state->wnext = 0;+ return inflateResetKeep(strm);+}+ int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits;@@ -180,10 +192,19 @@ if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) {+#ifdef Z_SOLO+ return Z_STREAM_ERROR;+#else strm->zalloc = zcalloc; strm->opaque = (voidpf)0;+#endif }- if (strm->zfree == (free_func)0) strm->zfree = zcfree;+ if (strm->zfree == (free_func)0)+#ifdef Z_SOLO+ return Z_STREAM_ERROR;+#else+ strm->zfree = zcfree;+#endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR;@@ -321,8 +342,8 @@ low = 0; for (;;) { if ((low % 7) == 0) printf("\n ");- printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,- state.lencode[low].val);+ printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op,+ state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); }@@ -355,12 +376,13 @@ 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. */-local int updatewindow(strm, out)+local int updatewindow(strm, end, copy) z_streamp strm;-unsigned out;+const Bytef *end;+unsigned copy; { struct inflate_state FAR *state;- unsigned copy, dist;+ unsigned dist; state = (struct inflate_state FAR *)strm->state; @@ -380,19 +402,18 @@ } /* copy state->wsize or less output bytes into the circular window */- copy = out - strm->avail_out; if (copy >= state->wsize) {- zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);+ zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy;- zmemcpy(state->window + state->wnext, strm->next_out - copy, dist);+ zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) {- zmemcpy(state->window, strm->next_out - copy, copy);+ zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; }@@ -499,11 +520,6 @@ bits -= bits & 7; \ } while (0) -/* Reverse the bytes in a 32-bit value */-#define REVERSE(q) \- ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \- (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))- /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is@@ -591,7 +607,7 @@ int flush; { struct inflate_state FAR *state;- unsigned char FAR *next; /* next input */+ z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */@@ -797,7 +813,7 @@ #endif case DICTID: NEEDBITS(32);- strm->adler = state->check = REVERSE(hold);+ strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT:@@ -905,7 +921,7 @@ while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes;- state->lencode = (code const FAR *)(state->next);+ state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work);@@ -925,7 +941,6 @@ PULLBYTE(); } if (here.val < 16) {- NEEDBITS(here.bits); DROPBITS(here.bits); state->lens[state->have++] = here.val; }@@ -980,7 +995,7 @@ values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes;- state->lencode = (code const FAR *)(state->next);+ state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work);@@ -989,7 +1004,7 @@ state->mode = BAD; break; }- state->distcode = (code const FAR *)(state->next);+ state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work);@@ -1170,7 +1185,7 @@ #ifdef GUNZIP state->flags ? hold : #endif- REVERSE(hold)) != state->check) {+ ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break;@@ -1214,8 +1229,9 @@ */ inf_leave: RESTORE();- if (state->wsize || (state->mode < CHECK && out != strm->avail_out))- if (updatewindow(strm, out)) {+ if (state->wsize || (out != strm->avail_out && state->mode < BAD &&+ (state->mode < CHECK || flush != Z_FINISH)))+ if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; }@@ -1249,13 +1265,37 @@ return Z_OK; } +int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength)+z_streamp strm;+Bytef *dictionary;+uInt *dictLength;+{+ struct inflate_state FAR *state;++ /* check state */+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;+ state = (struct inflate_state FAR *)strm->state;++ /* copy dictionary */+ if (state->whave && dictionary != Z_NULL) {+ zmemcpy(dictionary, state->window + state->wnext,+ state->whave - state->wnext);+ zmemcpy(dictionary + state->whave - state->wnext,+ state->window, state->wnext);+ }+ if (dictLength != Z_NULL)+ *dictLength = state->whave;+ return Z_OK;+}+ int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state;- unsigned long id;+ unsigned long dictid;+ int ret; /* check state */ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;@@ -1263,29 +1303,21 @@ if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; - /* check for correct dictionary id */+ /* check for correct dictionary identifier */ if (state->mode == DICT) {- id = adler32(0L, Z_NULL, 0);- id = adler32(id, dictionary, dictLength);- if (id != state->check)+ dictid = adler32(0L, Z_NULL, 0);+ dictid = adler32(dictid, dictionary, dictLength);+ if (dictid != state->check) return Z_DATA_ERROR; } - /* copy dictionary to window */- if (updatewindow(strm, strm->avail_out)) {+ /* copy dictionary to window using updatewindow(), which will amend the+ existing dictionary if appropriate */+ ret = updatewindow(strm, dictionary + dictLength, dictLength);+ if (ret) { state->mode = MEM; return Z_MEM_ERROR; }- if (dictLength > state->wsize) {- zmemcpy(state->window, dictionary + dictLength - state->wsize,- state->wsize);- state->whave = state->wsize;- }- else {- zmemcpy(state->window + state->wsize - dictLength, dictionary,- dictLength);- state->whave = dictLength;- } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK;@@ -1321,7 +1353,7 @@ */ local unsigned syncsearch(have, buf, len) unsigned FAR *have;-unsigned char FAR *buf;+const unsigned char FAR *buf; unsigned len; { unsigned got;@@ -1433,8 +1465,8 @@ } /* copy state */- zmemcpy(dest, source, sizeof(z_stream));- zmemcpy(copy, state, sizeof(struct inflate_state));+ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream));+ zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes);
cbits/inftrees.c view
@@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding- * Copyright (C) 1995-2010 Mark Adler+ * Copyright (C) 1995-2013 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] =- " inflate 1.2.5 Copyright 1995-2010 Mark Adler ";+ " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; /* 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@@ -62,7 +62,7 @@ 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 */ 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, 73, 195};+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; 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, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,@@ -208,8 +208,8 @@ mask = used - 1; /* mask for comparing low */ /* check available table space */- if ((type == LENS && used >= ENOUGH_LENS) ||- (type == DISTS && used >= ENOUGH_DISTS))+ if ((type == LENS && used > ENOUGH_LENS) ||+ (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */@@ -277,8 +277,8 @@ /* check for enough space */ used += 1U << curr;- if ((type == LENS && used >= ENOUGH_LENS) ||- (type == DISTS && used >= ENOUGH_DISTS))+ if ((type == LENS && used > ENOUGH_LENS) ||+ (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */@@ -289,38 +289,14 @@ } } - /*- Fill in rest of table for incomplete codes. This loop is similar to the- loop above in incrementing huff for table indices. It is assumed that- len is equal to curr + drop, so there is no loop needed to increment- through high index bits. When the current sub-table is filled, the loop- drops back to the root table to fill in any remaining entries there.- */- here.op = (unsigned char)64; /* invalid code marker */- here.bits = (unsigned char)(len - drop);- here.val = (unsigned short)0;- while (huff != 0) {- /* when done with sub-table, drop back to root table */- if (drop != 0 && (huff & mask) != low) {- drop = 0;- len = root;- next = *table;- here.bits = (unsigned char)len;- }-- /* put invalid code marker in table */- next[huff >> drop] = here;-- /* backwards increment the len-bit code huff */- incr = 1U << (len - 1);- while (huff & incr)- incr >>= 1;- if (incr != 0) {- huff &= incr - 1;- huff += incr;- }- else- huff = 0;+ /* fill in remaining table entry if code is incomplete (guaranteed to have+ at most one remaining entry, since if the code is incomplete, the+ maximum code length that was allowed to get this far is one bit) */+ if (huff != 0) {+ here.op = (unsigned char)64; /* invalid code marker */+ here.bits = (unsigned char)(len - drop);+ here.val = (unsigned short)0;+ next[huff] = here; } /* set return parameters */
cbits/trees.c view
@@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding- * Copyright (C) 1995-2010 Jean-loup Gailly+ * Copyright (C) 1995-2012 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */@@ -74,11 +74,6 @@ * probability, to avoid transmitting the lengths for unused bit length codes. */ -#define Buf_size (8 * 2*sizeof(char))-/* Number of bits used within bi_buf. (bi_buf might be implemented on- * more than 16 bits on some systems.)- */- /* =========================================================================== * Local data. These are initialized only once. */@@ -151,8 +146,8 @@ local int build_bl_tree OF((deflate_state *s)); local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, int blcodes));-local void compress_block OF((deflate_state *s, ct_data *ltree,- ct_data *dtree));+local void compress_block OF((deflate_state *s, const ct_data *ltree,+ 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));@@ -399,7 +394,6 @@ s->bi_buf = 0; s->bi_valid = 0;- s->last_eob_len = 8; /* enough lookahead for inflate */ #ifdef DEBUG s->compressed_len = 0L; s->bits_sent = 0L;@@ -883,15 +877,17 @@ } /* ===========================================================================+ * Flush the bits in the bit buffer to pending output (leaves at most 7 bits)+ */+void ZLIB_INTERNAL _tr_flush_bits(s)+ deflate_state *s;+{+ bi_flush(s);+}++/* =========================================================================== * Send one empty static block to give enough lookahead for inflate. * This takes 10 bits, of which 7 may remain in the bit buffer.- * The current inflate code requires 9 bits of lookahead. If the- * last two codes for the previous block (real code plus EOB) were coded- * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode- * the last real code. In this case we send two empty static blocks instead- * of one. (There are no problems if the previous block is stored or fixed.)- * To simplify the code, we assume the worst case of last real code encoded- * on one bit only. */ void ZLIB_INTERNAL _tr_align(s) deflate_state *s;@@ -902,20 +898,6 @@ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s);- /* Of the 10 bits for the empty block, we have already sent- * (10 - bi_valid) bits. The lookahead for the last real code (before- * the EOB of the previous block) was thus at least one plus the length- * of the EOB plus what we have just sent of the empty static block.- */- if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {- send_bits(s, STATIC_TREES<<1, 3);- send_code(s, END_BLOCK, static_ltree);-#ifdef DEBUG- s->compressed_len += 10L;-#endif- bi_flush(s);- }- s->last_eob_len = 7; } /* ===========================================================================@@ -990,7 +972,8 @@ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { #endif send_bits(s, (STATIC_TREES<<1)+last, 3);- compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);+ compress_block(s, (const ct_data *)static_ltree,+ (const ct_data *)static_dtree); #ifdef DEBUG s->compressed_len += 3 + s->static_len; #endif@@ -998,7 +981,8 @@ send_bits(s, (DYN_TREES<<1)+last, 3); send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, max_blindex+1);- compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);+ compress_block(s, (const ct_data *)s->dyn_ltree,+ (const ct_data *)s->dyn_dtree); #ifdef DEBUG s->compressed_len += 3 + s->opt_len; #endif@@ -1075,8 +1059,8 @@ */ local void compress_block(s, ltree, dtree) deflate_state *s;- ct_data *ltree; /* literal tree */- ct_data *dtree; /* distance tree */+ 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) */@@ -1118,7 +1102,6 @@ } while (lx < s->last_lit); send_code(s, END_BLOCK, ltree);- s->last_eob_len = ltree[END_BLOCK].Len; } /* ===========================================================================@@ -1226,7 +1209,6 @@ int header; /* true if block header must be written */ { bi_windup(s); /* align on byte boundary */- s->last_eob_len = 8; /* enough lookahead for inflate */ if (header) { put_short(s, (ush)len);
cbits/uncompr.c view
@@ -30,7 +30,7 @@ z_stream stream; int err; - stream.next_in = (Bytef*)source;+ stream.next_in = (z_const Bytef *)source; stream.avail_in = (uInt)sourceLen; /* Check for source > 64K on 16-bit machine: */ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
cbits/zconf.h view
@@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library- * Copyright (C) 1995-2010 Jean-loup Gailly.+ * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -15,11 +15,13 @@ * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */+# define Z_PREFIX_SET /* all linked symbols */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align+# define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block@@ -27,9 +29,11 @@ # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64-# define compress z_compress-# define compress2 z_compress2-# define compressBound z_compressBound+# ifndef Z_SOLO+# define compress z_compress+# define compress2 z_compress2+# define compressBound z_compressBound+# endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64@@ -40,44 +44,53 @@ # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams+# define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset+# define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table-# define gz_error z_gz_error-# define gz_intmax z_gz_intmax-# define gz_strwinerror z_gz_strwinerror-# define gzbuffer z_gzbuffer-# define gzclearerr z_gzclearerr-# define gzclose z_gzclose-# define gzclose_r z_gzclose_r-# define gzclose_w z_gzclose_w-# define gzdirect z_gzdirect-# define gzdopen z_gzdopen-# define gzeof z_gzeof-# define gzerror z_gzerror-# define gzflush z_gzflush-# define gzgetc z_gzgetc-# define gzgets z_gzgets-# define gzoffset z_gzoffset-# define gzoffset64 z_gzoffset64-# define gzopen z_gzopen-# define gzopen64 z_gzopen64-# define gzprintf z_gzprintf-# define gzputc z_gzputc-# define gzputs z_gzputs-# define gzread z_gzread-# define gzrewind z_gzrewind-# define gzseek z_gzseek-# define gzseek64 z_gzseek64-# define gzsetparams z_gzsetparams-# define gztell z_gztell-# define gztell64 z_gztell64-# define gzungetc z_gzungetc-# define gzwrite z_gzwrite+# ifndef Z_SOLO+# define gz_error z_gz_error+# define gz_intmax z_gz_intmax+# define gz_strwinerror z_gz_strwinerror+# define gzbuffer z_gzbuffer+# define gzclearerr z_gzclearerr+# define gzclose z_gzclose+# define gzclose_r z_gzclose_r+# define gzclose_w z_gzclose_w+# define gzdirect z_gzdirect+# define gzdopen z_gzdopen+# define gzeof z_gzeof+# define gzerror z_gzerror+# define gzflush z_gzflush+# define gzgetc z_gzgetc+# define gzgetc_ z_gzgetc_+# define gzgets z_gzgets+# define gzoffset z_gzoffset+# define gzoffset64 z_gzoffset64+# define gzopen z_gzopen+# define gzopen64 z_gzopen64+# ifdef _WIN32+# define gzopen_w z_gzopen_w+# endif+# define gzprintf z_gzprintf+# define gzvprintf z_gzvprintf+# define gzputc z_gzputc+# define gzputs z_gzputs+# define gzread z_gzread+# define gzrewind z_gzrewind+# define gzseek z_gzseek+# define gzseek64 z_gzseek64+# define gzsetparams z_gzsetparams+# define gztell z_gztell+# define gztell64 z_gztell64+# define gzungetc z_gzungetc+# define gzwrite z_gzwrite+# endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd@@ -92,16 +105,22 @@ # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateSetDictionary z_inflateSetDictionary+# define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine+# define inflateResetKeep z_inflateResetKeep # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table-# define uncompress z_uncompress+# ifndef Z_SOLO+# define uncompress z_uncompress+# endif # define zError z_zError-# define zcalloc z_zcalloc-# define zcfree z_zcfree+# ifndef Z_SOLO+# define zcalloc z_zcalloc+# define zcfree z_zcfree+# endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion @@ -111,7 +130,9 @@ # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func-# define gzFile z_gzFile+# ifndef Z_SOLO+# define gzFile z_gzFile+# endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func@@ -197,6 +218,12 @@ # endif #endif +#if defined(ZLIB_CONST) && !defined(z_const)+# define z_const const+#else+# define z_const+#endif+ /* Some Mac compilers merge all .h files incorrectly: */ #if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) # define NO_DUMMY_DECL@@ -243,6 +270,14 @@ # endif #endif +#ifndef Z_ARG /* function prototypes for stdarg */+# if defined(STDC) || defined(Z_HAVE_STDARG_H)+# define Z_ARG(args) args+# else+# define Z_ARG(args) ()+# endif+#endif+ /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have@@ -356,35 +391,87 @@ typedef Byte *voidp; #endif +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC)+# include <limits.h>+# if (UINT_MAX == 0xffffffffUL)+# define Z_U4 unsigned+# elif (ULONG_MAX == 0xffffffffUL)+# define Z_U4 unsigned long+# elif (USHRT_MAX == 0xffffffffUL)+# define Z_U4 unsigned short+# endif+#endif++#ifdef Z_U4+ typedef Z_U4 z_crc_t;+#else+ typedef unsigned long z_crc_t;+#endif+ #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */+# define Z_HAVE_STDARG_H+#endif+ #ifdef STDC-# include <sys/types.h> /* for off_t */+# ifndef Z_SOLO+# include <sys/types.h> /* for off_t */+# endif #endif +#if defined(STDC) || defined(Z_HAVE_STDARG_H)+# ifndef Z_SOLO+# include <stdarg.h> /* for va_list */+# endif+#endif++#ifdef _WIN32+# ifndef Z_SOLO+# include <stddef.h> /* for wchar_t */+# endif+#endif+ /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */-#if -_LARGEFILE64_SOURCE - -1 == 1+#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif -#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)-# include <unistd.h> /* for SEEK_* and off_t */-# ifdef VMS-# include <unixio.h> /* for off_t */-# endif-# ifndef z_off_t-# define z_off_t off_t+#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H)+# define Z_HAVE_UNISTD_H+#endif+#ifndef Z_SOLO+# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)+# include <unistd.h> /* for SEEK_*, off_t, and _LFS64_LARGEFILE */+# ifdef VMS+# include <unixio.h> /* for off_t */+# endif+# ifndef z_off_t+# define z_off_t off_t+# endif # endif #endif -#ifndef SEEK_SET+#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0+# define Z_LFS64+#endif++#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64)+# define Z_LARGE64+#endif++#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64)+# define Z_WANT64+#endif++#if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */@@ -394,18 +481,14 @@ # define z_off_t long #endif -#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0+#if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else-# define z_off64_t z_off_t-#endif--#if defined(__OS400__)-# define NO_vsnprintf-#endif--#if defined(__MVS__)-# define NO_vsnprintf+# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO)+# define z_off64_t __int64+# else+# define z_off64_t z_off_t+# endif #endif /* MVS linker does not support external names larger than 8 bytes */
cbits/zlib.h view
@@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library- version 1.2.5, April 19th, 2010+ version 1.2.8, April 28th, 2013 - Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler+ Copyright (C) 1995-2013 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@@ -24,8 +24,8 @@ The data format used by the zlib library is described by RFCs (Request for- Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt- (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).+ Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950+ (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H@@ -37,11 +37,11 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.5"-#define ZLIB_VERNUM 0x1250+#define ZLIB_VERSION "1.2.8"+#define ZLIB_VERNUM 0x1280 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2-#define ZLIB_VER_REVISION 5+#define ZLIB_VER_REVISION 8 #define ZLIB_VER_SUBREVISION 0 /*@@ -83,15 +83,15 @@ struct internal_state; typedef struct z_stream_s {- Bytef *next_in; /* next input byte */+ z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */- uLong total_in; /* total nb of input bytes read so far */+ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */- uLong total_out; /* total nb of bytes output so far */+ uLong total_out; /* total number of bytes output so far */ - char *msg; /* last error message, NULL if no error */+ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */@@ -327,8 +327,9 @@ Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least the- value returned by deflateBound (see below). If deflate does not return- Z_STREAM_END, then it must be called again as described above.+ value returned by deflateBound (see below). Then deflate is guaranteed to+ return Z_STREAM_END. If not enough output space is provided, deflate will+ not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the adler32 checksum of all input read so far (that is, total_in bytes).@@ -451,23 +452,29 @@ error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed;- avail_out must be large enough to hold all the uncompressed data. (The size- of the uncompressed data may have been saved by the compressor for this- purpose.) The next operation on this stream must be inflateEnd to deallocate- the decompression state. The use of Z_FINISH is never required, but can be- used to inform inflate that a faster approach may be used for the single- inflate() call.+ avail_out must be large enough to hold all of the uncompressed data for the+ operation to complete. (The size of the uncompressed data may have been+ saved by the compressor for this purpose.) The use of Z_FINISH is not+ required to perform an inflation in one step. However it may be used to+ inform inflate that a faster approach can be used for the single inflate()+ call. Z_FINISH also informs inflate to not maintain a sliding window if the+ stream completes, which reduces inflate's memory footprint. If the stream+ does not complete, either because not all of the stream is provided or not+ enough output space is provided, then a sliding window will be allocated and+ inflate() can be called again to continue the operation as if Z_NO_FLUSH had+ been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the- first call. So the only effect of the flush parameter in this implementation- is on the return value of inflate(), as noted below, or when it returns early- because Z_BLOCK or Z_TREES is used.+ first call. So the effects of the flush parameter in this implementation are+ on the return value of inflate() as noted below, when inflate() returns early+ when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of+ memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary- below), inflate sets strm->adler to the adler32 checksum of the dictionary+ below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets- strm->adler to the adler32 checksum of all output produced so far (that is,+ strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END@@ -478,7 +485,9 @@ initializing with inflateInit2(). Any information contained in the gzip header is not retained, so applications that need that information should instead use raw inflate, see inflateInit2() below, or inflateBack() and- perform their own processing of the gzip header and trailer.+ perform their own processing of the gzip header and trailer. When processing+ gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output+ producted so far. The CRC-32 is checked against the gzip trailer. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has@@ -580,10 +589,15 @@ uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence- without producing any compressed output. This function must be called- immediately after deflateInit, deflateInit2 or deflateReset, before any call- of deflate. The compressor and decompressor must use exactly the same- dictionary (see inflateSetDictionary).+ without producing any compressed output. When using the zlib format, this+ function must be called immediately after deflateInit, deflateInit2 or+ deflateReset, and before any call of deflate. When doing raw deflate, this+ function must be called either before any call of deflate, or immediately+ after the completion of a deflate block, i.e. after all input has been+ consumed and all output has been delivered when using any of the flush+ options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The+ compressor and decompressor must use exactly the same dictionary (see+ inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly@@ -610,8 +624,8 @@ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream- or if the compression method is bsort). deflateSetDictionary does not- perform any compression: this will be done by deflate().+ or if not at a block boundary for raw deflate). deflateSetDictionary does+ not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,@@ -688,9 +702,29 @@ deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be- called before deflate().+ called before deflate(). If that first deflate() call is provided the+ sourceLen input bytes, an output buffer allocated to the size returned by+ deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed+ to return Z_STREAM_END. Note that it is possible for the compressed size to+ be larger than the value returned by deflateBound() if flush options other+ than Z_FINISH or Z_NO_FLUSH are used. */ +ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm,+ unsigned *pending,+ int *bits));+/*+ deflatePending() returns the number of bytes and bits of output that have+ been generated, but not yet provided in the available output. The bytes not+ provided would be due to the available output space having being consumed.+ The number of bits of output not provided are between 0 and 7, where they+ await more bits to join them in order to fill out a full byte. If pending+ or bits are Z_NULL, then those values are not set.++ deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source+ stream state was inconsistent.+ */+ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value));@@ -703,8 +737,9 @@ than or equal to 16, and that many of the least significant bits of value will be inserted in the output. - deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source- stream state was inconsistent.+ deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough+ room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the+ source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,@@ -790,10 +825,11 @@ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the adler32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see- deflateSetDictionary). For raw inflate, this function can be called- immediately after inflateInit2() or inflateReset() and before any call of- inflate() to set the dictionary. The application must insure that the- dictionary that was used for compression is provided.+ deflateSetDictionary). For raw inflate, this function can be called at any+ time to set the dictionary. If the provided dictionary is smaller than the+ window and there is already data in the window, then the provided dictionary+ will amend what's there. The application must insure that the dictionary+ that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is@@ -803,19 +839,38 @@ inflate(). */ +ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm,+ Bytef *dictionary,+ uInt *dictLength));+/*+ Returns the sliding dictionary being maintained by inflate. dictLength is+ set to the number of bytes in the dictionary, and that many bytes are copied+ to dictionary. dictionary must have enough space, where 32768 bytes is+ always enough. If inflateGetDictionary() is called with dictionary equal to+ Z_NULL, then only the dictionary length is returned, and nothing is copied.+ Similary, if dictLength is Z_NULL, then it is not set.++ inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the+ stream state is inconsistent.+*/+ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /*- Skips invalid compressed data until a full flush point (see above the- description of deflate with Z_FULL_FLUSH) can be found, or until all+ Skips invalid compressed data until a possible full flush point (see above+ for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. - inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR- if no more input was provided, Z_DATA_ERROR if no flush point has been- found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the- success case, the application may save the current current value of total_in- which indicates where valid compressed data was found. In the error case,- the application may repeatedly call inflateSync, providing more input each- time, until success or end of the input data.+ inflateSync searches for a 00 00 FF FF pattern in the compressed data.+ All full flush points have this pattern, but not all occurrences of this+ pattern are full flush points.++ inflateSync returns Z_OK if a possible full flush point has been found,+ Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point+ has been found, or Z_STREAM_ERROR if the stream structure was inconsistent.+ In the success case, the application may save the current current value of+ total_in which indicates where valid compressed data was found. In the+ error case, the application may repeatedly call inflateSync, providing more+ input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,@@ -962,12 +1017,13 @@ See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of- the paramaters are invalid, Z_MEM_ERROR if the internal state could not be+ the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ -typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));+typedef unsigned (*in_func) OF((void FAR *,+ z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,@@ -975,11 +1031,12 @@ out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back- interface for input and output. This is more efficient than inflate() for- file i/o applications in that it avoids copying between the output and the- sliding window by simply making the window itself the output buffer. This- function trusts the application to not change the output buffer passed by- the output function, at least until inflateBack() returns.+ interface for input and output. This is potentially more efficient than+ inflate() for file i/o applications, in that it avoids copying between the+ output and the sliding window by simply making the window itself the output+ buffer. inflate() can be faster on modern CPUs when used with large+ buffers. inflateBack() trusts the application to not change the output+ buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer.@@ -1088,6 +1145,7 @@ 27-31: 0 (reserved) */ +#ifndef Z_SOLO /* utility functions */ @@ -1149,10 +1207,11 @@ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output- buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In+ the case where there is not enough room, uncompress() will fill the output+ buffer with the uncompressed data up to that point. */ - /* gzip file access functions */ /*@@ -1162,7 +1221,7 @@ wrapper, documented in RFC 1952, wrapped around a deflate stream. */ -typedef voidp gzFile; /* opaque gzip file descriptor */+typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));@@ -1172,13 +1231,28 @@ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of- deflateInit2 for more information about the strategy parameter.) Also "a"- can be used instead of "w" to request that the gzip stream that will be- written be appended to the file. "+" will result in an error, since reading- and writing to the same gzip file is not supported.+ deflateInit2 for more information about the strategy parameter.) 'T' will+ request transparent writing or appending with no compression and not using+ the gzip format. + "a" can be used instead of "w" to request that the gzip stream that will+ be written be appended to the file. "+" will result in an error, since+ reading and writing to the same gzip file is not supported. The addition of+ "x" when writing will create the file exclusively, which fails if the file+ already exists. On systems that support it, the addition of "e" when+ reading or writing will set the flag to close the file on an execve() call.++ These functions, as well as gzip, will read and decode a sequence of gzip+ streams in a file. The append function of gzopen() can be used to create+ such a file. (Also see gzflush() for another way to do this.) When+ appending, gzopen does not test whether the file begins with a gzip stream,+ nor does it look for the end of the gzip streams to begin appending. gzopen+ will simply append a gzip stream to the existing file.+ gzopen can be used to read a file which is not in gzip format; in this- case gzread will directly read from the file without decompression.+ case gzread will directly read from the file without decompression. When+ reading, this will be detected automatically by looking for the magic two-+ byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was@@ -1197,7 +1271,11 @@ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since- gzdopen does not close fd if it fails.+ gzdopen does not close fd if it fails. If you are using fileno() to get the+ file descriptor from a FILE *, then you will have to use dup() to avoid+ double-close()ing the file descriptor. Both gzclose() and fclose() will+ close the associated file descriptor, so they need to have different file+ descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not@@ -1235,15 +1313,27 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If- the input file was not in gzip format, gzread copies the given number of- bytes into the buffer.+ the input file is not in gzip format, gzread copies the given number of+ bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue- to read, looking for another gzip stream, or failing that, reading the rest- of the input file directly without decompression. The entire input file- will be read if gzread is called until it returns less than the requested- len.+ to read, looking for another gzip stream. Any number of gzip streams may be+ concatenated in the input file, and will all be decompressed by gzread().+ If something other than a gzip stream is encountered after a gzip stream,+ that remaining trailing garbage is ignored (and no error is returned). + gzread can be used to read a gzip file that is being concurrently written.+ Upon reaching the end of the input, gzread will return with the available+ data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then+ gzclearerr can be used to clear the end of file indicator in order to permit+ gzread to be tried again. Z_OK indicates that a gzip stream was completed+ on the last gzread. Z_BUF_ERROR indicates that the input file ended in the+ middle of a gzip stream. Note that gzread does not return -1 in the event+ of an incomplete gzip stream. This error is deferred until gzclose(), which+ will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip+ stream. Alternatively, gzerror can be used before gzclose to detect this+ case.+ gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. */@@ -1256,7 +1346,7 @@ error. */ -ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));+ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of@@ -1301,7 +1391,10 @@ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1- in case of end of file or error.+ in case of end of file or error. This is implemented as a macro for speed.+ As such, it does not do all of the checking the other functions do. I.e.+ it does not check to see if file is NULL, nor whether the structure file+ points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));@@ -1397,9 +1490,7 @@ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false- (0) if file is a gzip stream being decompressed. This state can change from- false to true while reading the input file if the end of a gzip stream is- reached, but is followed by data that is not another gzip stream.+ (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream.@@ -1408,6 +1499,13 @@ cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect().++ When writing, gzdirect() returns true (1) if transparent writing was+ requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note:+ gzdirect() is not needed when writing. Transparent writing must be+ explicitly requested, so the application already knows the answer. When+ linking statically, using gzdirect() will include all of the zlib code for+ gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file));@@ -1419,7 +1517,8 @@ must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a- file operation error, or Z_OK on success.+ file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the+ last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));@@ -1457,6 +1556,7 @@ file that is being written concurrently. */ +#endif /* !Z_SOLO */ /* checksum functions */ @@ -1492,16 +1592,17 @@ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of- seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note+ that the z_off_t type (like off_t) is a signed integer. If len2 is+ negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required- initial value for the for the crc. Pre- and post-conditioning (one's- complement) is performed within this function so it shouldn't be done by the- application.+ initial value for the crc. Pre- and post-conditioning (one's complement) is+ performed within this function so it shouldn't be done by the application. Usage example: @@ -1544,25 +1645,50 @@ const char *version, int stream_size)); #define deflateInit(strm, level) \- deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))+ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit(strm) \- inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))+ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) #define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\- (strategy), ZLIB_VERSION, sizeof(z_stream))+ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) #define inflateInit2(strm, windowBits) \- inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \+ (int)sizeof(z_stream)) #define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \- ZLIB_VERSION, sizeof(z_stream))+ ZLIB_VERSION, (int)sizeof(z_stream)) +#ifndef Z_SOLO++/* gzgetc() macro and its supporting function and exposed data structure. Note+ * that the real internal state is much larger than the exposed structure.+ * This abbreviated structure exposes just enough for the gzgetc() macro. The+ * user should not mess with these exposed elements, since their names or+ * behavior could change in the future, perhaps even capriciously. They can+ * only be used by the gzgetc() macro. You have been warned.+ */+struct gzFile_s {+ unsigned have;+ unsigned char *next;+ z_off64_t pos;+};+ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */+#ifdef Z_PREFIX_SET+# undef z_gzgetc+# define z_gzgetc(g) \+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))+#else+# define gzgetc(g) \+ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g))+#endif+ /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */-#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0+#ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));@@ -1571,14 +1697,23 @@ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif -#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0-# define gzopen gzopen64-# define gzseek gzseek64-# define gztell gztell64-# define gzoffset gzoffset64-# define adler32_combine adler32_combine64-# define crc32_combine crc32_combine64-# ifdef _LARGEFILE64_SOURCE+#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64)+# ifdef Z_PREFIX_SET+# define z_gzopen z_gzopen64+# define z_gzseek z_gzseek64+# define z_gztell z_gztell64+# define z_gzoffset z_gzoffset64+# define z_adler32_combine z_adler32_combine64+# define z_crc32_combine z_crc32_combine64+# else+# define gzopen gzopen64+# define gzseek gzseek64+# define gztell gztell64+# define gzoffset gzoffset64+# define adler32_combine adler32_combine64+# define crc32_combine crc32_combine64+# endif+# ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));@@ -1595,6 +1730,13 @@ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif +#else /* Z_SOLO */++ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));++#endif /* !Z_SOLO */+ /* hack for buggy compilers */ #if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) struct internal_state {int dummy;};@@ -1603,8 +1745,21 @@ /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));-ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));+ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));+ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp));+ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp));+#if defined(_WIN32) && !defined(Z_SOLO)+ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path,+ const char *mode));+#endif+#if defined(STDC) || defined(Z_HAVE_STDARG_H)+# ifndef Z_SOLO+ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file,+ const char *format,+ va_list va));+# endif+#endif #ifdef __cplusplus }
cbits/zutil.c view
@@ -1,17 +1,20 @@ /* zutil.c -- target dependent utility functions for the compression library- * Copyright (C) 1995-2005, 2010 Jean-loup Gailly.+ * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h"+#ifndef Z_SOLO+# include "gzguts.h"+#endif #ifndef NO_DUMMY_DECL struct internal_state {int dummy;}; /* for buggy compilers */ #endif -const char * const z_errmsg[10] = {+z_const char * const z_errmsg[10] = { "need dictionary", /* Z_NEED_DICT 2 */ "stream end", /* Z_STREAM_END 1 */ "", /* Z_OK 0 */@@ -85,27 +88,27 @@ #ifdef FASTEST flags += 1L << 21; #endif-#ifdef STDC+#if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf- flags += 1L << 25;+ flags += 1L << 25; # ifdef HAS_vsprintf_void- flags += 1L << 26;+ flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void- flags += 1L << 26;+ flags += 1L << 26; # endif # endif #else- flags += 1L << 24;+ flags += 1L << 24; # ifdef NO_snprintf- flags += 1L << 25;+ flags += 1L << 25; # ifdef HAS_sprintf_void- flags += 1L << 26;+ flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void- flags += 1L << 26;+ flags += 1L << 26; # endif # endif #endif@@ -181,6 +184,7 @@ } #endif +#ifndef Z_SOLO #ifdef SYS16BIT @@ -316,3 +320,5 @@ } #endif /* MY_ZCALLOC */++#endif /* !Z_SOLO */
cbits/zutil.h view
@@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library- * Copyright (C) 1995-2010 Jean-loup Gailly.+ * Copyright (C) 1995-2013 Jean-loup Gailly. * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -13,7 +13,7 @@ #ifndef ZUTIL_H #define ZUTIL_H -#if ((__GNUC__-0) * 10 + __GNUC_MINOR__-0 >= 33) && !defined(NO_VIZ)+#ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL@@ -21,7 +21,7 @@ #include "zlib.h" -#ifdef STDC+#if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include <stddef.h> # endif@@ -29,6 +29,10 @@ # include <stdlib.h> #endif +#ifdef Z_SOLO+ typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */+#endif+ #ifndef local # define local static #endif@@ -40,13 +44,13 @@ typedef ush FAR ushf; typedef unsigned long ulg; -extern 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++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \- return (strm->msg = (char*)ERR_MSG(err), (err))+ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */@@ -78,16 +82,18 @@ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00-# if defined(__TURBOC__) || defined(__BORLANDC__)-# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))- /* Allow compilation with ANSI keywords only enabled */- void _Cdecl farfree( void *block );- void *_Cdecl farmalloc( unsigned long nbytes );-# else-# include <alloc.h>+# ifndef Z_SOLO+# if defined(__TURBOC__) || defined(__BORLANDC__)+# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))+ /* Allow compilation with ANSI keywords only enabled */+ void _Cdecl farfree( void *block );+ void *_Cdecl farmalloc( unsigned long nbytes );+# else+# include <alloc.h>+# endif+# else /* MSC or DJGPP */+# include <malloc.h> # endif-# else /* MSC or DJGPP */-# include <malloc.h> # endif #endif @@ -107,18 +113,20 @@ #ifdef OS2 # define OS_CODE 0x06-# ifdef M_I86+# if defined(M_I86) && !defined(Z_SOLO) # include <malloc.h> # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 0x07-# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os-# include <unix.h> /* for fdopen */-# else-# ifndef fdopen-# define fdopen(fd,mode) NULL /* No fdopen() */+# ifndef Z_SOLO+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os+# include <unix.h> /* for fdopen */+# else+# ifndef fdopen+# define fdopen(fd,mode) NULL /* No fdopen() */+# endif # endif # endif #endif@@ -153,14 +161,15 @@ # endif #endif -#if defined(__BORLANDC__)+#if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */-#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0+#if !defined(_WIN32) && \+ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif@@ -177,42 +186,7 @@ /* functions */ -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)-# ifndef HAVE_VSNPRINTF-# define HAVE_VSNPRINTF-# endif-#endif-#if defined(__CYGWIN__)-# ifndef HAVE_VSNPRINTF-# define HAVE_VSNPRINTF-# endif-#endif-#ifndef HAVE_VSNPRINTF-# ifdef MSDOS- /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),- but for now we just assume it doesn't. */-# define NO_vsnprintf-# endif-# ifdef __TURBOC__-# define NO_vsnprintf-# endif-# ifdef WIN32- /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */-# if !defined(vsnprintf) && !defined(NO_vsnprintf)-# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 )-# define vsnprintf _vsnprintf-# endif-# endif-# endif-# ifdef __SASC-# define NO_vsnprintf-# endif-#endif-#ifdef VMS-# define NO_vsnprintf-#endif--#if defined(pyr)+#if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)@@ -261,14 +235,19 @@ # define Tracecv(c,x) #endif --voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,- unsigned size));-void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));+#ifndef Z_SOLO+ voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items,+ unsigned size));+ void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr));+#endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);}++/* Reverse the bytes in a 32-bit value */+#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */
+ test/Test.hs view
@@ -0,0 +1,246 @@+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++module Main where++import Codec.Compression.Zlib.Internal+import qualified Codec.Compression.Zlib as Zlib+import qualified Codec.Compression.GZip as GZip+import qualified Codec.Compression.Zlib.Raw as Raw++import Test.Codec.Compression.Zlib.Internal ()+import Test.Codec.Compression.Zlib.Stream ()++import Test.QuickCheck+import Test.HUnit+import Test.Tasty+import Test.Tasty.QuickCheck+import Test.Tasty.HUnit+import Utils ()++import Control.Monad+import Control.Exception+import qualified Data.ByteString.Char8 as BS.Char8+import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString as BS+import System.IO+import Prelude hiding (catch)+++main :: IO ()+main = defaultMain $+ testGroup "zlib tests" [+ testGroup "property tests" [+ testProperty "decompress . compress = id (standard)" prop_decompress_after_compress,+ testProperty "decompress . compress = id (Zlib -> GZipOrZLib)" prop_gziporzlib1,+ testProperty "decompress . compress = id (GZip -> GZipOrZlib)" prop_gziporzlib2,+ testProperty "prefixes of valid stream detected as truncated" prop_truncated+ ],+ testGroup "unit tests" [+ testCase "simple gzip case" test_simple_gzip,+ testCase "detect bad crc" test_bad_crc,+ testCase "detect non-gzip" test_non_gzip,+ testCase "detect custom dictionary" test_custom_dict,+ testCase "dectect inflate with wrong dict" test_wrong_dictionary,+ testCase "dectect inflate with right dict" test_right_dictionary,+ testCase "handle trailing data" test_trailing_data,+ testCase "check small input chunks" test_small_chunks,+ testCase "check exception raised" test_exception+ ]+ ]+++prop_decompress_after_compress :: Format+ -> CompressParams+ -> DecompressParams+ -> Property+prop_decompress_after_compress w cp dp =+ (w /= zlibFormat || decompressWindowBits dp >= compressWindowBits cp) &&+ -- Zlib decompression has been observed to fail with both compress and decompress+ -- window bits = 8. This seems to be contrary to the docs and to a quick reading+ -- of the zlib source code.+ (decompressWindowBits dp > compressWindowBits cp || decompressWindowBits dp > WindowBits 8) &&+ decompressBufferSize dp > 0 && compressBufferSize cp > 0 ==>+ liftM2 (==) (decompress w dp . compress w cp) id+++prop_gziporzlib1 :: CompressParams+ -> DecompressParams+ -> Property+prop_gziporzlib1 cp dp =+ decompressWindowBits dp > compressWindowBits cp &&+ decompressBufferSize dp > 0 && compressBufferSize cp > 0 ==>+ liftM2 (==) (decompress gzipOrZlibFormat dp . compress zlibFormat cp) id+++prop_gziporzlib2 :: CompressParams+ -> DecompressParams+ -> Property+prop_gziporzlib2 cp dp =+ decompressBufferSize dp > 0 && compressBufferSize cp > 0 ==>+ liftM2 (==) (decompress gzipOrZlibFormat dp . compress gzipFormat cp) id++prop_truncated :: Format -> Property+prop_truncated format =+ forAll shortStrings $ \bs ->+ all (truncated decomp)+ (init (BL.inits (comp bs)))+ -- All the initial prefixes of a valid compressed stream should be detected+ -- as truncated.+ where+ comp = compress format defaultCompressParams+ decomp = decompressST format defaultDecompressParams+ truncated = foldDecompressStreamWithInput (\_ r -> r) (\_ -> False)+ (\err -> case err of TruncatedInput -> True; _ -> False)++ shortStrings = sized $ \sz -> resize (sz `div` 6) arbitrary+++test_simple_gzip :: Assertion+test_simple_gzip =+ withSampleData "hello.gz" $ \hnd ->+ let decomp = decompressIO gzipFormat defaultDecompressParams+ in assertDecompressOk hnd decomp++test_bad_crc :: Assertion+test_bad_crc =+ withSampleData "bad-crc.gz" $ \hnd -> do+ let decomp = decompressIO gzipFormat defaultDecompressParams+ err <- assertDecompressError hnd decomp+ msg <- assertDataFormatError err+ msg @?= "incorrect data check"++test_non_gzip :: Assertion+test_non_gzip = do+ withSampleData "not-gzip" $ \hnd -> do+ let decomp = decompressIO gzipFormat defaultDecompressParams+ err <- assertDecompressError hnd decomp+ msg <- assertDataFormatError err+ msg @?= "incorrect header check"++ withSampleData "not-gzip" $ \hnd -> do+ let decomp = decompressIO zlibFormat defaultDecompressParams+ err <- assertDecompressError hnd decomp+ msg <- assertDataFormatError err+ msg @?= "incorrect header check"++ withSampleData "not-gzip" $ \hnd -> do+ let decomp = decompressIO rawFormat defaultDecompressParams+ err <- assertDecompressError hnd decomp+ msg <- assertDataFormatError err+ msg @?= "invalid code lengths set"++ withSampleData "not-gzip" $ \hnd -> do+ let decomp = decompressIO gzipOrZlibFormat defaultDecompressParams+ err <- assertDecompressError hnd decomp+ msg <- assertDataFormatError err+ msg @?= "incorrect header check"++test_custom_dict :: Assertion+test_custom_dict =+ withSampleData "custom-dict.zlib" $ \hnd -> do+ let decomp = decompressIO zlibFormat defaultDecompressParams+ err <- assertDecompressError hnd decomp+ err @?= DictionaryRequired++test_wrong_dictionary :: Assertion+test_wrong_dictionary = do+ withSampleData "custom-dict.zlib" $ \hnd -> do+ let decomp = decompressIO zlibFormat defaultDecompressParams {+ decompressDictionary = -- wrong dict!+ Just (BS.pack [65,66,67])+ }++ err <- assertDecompressError hnd decomp+ err @?= DictionaryMismatch++test_right_dictionary :: Assertion+test_right_dictionary = do+ withSampleData "custom-dict.zlib" $ \hnd -> do+ dict <- readSampleData "custom-dict.zlib-dict"+ let decomp = decompressIO zlibFormat defaultDecompressParams {+ decompressDictionary =+ Just (BL.toStrict dict)+ }+ assertDecompressOk hnd decomp++test_trailing_data :: Assertion+test_trailing_data =+ withSampleData "two-files.gzip" $ \hnd -> do+ let decomp = decompressIO gzipFormat defaultDecompressParams+ chunks <- assertDecompressOkChunks hnd decomp+ case chunks of+ [chunk] -> chunk @?= BS.Char8.pack "Test 1"+ _ -> assertFailure "expected single chunk"++test_small_chunks :: Assertion+test_small_chunks = do+ uncompressedFile <- readSampleData "not-gzip"+ GZip.compress (smallChunks uncompressedFile) @?= GZip.compress uncompressedFile+ Zlib.compress (smallChunks uncompressedFile) @?= Zlib.compress uncompressedFile+ Raw.compress (smallChunks uncompressedFile) @?= Raw.compress uncompressedFile++ GZip.decompress (smallChunks (GZip.compress uncompressedFile)) @?= uncompressedFile+ Zlib.decompress (smallChunks (Zlib.compress uncompressedFile)) @?= uncompressedFile+ Raw.decompress (smallChunks (Raw.compress uncompressedFile)) @?= uncompressedFile++ compressedFile <- readSampleData "hello.gz"+ (GZip.decompress . smallChunks) compressedFile @?= GZip.decompress compressedFile++ where+ smallChunks :: BL.ByteString -> BL.ByteString+ smallChunks = BL.fromChunks . map (\c -> BS.pack [c]) . BL.unpack++test_exception :: Assertion+test_exception =+ (do+ compressedFile <- readSampleData "bad-crc.gz"+ _ <- evaluate (BL.length (GZip.decompress compressedFile))+ assertFailure "expected exception")++ `catch` \err -> do+ msg <- assertDataFormatError err+ msg @?= "incorrect data check"+++--------------+-- HUnit Utils++readSampleData :: FilePath -> IO BL.ByteString+readSampleData file = BL.readFile ("test/data/" ++ file)++withSampleData :: FilePath -> (Handle -> IO a) -> IO a+withSampleData file = withFile ("test/data/" ++ file) ReadMode++expected :: String -> String -> IO a+expected e g = assertFailure ("expected: " ++ e ++ "\nbut got: " ++ g)+ >> fail ""++assertDecompressOk :: Handle -> DecompressStream IO -> Assertion+assertDecompressOk hnd =+ foldDecompressStream+ (BS.hGet hnd 4000 >>=)+ (\_ r -> r)+ (\_ -> return ())+ (\err -> expected "decompress ok" (show err))++assertDecompressOkChunks :: Handle -> DecompressStream IO -> IO [BS.ByteString]+assertDecompressOkChunks hnd =+ foldDecompressStream+ (BS.hGet hnd 4000 >>=)+ (\chunk -> liftM (chunk:))+ (\_ -> return [])+ (\err -> expected "decompress ok" (show err))++assertDecompressError :: Handle -> DecompressStream IO -> IO DecompressError+assertDecompressError hnd =+ foldDecompressStream+ (BS.hGet hnd 4000 >>=)+ (\_ r -> r)+ (\_ -> expected "StreamError" "StreamEnd")+ return++assertDataFormatError :: DecompressError -> IO String+assertDataFormatError (DataFormatError detail) = return detail+assertDataFormatError _ = assertFailure "expected DataError"+ >> return ""
+ test/Test/Codec/Compression/Zlib/Internal.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- | Test code and properties for "Codec.Compression.Zlib.Internal"+--+module Test.Codec.Compression.Zlib.Internal where++import Codec.Compression.Zlib.Internal+import Test.Codec.Compression.Zlib.Stream ()+import Test.QuickCheck++import Control.Monad (ap, msum)+++deriving instance Show CompressParams++instance Arbitrary CompressParams where+ arbitrary = return CompressParams `ap` arbitrary `ap` arbitrary+ `ap` arbitrary `ap` arbitrary+ `ap` arbitrary `ap` arbitraryBufferSize+ `ap` return Nothing++ -- this definition (and the equivalent in DecompressParams below) could be+ -- made nicer using Data.Accessor, but it's probably not worth the+ -- dependency+ shrink cp = msum [+ return (\lv -> cp { compressLevel = lv }) `ap`+ shrink (compressLevel cp),+ return (\mt -> cp { compressMethod = mt }) `ap`+ shrink (compressMethod cp),+ return (\wb -> cp { compressWindowBits = wb }) `ap`+ shrink (compressWindowBits cp),+ return (\ml -> cp { compressMemoryLevel = ml }) `ap`+ shrink (compressMemoryLevel cp),+ return (\st -> cp { compressStrategy = st }) `ap`+ shrink (compressStrategy cp),+ return (\bs -> cp { compressBufferSize = bs }) `ap`+ shrink (compressBufferSize cp)+ ]++arbitraryBufferSize :: Gen Int+arbitraryBufferSize = frequency $ [(10, return n) | n <- [1..1024]] +++ [(20, return n) | n <- [1025..8192]] +++ [(40, return n) | n <- [8193..131072]] +++ [(1, return n) | n <- [131072..1048576]]+++deriving instance Show DecompressParams++instance Arbitrary DecompressParams where+ arbitrary = return DecompressParams `ap` arbitrary `ap` arbitraryBufferSize `ap` return Nothing+ shrink dp = msum [+ return (\wb -> dp { decompressWindowBits = wb }) `ap`+ shrink (decompressWindowBits dp),+ return (\bs -> dp { decompressBufferSize = bs }) `ap`+ shrink (decompressBufferSize dp)+ ]
+ test/Test/Codec/Compression/Zlib/Stream.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE StandaloneDeriving #-}+{-# OPTIONS_GHC -fno-warn-orphans #-}++-- | Test code and properties for "Codec.Compression.Zlib.Stream"+--+module Test.Codec.Compression.Zlib.Stream where++import Codec.Compression.Zlib.Internal+import Test.QuickCheck+++deriving instance Show Format+instance Arbitrary Format where+ -- GZipOrZlib omitted since it's not symmetric+ arbitrary = elements [gzipFormat, zlibFormat, rawFormat]+++deriving instance Show Method+instance Arbitrary Method where+ arbitrary = return deflateMethod+++deriving instance Show CompressionLevel+instance Arbitrary CompressionLevel where+ arbitrary = elements $ [defaultCompression, noCompression,+ bestCompression, bestSpeed]+ ++ map compressionLevel [1..9]+++deriving instance Eq WindowBits+deriving instance Ord WindowBits+deriving instance Show WindowBits+instance Arbitrary WindowBits where+ arbitrary = elements $ defaultWindowBits:map windowBits [8..15]+ shrink DefaultWindowBits = []+ shrink (WindowBits n) = defaultWindowBits:map windowBits [n+1..15]+++deriving instance Show MemoryLevel+instance Arbitrary MemoryLevel where+ arbitrary = elements $ [defaultMemoryLevel, minMemoryLevel, maxMemoryLevel]+ ++ [memoryLevel n | n <- [1..9]]++++deriving instance Show CompressionStrategy+instance Arbitrary CompressionStrategy where+ arbitrary = elements $ [defaultStrategy, filteredStrategy, huffmanOnlyStrategy]+ -- These are disabled by default in the package+ -- as they are only available with zlib >=1.2+ -- ++ [RLE, Fixed]
+ test/Utils.hs view
@@ -0,0 +1,28 @@+{-# OPTIONS_GHC -fno-warn-orphans #-}+module Utils where++import qualified Data.ByteString.Lazy as BL+import qualified Data.ByteString as BS++import Test.QuickCheck++-------------------+-- QuickCheck Utils++maxStrSize :: Double+maxStrSize = 5000++-- convert a QC size parameter into one for generating long lists,+-- growing inverse exponentially up to maxStrSize+strSize :: Int -> Int+strSize n = floor (maxStrSize * (1 - 2 ** (-fromIntegral n/100)))++instance Arbitrary BL.ByteString where+ arbitrary = sized $ \sz -> fmap BL.fromChunks $ listOf $ resize (sz `div` 2) arbitrary+ shrink = map BL.pack . shrink . BL.unpack++instance Arbitrary BS.ByteString where+ arbitrary = sized $ \sz -> resize (strSize sz) $ fmap BS.pack $ listOf $ arbitrary+ shrink = map BS.pack . shrink . BS.unpack++
zlib.cabal view
@@ -1,6 +1,6 @@ name: zlib-version: 0.5.4.2-copyright: (c) 2006-2012 Duncan Coutts+version: 0.6.0.0+copyright: (c) 2006-2014 Duncan Coutts license: BSD3 license-file: LICENSE author: Duncan Coutts <duncan@community.haskell.org>@@ -17,7 +17,7 @@ tasks and for the few cases where more control is needed it provides access to the full zlib feature set. build-type: Simple-cabal-version: >= 1.8+cabal-version: >= 1.10 extra-source-files: cbits/crc32.h cbits/inffast.h cbits/inflate.h cbits/trees.h cbits/deflate.h cbits/inffixed.h cbits/inftrees.h cbits/zutil.h@@ -34,20 +34,41 @@ Codec.Compression.Zlib.Raw, Codec.Compression.Zlib.Internal other-modules: Codec.Compression.Zlib.Stream- extensions: CPP, ForeignFunctionInterface+ if impl(ghc < 7)+ default-language: Haskell98+ else+ default-language: Haskell2010+ other-extensions: CPP, ForeignFunctionInterface, RankNTypes, BangPatterns,+ DeriveDataTypeable, DeriveGeneric build-depends: base >= 3 && < 5, bytestring >= 0.9 && < 0.12 includes: zlib.h- ghc-options: -Wall+ ghc-options: -Wall -fwarn-tabs if !os(windows) -- Normally we use the the standard system zlib: extra-libraries: z else -- However for the benefit of users of Windows (which does not have zlib- -- by default) we bundle a complete copy of the C sources of zlib-1.2.5+ -- by default) we bundle a complete copy of the C sources of zlib-1.2.8 c-sources: cbits/adler32.c cbits/compress.c cbits/crc32.c cbits/deflate.c cbits/infback.c cbits/inffast.c cbits/inflate.c cbits/inftrees.c cbits/trees.c cbits/uncompr.c cbits/zutil.c include-dirs: cbits install-includes: zlib.h zconf.h++test-suite tests+ type: exitcode-stdio-1.0+ main-is: Test.hs+ other-modules: Utils,+ Test.Codec.Compression.Zlib.Internal,+ Test.Codec.Compression.Zlib.Stream+ hs-source-dirs: test+ default-language: Haskell2010+ build-depends: base, bytestring, zlib,+ QuickCheck == 2.*,+ HUnit == 1.2.*,+ tasty == 0.8.*,+ tasty-quickcheck == 0.8.*,+ tasty-hunit == 0.8.*+ ghc-options: -Wall