Skip to content

Instantly share code, notes, and snippets.

@NathanHowell
Created July 20, 2011 22:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NathanHowell/1096039 to your computer and use it in GitHub Desktop.
Save NathanHowell/1096039 to your computer and use it in GitHub Desktop.
Length prefixed gzipped streams
import Data.Binary.Get
import qualified Data.ByteString as B
import qualified Data.Enumerator as E
import qualified Data.Enumerator.Binary as EB
import qualified Codec.Zlib.Enum as Z
unzipStream :: E.Iteratee B.ByteString IO b
-> E.Iteratee B.ByteString IO b
unzipStream sink = do
-- read four bytes off the wire into a bytestring
header <- EB.take 4
-- convert the 4 byte bytestring to a 32 bit little endian integer
-- then convert it again to an Integer (required for isolate)
let streamLength = fromIntegral $ runGet getWord32le header
-- create an Enumerator that is exactly 'streamLength' bytes long
-- feed it into zlib's decompressor
-- and stream the decompressed results into 'sink', an Iteratee
val <- E.joinI (EB.isolate streamLength E.$$ E.joinI (Z.decompress Z.defaultWindowBits E.$$ sink))
isDone <- E.isEOF
if isDone
-- if we're at the end of the input stream, return the last value.
-- you could also build these up during the recursion or simply ignore
-- the return value (if any) by returning ()
then return val
-- otherwise recurse, reading the next gzipped entry out of the stream
else unzipStream sink
main :: IO () -- process ./source.file.bin
main = E.run_ $ EB.enumFile "source.file.bin"
-- and print the decompressed stream to stdout
E.$$ unzipStream (E.printChunks False)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment