Skip to content

Commit 900196f

Browse files
committed
add zlib header (RFC1950) support.
1 parent 8b97613 commit 900196f

File tree

5 files changed

+120
-7
lines changed

5 files changed

+120
-7
lines changed

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2011-02-22
2+
Added zlib header support (RFC1950)
3+
4+
2008
5+
Initial version

MANIFEST

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
COPYRIGHT
22
MANIFEST
3+
CHANGES.txt
34
compress.deflatelua-0.1.0-1.rockspec
45
dist.info
56
util.mk
67
bin/gunziplua
78
module/lmod/bin/gunziplua.lua
89
module/lmod/compress/deflatelua.lua
910
share/compress.deflatelua/hello.txt.gz
11+
test/test.lua

README.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
=== Description ===
22

3-
compress.deflatelua is Lua module implementing DEFLATE [1] and
4-
gzip/zlib decompression in pure Lua.
3+
compress.deflatelua is Lua module implementing DEFLATE [5,1], as well as
4+
zlib [4] and gzip [6] decompression in pure Lua.
55

66
=== Example / Performance ===
77

@@ -63,3 +63,6 @@ David Manura. See COPYRIGHT file.
6363
[1] http://en.wikipedia.org/wiki/DEFLATE
6464
[2] http://search.cpan.org/~nwclark/Compress-Zlib-Perl/Perl.pm
6565
[3] http://search.cpan.org/~fays/Digest-Crc32/Crc32.pm
66+
[4] http://tools.ietf.org/html/rfc1950
67+
[5] http://tools.ietf.org/html/rfc1951
68+
[6] http://tools.ietf.org/html/rfc1952

module/lmod/compress/deflatelua.lua

Lines changed: 83 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ local function get_obytestream(o)
257257
elseif type(o) == 'function' then
258258
bs = o
259259
else
260-
error('unrecognized type: ' .. tostring(o))
260+
runtime_error('unrecognized type: ' .. tostring(o))
261261
end
262262
return bs
263263
end
@@ -428,6 +428,35 @@ local function parse_gzip_header(bs)
428428
end
429429
end
430430

431+
local function parse_zlib_header(bs)
432+
local cm = bs:read(4) -- Compression Method
433+
local cinfo = bs:read(4) -- Compression info
434+
local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG)
435+
local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary)
436+
local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level)
437+
local cmf = cinfo * 16 + cm -- CMF (Compresion Method and flags)
438+
local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs
439+
440+
if cm ~= 8 then -- not "deflate"
441+
runtime_error("unrecognized zlib compression method: " + cm)
442+
end
443+
local window_size
444+
if cinfo > 7 then
445+
runtime_error("invalid zlib window size: cinfo=" + cinfo)
446+
end
447+
local window_size = 2^(cinfo + 8)
448+
449+
if (cmf*256 + flg) % 31 ~= 0 then
450+
runtime_error("invalid zlib header (bad fcheck sum)")
451+
end
452+
453+
if fdict == 1 then
454+
runtime_error("FIX:TODO - FDICT not currently implemented")
455+
local dictid = bs:read(32)
456+
end
457+
458+
return window_size
459+
end
431460

432461
local function parse_huffmantables(bs)
433462
local hlit = bs:read(5) -- # of literal/length codes - 257
@@ -622,7 +651,7 @@ local function deflate(t)
622651
end
623652
M.deflate = deflate
624653

625-
654+
-- http://tools.ietf.org/html/rfc1952
626655
local function gunzip(t)
627656
local bs = get_bitstream(t.input)
628657
local outbs = get_obytestream(t.output)
@@ -643,14 +672,14 @@ local function gunzip(t)
643672

644673
bs:read(bs:nbits_left_in_byte())
645674

646-
local crc32 = bs:read(32)
675+
local expected_crc32 = bs:read(32)
647676
local isize = bs:read(32) -- ignored
648677
if DEBUG then
649-
debug('crc32=', crc32)
678+
debug('crc32=', expected_crc32)
650679
debug('isize=', isize)
651680
end
652681
if not disable_crc and data_crc32 then
653-
if data_crc32 ~= crc32 then
682+
if data_crc32 ~= expected_crc32 then
654683
runtime_error('invalid compressed data--crc error')
655684
end
656685
end
@@ -660,6 +689,55 @@ local function gunzip(t)
660689
end
661690
M.gunzip = gunzip
662691

692+
-- adler32 checksum
693+
-- see ADLER32 in http://tools.ietf.org/html/rfc1950 .
694+
local function adler32(byte, crc)
695+
local s1 = crc % 65536
696+
local s2 = (crc - s1) / 65536
697+
s1 = (s1 + byte) % 65521
698+
s2 = (s2 + s1) % 65521
699+
return s2*65536 + s1
700+
end -- 65521 is the largest prime smaller than 2^16
701+
702+
-- http://tools.ietf.org/html/rfc1950
703+
local function inflate_zlib(t)
704+
local bs = get_bitstream(t.input)
705+
local outbs = get_obytestream(t.output)
706+
local disable_crc = t.disable_crc
707+
if disable_crc == nil then disable_crc = false end
708+
709+
local window_size = parse_zlib_header(bs)
710+
711+
local data_adler32 = 1
712+
713+
deflate{input=bs, output=
714+
disable_crc and outbs or
715+
function(byte)
716+
data_adler32 = adler32(byte, data_adler32)
717+
outbs(byte)
718+
end
719+
}
720+
721+
bs:read(bs:nbits_left_in_byte())
722+
723+
local b3 = bs:read(8)
724+
local b2 = bs:read(8)
725+
local b1 = bs:read(8)
726+
local b0 = bs:read(8)
727+
local expected_adler32 = ((b3*256 + b2)*256 + b1)*256 + b0
728+
if DEBUG then
729+
debug('alder32=', expected_adler32)
730+
end
731+
if not disable_crc then
732+
if data_adler32 ~= expected_adler32 then
733+
runtime_error('invalid compressed data--crc error')
734+
end
735+
end
736+
if bs:read() then
737+
warn 'trailing garbage ignored'
738+
end
739+
end
740+
M.inflate_zlib = inflate_zlib
663741

664742
return M
665743

test/test.lua

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-- tests of lua-compress-deflatelua
2+
3+
package.path = '../../lua-digest-crc32lua/module/lmod/?.lua;' .. package.path
4+
package.path = '../../lua-pythonic-optparse/module/lmod/?.lua;' .. package.path
5+
package.path = '../../lua-bit-numberlua/module/lmod/?.lua;' .. package.path
6+
package.path = '../../lua-compress-deflatelua/module/lmod/?.lua;' .. package.path
7+
8+
deflate = require("compress.deflatelua")
9+
10+
local output = {}
11+
deflate.inflate_zlib {
12+
input = "\120\156\203\072\205\201\201\087\040\207\047\202\073\001\000\026\011\004\093",
13+
output = function(byte) output[#output+1] = string.char(byte) end
14+
}
15+
assert(table.concat(output) == "hello world")
16+
17+
local output = {}
18+
deflate.gunzip {
19+
input = "\031\139\008\000\217\124\100\077\000\003\203\072\205\201\201\087\040\207\047\202\073\001\000\133\017\074\013\011\000\000\000",
20+
output = function(byte) output[#output+1] = string.char(byte) end
21+
}
22+
assert(table.concat(output) == "hello world")
23+
24+
print 'DONE'
25+

0 commit comments

Comments
 (0)