Skip to content

Commit

Permalink
Separate inflate and deflate functions
Browse files Browse the repository at this point in the history
  • Loading branch information
hamishforbes committed Feb 9, 2017
1 parent ba354f4 commit b715e24
Showing 1 changed file with 75 additions and 21 deletions.
96 changes: 75 additions & 21 deletions lib/ffi-zlib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,13 @@ _M.zlib = zlib
-- Default to 16k output buffer
local DEFAULT_CHUNK = 16384

local Z_OK = zlib.Z_OK
local Z_NO_FLUSH = zlib.Z_NO_FLUSH
local Z_STREAM_END = zlib.Z_STREAM_END
local Z_FINISH = zlib.Z_FINISH
local Z_NEED_DICT = zlib.Z_NEED_DICT
local Z_BUF_ERROR = zlib.Z_BUF_ERROR
local Z_OK = zlib.Z_OK
local Z_NO_FLUSH = zlib.Z_NO_FLUSH
local Z_STREAM_END = zlib.Z_STREAM_END
local Z_FINISH = zlib.Z_FINISH
local Z_NEED_DICT = zlib.Z_NEED_DICT
local Z_BUF_ERROR = zlib.Z_BUF_ERROR
local Z_STREAM_ERROR = zlib.Z_STREAM_ERROR

local function zlib_err(err)
return ffi_str(zlib.zError(err))
Expand Down Expand Up @@ -161,8 +162,61 @@ local function flushOutput(stream, bufsize, output, outbuf)
output(ffi_str(outbuf, out_sz))
end

local function flate(zlib_flate, zlib_flateEnd, input, output, bufsize, stream, inbuf, outbuf)
-- Inflate or Deflate a stream
local function inflate(input, output, bufsize, stream, inbuf, outbuf)
local zlib_flate = zlib.inflate
local zlib_flateEnd = zlib.inflateEnd
-- Inflate a stream
local err = 0
repeat
-- Read some input
local data = input(bufsize)
if data ~= nil then
ffi_copy(inbuf, data)
stream.next_in, stream.avail_in = inbuf, #data
else
-- no more input data
stream.avail_in = 0
end

if stream.avail_in == 0 then
-- When decompressing we *must* have input bytes
zlib_flateEnd(stream)
return false, "INFLATE: Data error, no input bytes"
end

-- While the output buffer is being filled completely just keep going
repeat
stream.next_out = outbuf
stream.avail_out = bufsize
-- Process the stream, always Z_NO_FLUSH in inflate mode
err = zlib_flate(stream, Z_NO_FLUSH)

-- Buffer errors are OK here
if err == Z_BUF_ERROR then
err = Z_OK
end
if err < Z_OK or err == Z_NEED_DICT then
-- Error, clean up and return
zlib_flateEnd(stream)
return false, "INFLATE: "..zlib_err(err), stream
end
-- Write the data out
flushOutput(stream, bufsize, output, outbuf)
until stream.avail_out ~= 0

until err == Z_STREAM_END

-- Stream finished, clean up and return
zlib_flateEnd(stream)
return true, zlib_err(err)
end
_M.inflate = inflate

local function deflate(input, output, bufsize, stream, inbuf, outbuf)
local zlib_flate = zlib.deflate
local zlib_flateEnd = zlib.deflateEnd

-- Deflate a stream
local err = 0
local mode = Z_NO_FLUSH
repeat
Expand All @@ -181,31 +235,33 @@ local function flate(zlib_flate, zlib_flateEnd, input, output, bufsize, stream,
repeat
stream.next_out = outbuf
stream.avail_out = bufsize

-- Process the stream
err = zlib_flate(stream, mode)

-- From the zlib docs:
-- Note that a Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be made with more input or output space.
if err == Z_BUF_ERROR then
err = Z_OK
end

if err < Z_OK or err == Z_NEED_DICT then
-- Only possible *bad* return value here
if err == Z_STREAM_ERR then
-- Error, clean up and return
zlib_flateEnd(stream)
return false, "FLATE: "..zlib_err(err), stream
return false, "DEFLATE: "..zlib_err(err), stream
end
-- Write the data out
flushOutput(stream, bufsize, output, outbuf)
until stream.avail_out ~= 0

-- In deflate mode all input must be used by this point
if stream.avail_in ~= 0 then
zlib_flateEnd(stream)
return false, "DEFLATE: Input not used"
end

until err == Z_STREAM_END

-- Stream finished, clean up and return
zlib_flateEnd(stream)
return true, zlib_err(err)
end
_M.flate = flate
_M.deflate = deflate

local function adler(str, chksum)
local chksum = chksum or 0
Expand All @@ -230,8 +286,7 @@ function _M.inflateGzip(input, output, bufsize, windowBits)

local init = initInflate(stream, windowBits)
if init == Z_OK then
local ok, err = flate(zlib.inflate, zlib.inflateEnd, input, output, bufsize, stream, inbuf, outbuf)
return ok,err
return inflate(input, output, bufsize, stream, inbuf, outbuf)
else
-- Init error
zlib.inflateEnd(stream)
Expand All @@ -249,8 +304,7 @@ function _M.deflateGzip(input, output, bufsize, options)

local init = initDeflate(stream, options)
if init == Z_OK then
local ok, err = flate(zlib.deflate, zlib.deflateEnd, input, output, bufsize, stream, inbuf, outbuf)
return ok,err
return deflate(input, output, bufsize, stream, inbuf, outbuf)
else
-- Init error
zlib.deflateEnd(stream)
Expand Down

4 comments on commit b715e24

@sjnam
Copy link
Contributor

@sjnam sjnam commented on b715e24 Feb 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello,

When the second argument, chunk size is 1, the test file test.lua does not work.
% luajit test.lua sample.gz 1

But C file, zpipe.c with chunk size 1 has no error.

#define CHUNK 1 /16384/
% gcc -o zpipe zpipe.c -lz
% ./zpipe < sample > sample.gz
% ./zpipe -d < sample.gz > sample

@sjnam
Copy link
Contributor

@sjnam sjnam commented on b715e24 Feb 9, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I did pull request for the first time, the test with chunk size is 1 was OK.

@hamishforbes
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, I think thats actually an issue with the way test.lua is calling string.sub rather than an issue with the implementation.

The example code from the README works for me with bufsize set to 1

@hamishforbes
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed! aaa6284

Please sign in to comment.