Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Flushing (#2)

  • Loading branch information...
commit 3a4bc720c5bd694baf4a346a3369d62335e46c7c 1 parent 52eb4de
Michael Snoyman authored
25  Codec/Zlib.hs
@@ -25,12 +25,14 @@ module Codec.Zlib
25 25
     , initInflateWithDictionary
26 26
     , withInflateInput
27 27
     , finishInflate
  28
+    , flushInflate
28 29
       -- * Deflate
29 30
     , Deflate
30 31
     , initDeflate
31 32
     , initDeflateWithDictionary
32 33
     , withDeflateInput
33 34
     , finishDeflate
  35
+    , flushDeflate
34 36
       -- * Data types
35 37
     , WindowBits (WindowBits)
36 38
     , defaultWindowBits
@@ -214,7 +216,19 @@ finishInflate (Inflate ((fzstr, fbuff), _)) =
214 216
         withForeignPtr fbuff $ \buff -> do
215 217
             avail <- c_get_avail_out zstr
216 218
             let size = defaultChunkSize - fromIntegral avail
217  
-            S.packCStringLen (buff, size)
  219
+            bs <- S.packCStringLen (buff, size)
  220
+            c_set_avail_out zstr buff
  221
+                $ fromIntegral defaultChunkSize
  222
+            return bs
  223
+
  224
+-- | Flush the inflation buffer. Useful for interactive application.
  225
+--
  226
+-- This is actually a synonym for 'finishInflate'. It is provided for its more
  227
+-- semantic name.
  228
+--
  229
+-- Since 0.0.3
  230
+flushInflate :: Inflate -> IO S.ByteString
  231
+flushInflate = finishInflate
218 232
 
219 233
 -- | Feed the given 'S.ByteString' to the deflater. This function takes a
220 234
 -- function argument which takes a \"popper\". A popper is an IO action that
@@ -244,3 +258,12 @@ finishDeflate (Deflate (fzstr, fbuff)) f =
244 258
     withForeignPtr fzstr $ \zstr ->
245 259
         f $ drain fbuff zstr c_call_deflate_finish True
246 260
 
  261
+-- | Flush the deflation buffer. Useful for interactive application.
  262
+--
  263
+-- Internally this passes Z_SYNC_FLUSH to the zlib library.
  264
+--
  265
+-- Since 0.0.3
  266
+flushDeflate :: Deflate -> (IO (Maybe S.ByteString) -> IO a) -> IO a
  267
+flushDeflate (Deflate (fzstr, fbuff)) f =
  268
+    withForeignPtr fzstr $ \zstr ->
  269
+        f $ drain fbuff zstr c_call_deflate_flush True
4  Codec/Zlib/Lowlevel.hs
@@ -16,6 +16,7 @@ module Codec.Zlib.Lowlevel
16 16
     , c_call_inflate_noflush
17 17
     , c_call_deflate_noflush
18 18
     , c_call_deflate_finish
  19
+    , c_call_deflate_flush
19 20
     , c_call_deflate_set_dictionary
20 21
     , c_call_inflate_set_dictionary
21 22
     ) where
@@ -81,6 +82,9 @@ foreign import ccall unsafe "call_deflate_noflush"
81 82
 foreign import ccall unsafe "call_deflate_finish"
82 83
     c_call_deflate_finish :: ZStream' -> IO CInt
83 84
 
  85
+foreign import ccall unsafe "call_deflate_flush"
  86
+    c_call_deflate_flush :: ZStream' -> IO CInt
  87
+
84 88
 foreign import ccall unsafe "deflate_set_dictionary"
85 89
     c_call_deflate_set_dictionary :: ZStream' -> Ptr CChar -> CUInt -> IO ()
86 90
 
5  c/helper.c
@@ -81,6 +81,11 @@ int call_deflate_noflush (z_stream *stream)
81 81
 	return deflate(stream, Z_NO_FLUSH);
82 82
 }
83 83
 
  84
+int call_deflate_flush (z_stream *stream)
  85
+{
  86
+	return deflate(stream, Z_SYNC_FLUSH);
  87
+}
  88
+
84 89
 int call_deflate_finish (z_stream *stream)
85 90
 {
86 91
 	return deflate(stream, Z_FINISH);
33  test/main.hs
@@ -13,7 +13,7 @@ import qualified Codec.Compression.GZip as Gzip
13 13
 import qualified Data.ByteString as S
14 14
 import qualified Data.ByteString.Char8 as S8
15 15
 import qualified Data.ByteString.Lazy as L
16  
-import Control.Monad (foldM)
  16
+import Control.Monad (foldM, forM_, forM)
17 17
 import System.IO.Unsafe (unsafePerformIO)
18 18
 
19 19
 decompress' :: L.ByteString -> L.ByteString
@@ -174,3 +174,34 @@ main = hspecX $ do
174 174
             deflated <- foldM (go' def) id $ L.toChunks lbs
175 175
             deflated' <- finishDeflate def $ go deflated
176 176
             return $ lbs == decompress (L.fromChunks (deflated' []))
  177
+
  178
+    describe "flushing" $ do
  179
+        let helper wb = do
  180
+                let bss0 = replicate 5000 "abc"
  181
+                def <- initDeflate 9 wb
  182
+                inf <- initInflate wb
  183
+
  184
+                let popList pop = do
  185
+                        mx <- pop
  186
+                        case mx of
  187
+                            Nothing -> return []
  188
+                            Just x -> do
  189
+                                xs <- popList pop
  190
+                                return $ x : xs
  191
+
  192
+                let callback name expected pop = do
  193
+                        bssDeflated <- popList pop
  194
+                        bsInflated <- fmap (S.concat . concat) $ forM bssDeflated $ \bs -> do
  195
+                            x <- withInflateInput inf bs popList
  196
+                            y <- flushInflate inf
  197
+                            return $ x ++ [y]
  198
+                        if bsInflated == expected
  199
+                            then return ()
  200
+                            else error $ "callback " ++ name ++ ", got: " ++ show bsInflated ++ ", expected: " ++ show expected
  201
+
  202
+                forM_ (zip [1..] bss0) $ \(i, bs) -> do
  203
+                    withDeflateInput def bs $ callback ("loop" ++ show (i :: Int)) ""
  204
+                    flushDeflate def $ callback ("loop" ++ show (i :: Int)) bs
  205
+                finishDeflate def $ callback "finish" ""
  206
+        it "zlib" $ helper defaultWindowBits
  207
+        it "gzip" $ helper $ WindowBits 31
2  zlib-bindings.cabal
... ...
@@ -1,5 +1,5 @@
1 1
 name:            zlib-bindings
2  
-version:         0.0.2
  2
+version:         0.0.3
3 3
 license:         BSD3
4 4
 license-file:    LICENSE
5 5
 author:          Michael Snoyman <michael@snoyman.com>

0 notes on commit 3a4bc72

Please sign in to comment.
Something went wrong with that request. Please try again.