Advertisement
MoonlightOwl

deflatelua

Jan 27th, 2015
650
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 16.51 KB | None | 0 0
  1. --[[
  2.  
  3. LUA MODULE
  4.  
  5.     deflatelua - inflate (and gunzip/zlib) implemented in Lua.
  6.    
  7. DESCRIPTION
  8.    
  9.     This is a pure Lua implementation of decompressing the DEFLATE format,
  10.     including the related zlib and gzip formats.
  11.    
  12.     Note: This library only supports decompression.
  13.     Compression is not currently implemented.
  14.  
  15. REFERENCES
  16.  
  17.     [1] DEFLATE Compressed Data Format Specification version 1.3
  18.             http://tools.ietf.org/html/rfc1951
  19.     [2] GZIP file format specification version 4.3
  20.             http://tools.ietf.org/html/rfc1952
  21.     [3] http://en.wikipedia.org/wiki/DEFLATE
  22.     [4] pyflate, by Paul Sladen
  23.             http://www.paul.sladen.org/projects/pyflate/
  24.     [5] Compress::Zlib::Perl - partial pure Perl implementation of
  25.             Compress::Zlib
  26.             http://search.cpan.org/~nwclark/Compress-Zlib-Perl/Perl.pm
  27.  
  28. LICENSE
  29.  
  30.     (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT).
  31.  
  32.     Permission is hereby granted, free of charge, to any person obtaining a copy
  33.     of this software and associated documentation files (the "Software"), to deal
  34.     in the Software without restriction, including without limitation the rights
  35.     to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  36.     copies of the Software, and to permit persons to whom the Software is
  37.     furnished to do so, subject to the following conditions:
  38.  
  39.     The above copyright notice and this permission notice shall be included in
  40.     all copies or substantial portions of the Software.
  41.  
  42.     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  43.     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  44.     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   IN NO EVENT SHALL THE
  45.     AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  46.     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  47.     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  48.     THE SOFTWARE.
  49.     (end license)
  50.    
  51.    
  52.    
  53.     Modified by TehSomeLuigi under the above license.
  54.    
  55. --]]
  56.  
  57. local M = {_TYPE='module', _NAME='deflatelua', _VERSION='0.3.20111128'}
  58.  
  59. local assert = assert
  60. local error = error
  61. local ipairs = ipairs
  62. local pairs = pairs
  63. local print = print
  64. local require = require
  65. local tostring = tostring
  66. local type = type
  67. local setmetatable = setmetatable
  68. local io = io
  69. local math = math
  70. local table_sort = table.sort
  71. local math_max = math.max
  72. local string_char = string.char
  73.  
  74. local DEBUG = false
  75.  
  76.  
  77. local band, lshift, rshift
  78. band = bit32.band
  79. lshift = bit32.lshift
  80. rshift = bit32.rshift
  81.  
  82.  
  83. local function warn(s)
  84.     io.stderr:write(s, '\n')
  85. end
  86.  
  87.  
  88. local function debug(...)
  89.     print('DEBUG', ...)
  90. end
  91.  
  92.  
  93. local function runtime_error(s, level)
  94.     level = level or 1
  95.     error(s, level+1)
  96. end
  97.  
  98. local function make_outstate(outbs)
  99.     local outstate = {}
  100.     outstate.outbs = outbs
  101.     outstate.window = {}
  102.     outstate.window_pos = 1
  103.     return outstate
  104. end
  105.  
  106. local function output(outstate, byte)
  107.     -- debug('OUTPUT:', s)
  108.     local window_pos = outstate.window_pos
  109.     outstate.outbs(byte)
  110.     outstate.window[window_pos] = byte
  111.     outstate.window_pos = window_pos % 32768 + 1    -- 32K
  112. end
  113.  
  114. local function noeof(val, ctx)
  115.     return assert(val, 'unexpected end of file with context ' .. tostring(ctx))
  116. end
  117.  
  118. local function hasbit(bits, bit)
  119.     return bits % (bit + bit) >= bit
  120. end
  121.  
  122. local function memoize(f)
  123.     local mt = {}
  124.     local t = setmetatable({}, mt)
  125.     function mt:__index(k)
  126.         local v = f(k)
  127.         t[k] = v
  128.         return v
  129.     end
  130.     return t
  131. end
  132.  
  133. -- small optimization (lookup table for powers of 2)
  134. local pow2 = memoize(function(n) return 2^n end)
  135.  
  136. --local tbits = memoize(
  137. --  function(bits)
  138. --      return memoize( function(bit) return getbit(bits, bit) end )
  139. --  end )
  140.  
  141.  
  142. -- weak metatable marking objects as bitstream type
  143. local is_bitstream = setmetatable({}, {__mode='k'})
  144.  
  145. local function bytestream_from_file(fh)
  146.     local o = {}
  147.     function o:read()
  148.         local sb = fh:read(1)
  149.         if sb then return sb:byte() end
  150.     end
  151.     return o
  152. end
  153.  
  154. local function bytestream_from_string(s)
  155.     local i = 1
  156.     local o = {s=s}
  157.     function o:read()
  158.         local by
  159.         if i <= #self.s then
  160.             by = self.s:byte(i)
  161.             i = i + 1
  162.         end
  163.         return by
  164.     end
  165.     return o
  166. end
  167.  
  168. M.stringToBytestream = bytestream_from_string
  169.  
  170. local function bytestream_from_function(f)
  171.     local i = 0
  172.     local buffer = ''
  173.     local o = {}
  174.     function o:read()
  175.         i = i + 1
  176.         if i > #buffer then
  177.             buffer = f()
  178.             if not buffer then return end
  179.             i = 1
  180.         end
  181.         return buffer:byte(i,i)
  182.     end
  183.     return o
  184. end
  185.  
  186. local function bitstream_from_bytestream(bys)
  187.     local buf_byte = 0
  188.     local buf_nbit = 0
  189.     local o = {}
  190.  
  191.     function o:nbits_left_in_byte()
  192.         return buf_nbit
  193.     end
  194.  
  195.     function o:read(nbits)
  196.         nbits = nbits or 1
  197.         while buf_nbit < nbits do
  198.             local byte = bys:read()
  199.             if not byte then return end -- note: more calls also return nil
  200.             buf_byte = buf_byte + lshift(byte, buf_nbit)
  201.             buf_nbit = buf_nbit + 8
  202.         end
  203.         local bits
  204.         if nbits == 0 then
  205.             bits = 0
  206.         elseif nbits == 32 then
  207.             bits = buf_byte
  208.             buf_byte = 0
  209.         else
  210.             bits = band(buf_byte, rshift(0xffffffff, 32 - nbits))
  211.             buf_byte = rshift(buf_byte, nbits)
  212.         end
  213.        
  214.         if nbits == 16 then
  215.             -- bugfix: swap bytes
  216.             bits = rshift(band(bits, 0xFF00), 8) + lshift(band(bits, 0xFF), 8)
  217.         end
  218.        
  219.         buf_nbit = buf_nbit - nbits
  220.         return bits
  221.     end
  222.    
  223.     is_bitstream[o] = true
  224.  
  225.     return o
  226. end
  227.  
  228.  
  229. function M.adler32(byte, crc)
  230.     local s1 = crc % 65536
  231.     local s2 = (crc - s1) / 65536
  232.     s1 = (s1 + byte) % 65521
  233.     s2 = (s2 + s1) % 65521
  234.     return s2*65536 + s1
  235. end
  236.  
  237. local function get_bitstream(o)
  238.     local bs
  239.     if is_bitstream[o] then
  240.         return o
  241.     elseif io.type(o) == 'file' then
  242.         bs = bitstream_from_bytestream(bytestream_from_file(o))
  243.     elseif type(o) == 'string' then
  244.         bs = bitstream_from_bytestream(bytestream_from_string(o))
  245.     elseif type(o) == 'function' then
  246.         bs = bitstream_from_bytestream(bytestream_from_function(o))
  247.     else
  248.         runtime_error 'unrecognized type'
  249.     end
  250.     return bs
  251. end
  252.  
  253.  
  254. local function get_obytestream(o)
  255.     local bs
  256.     if io.type(o) == 'file' then
  257.         bs = function(sbyte) o:write(string_char(sbyte)) end
  258.     elseif type(o) == 'function' then
  259.         bs = o
  260.     elseif type(o) == 'table' then
  261.         -- assume __callable table
  262.         bs = o
  263.     else
  264.         runtime_error('unrecognized type: ' .. tostring(o))
  265.     end
  266.     return bs
  267. end
  268.  
  269.  
  270. local function HuffmanTable(init, is_full)
  271.     local t = {}
  272.     if is_full then
  273.         for val,nbits in pairs(init) do
  274.             if nbits ~= 0 then
  275.                 t[#t+1] = {val=val, nbits=nbits}
  276.                 --debug('*',val,nbits)
  277.             end
  278.         end
  279.     else
  280.         for i=1,#init-2,2 do
  281.             local firstval, nbits, nextval = init[i], init[i+1], init[i+2]
  282.             --debug(val, nextval, nbits)
  283.             if nbits ~= 0 then
  284.                 for val=firstval,nextval-1 do
  285.                     t[#t+1] = {val=val, nbits=nbits}
  286.                 end
  287.             end
  288.         end
  289.     end
  290.     table_sort(t, function(a,b)
  291.         return a.nbits == b.nbits and a.val < b.val or a.nbits < b.nbits
  292.     end)
  293.  
  294.     -- assign codes
  295.     local code = 1  -- leading 1 marker
  296.     local nbits = 0
  297.     for i,s in ipairs(t) do
  298.         if s.nbits ~= nbits then
  299.             code = code * pow2[s.nbits - nbits]
  300.             nbits = s.nbits
  301.         end
  302.         s.code = code
  303.         --debug('huffman code:', i, s.nbits, s.val, code, bits_tostring(code))
  304.         code = code + 1
  305.     end
  306.  
  307.     local minbits = math.huge
  308.     local look = {}
  309.     for i,s in ipairs(t) do
  310.         minbits = math.min(minbits, s.nbits)
  311.         look[s.code] = s.val
  312.     end
  313.  
  314.     --for _,o in ipairs(t) do
  315.     --  debug(':', o.nbits, o.val)
  316.     --end
  317.  
  318.     -- function t:lookup(bits) return look[bits] end
  319.  
  320.     local msb = function(bits, nbits)
  321.         local res = 0
  322.         for i=1,nbits do
  323.             res = lshift(res, 1) + band(bits, 1)
  324.             bits = rshift(bits, 1)
  325.         end
  326.         return res
  327.     end
  328.    
  329.     local tfirstcode = memoize(function(bits)
  330.         return pow2[minbits] + msb(bits, minbits)
  331.     end)
  332.  
  333.     function t:read(bs)
  334.         local code = 1 -- leading 1 marker
  335.         local nbits = 0
  336.         while 1 do
  337.             if nbits == 0 then  -- small optimization (optional)
  338.                 code = tfirstcode[noeof(bs:read(minbits), 1)]
  339.                 nbits = nbits + minbits
  340.             else
  341.                 local b = noeof(bs:read(), 2)
  342.                 nbits = nbits + 1
  343.                 code = lshift(code, 1) + b   -- MSB first
  344.             end
  345.             --debug('code?', code, bits_tostring(code))
  346.             local val = look[code]
  347.             if val then
  348.                 --debug('FOUND', val)
  349.                 return val
  350.             end
  351.         end
  352.     end
  353.  
  354.     return t
  355. end
  356.  
  357.  
  358. local function parse_gzip_header(bs)
  359.     -- local FLG_FTEXT = 2^0
  360.     local FLG_FHCRC = 2^1
  361.     local FLG_FEXTRA = 2^2
  362.     local FLG_FNAME = 2^3
  363.     local FLG_FCOMMENT = 2^4
  364.  
  365.     local id1 = bs:read(8)
  366.     local id2 = bs:read(8)
  367.     if id1 ~= 31 or id2 ~= 139 then
  368.         runtime_error 'not in gzip format'
  369.     end
  370.     local cm = bs:read(8)   -- compression method
  371.     local flg = bs:read(8) -- FLaGs
  372.     local mtime = bs:read(32) -- Modification TIME
  373.     local xfl = bs:read(8) -- eXtra FLags
  374.     local os = bs:read(8) -- Operating System
  375.  
  376.     if DEBUG then
  377.         debug("CM=", cm)
  378.         debug("FLG=", flg)
  379.         debug("MTIME=", mtime)
  380.         -- debug("MTIME_str=",os.date("%Y-%m-%d %H:%M:%S",mtime)) -- non-portable
  381.         debug("XFL=", xfl)
  382.         debug("OS=", os)
  383.     end
  384.  
  385.     if not os then runtime_error 'invalid header' end
  386.  
  387.     if hasbit(flg, FLG_FEXTRA) then
  388.         local xlen = bs:read(16)
  389.         local extra = 0
  390.         for i=1,xlen do
  391.             extra = bs:read(8)
  392.         end
  393.         if not extra then runtime_error 'invalid header' end
  394.     end
  395.  
  396.     local function parse_zstring(bs)
  397.         repeat
  398.             local by = bs:read(8)
  399.             if not by then runtime_error 'invalid header' end
  400.         until by == 0
  401.     end
  402.  
  403.     if hasbit(flg, FLG_FNAME) then
  404.         parse_zstring(bs)
  405.     end
  406.  
  407.     if hasbit(flg, FLG_FCOMMENT) then
  408.         parse_zstring(bs)
  409.     end
  410.  
  411.     if hasbit(flg, FLG_FHCRC) then
  412.         local crc16 = bs:read(16)
  413.         if not crc16 then runtime_error 'invalid header' end
  414.         -- IMPROVE: check CRC.  where is an example .gz file that
  415.         -- has this set?
  416.         if DEBUG then
  417.             debug("CRC16=", crc16)
  418.         end
  419.     end
  420. end
  421.  
  422. local function parse_zlib_header(bs)
  423.     local cm = bs:read(4) -- Compression Method
  424.     local cinfo = bs:read(4) -- Compression info
  425.     local fcheck = bs:read(5) -- FLaGs: FCHECK (check bits for CMF and FLG)
  426.     local fdict = bs:read(1) -- FLaGs: FDICT (present dictionary)
  427.     local flevel = bs:read(2) -- FLaGs: FLEVEL (compression level)
  428.     local cmf = cinfo * 16  + cm -- CMF (Compresion Method and flags)
  429.     local flg = fcheck + fdict * 32 + flevel * 64 -- FLaGs
  430.    
  431.     if cm ~= 8 then -- not "deflate"
  432.         runtime_error("unrecognized zlib compression method: " + cm)
  433.     end
  434.     if cinfo > 7 then
  435.         runtime_error("invalid zlib window size: cinfo=" + cinfo)
  436.     end
  437.     local window_size = 2^(cinfo + 8)
  438.    
  439.     if (cmf*256 + flg) % 31 ~= 0 then
  440.         runtime_error("invalid zlib header (bad fcheck sum) - overflow by " .. ((cmf*256 + flg) % 31))
  441.     end
  442.    
  443.     if fdict == 1 then
  444.         runtime_error("FIX:TODO - FDICT not currently implemented")
  445.         local dictid_ = bs:read(32)
  446.     end
  447.    
  448.     return window_size
  449. end
  450.  
  451. local function parse_huffmantables(bs)
  452.         local hlit = bs:read(5) -- # of literal/length codes - 257
  453.         local hdist = bs:read(5) -- # of distance codes - 1
  454.         local hclen = noeof(bs:read(4), 3) -- # of code length codes - 4
  455.  
  456.         local ncodelen_codes = hclen + 4
  457.         local codelen_init = {}
  458.         local codelen_vals = {
  459.             16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
  460.         for i=1,ncodelen_codes do
  461.             local nbits = bs:read(3)
  462.             local val = codelen_vals[i]
  463.             codelen_init[val] = nbits
  464.         end
  465.         local codelentable = HuffmanTable(codelen_init, true)
  466.  
  467.         local function decode(ncodes)
  468.             local init = {}
  469.             local nbits
  470.             local val = 0
  471.             while val < ncodes do
  472.                 local codelen = codelentable:read(bs)
  473.                 --FIX:check nil?
  474.                 local nrepeat
  475.                 if codelen <= 15 then
  476.                     nrepeat = 1
  477.                     nbits = codelen
  478.                     --debug('w', nbits)
  479.                 elseif codelen == 16 then
  480.                     nrepeat = 3 + noeof(bs:read(2), 4)
  481.                     -- nbits unchanged
  482.                 elseif codelen == 17 then
  483.                     nrepeat = 3 + noeof(bs:read(3), 5)
  484.                     nbits = 0
  485.                 elseif codelen == 18 then
  486.                     nrepeat = 11 + noeof(bs:read(7), 6)
  487.                     nbits = 0
  488.                 else
  489.                     error 'ASSERT'
  490.                 end
  491.                 for i=1,nrepeat do
  492.                     init[val] = nbits
  493.                     val = val + 1
  494.                 end
  495.             end
  496.             local huffmantable = HuffmanTable(init, true)
  497.             return huffmantable
  498.         end
  499.  
  500.         local nlit_codes = hlit + 257
  501.         local ndist_codes = hdist + 1
  502.  
  503.         local littable = decode(nlit_codes)
  504.         local disttable = decode(ndist_codes)
  505.  
  506.         return littable, disttable
  507. end
  508.  
  509.  
  510. local tdecode_len_base
  511. local tdecode_len_nextrabits
  512. local tdecode_dist_base
  513. local tdecode_dist_nextrabits
  514. local function parse_compressed_item(bs, outstate, littable, disttable)
  515.     local val = littable:read(bs)
  516.     --debug(val, val < 256 and string_char(val))
  517.     if val < 256 then -- literal
  518.         output(outstate, val)
  519.     elseif val == 256 then -- end of block
  520.         return true
  521.     else
  522.         if not tdecode_len_base then
  523.             local t = {[257]=3}
  524.             local skip = 1
  525.             for i=258,285,4 do
  526.                 for j=i,i+3 do t[j] = t[j-1] + skip end
  527.                 if i ~= 258 then skip = skip * 2 end
  528.             end
  529.             t[285] = 258
  530.             tdecode_len_base = t
  531.             --for i=257,285 do debug('T1',i,t[i]) end
  532.         end
  533.         if not tdecode_len_nextrabits then
  534.             local t = {}
  535.             for i=257,285 do
  536.                 local j = math_max(i - 261, 0)
  537.                 t[i] = rshift(j, 2)
  538.             end
  539.             t[285] = 0
  540.             tdecode_len_nextrabits = t
  541.             --for i=257,285 do debug('T2',i,t[i]) end
  542.         end
  543.         local len_base = tdecode_len_base[val]
  544.         local nextrabits = tdecode_len_nextrabits[val]
  545.         local extrabits = bs:read(nextrabits)
  546.         local len = len_base + extrabits
  547.  
  548.         if not tdecode_dist_base then
  549.             local t = {[0]=1}
  550.             local skip = 1
  551.             for i=1,29,2 do
  552.                 for j=i,i+1 do t[j] = t[j-1] + skip end
  553.                 if i ~= 1 then skip = skip * 2 end
  554.             end
  555.             tdecode_dist_base = t
  556.             --for i=0,29 do debug('T3',i,t[i]) end
  557.         end
  558.         if not tdecode_dist_nextrabits then
  559.             local t = {}
  560.             for i=0,29 do
  561.                 local j = math_max(i - 2, 0)
  562.                 t[i] = rshift(j, 1)
  563.             end
  564.             tdecode_dist_nextrabits = t
  565.             --for i=0,29 do debug('T4',i,t[i]) end
  566.         end
  567.         local dist_val = disttable:read(bs)
  568.         local dist_base = tdecode_dist_base[dist_val]
  569.         local dist_nextrabits = tdecode_dist_nextrabits[dist_val]
  570.         local dist_extrabits = bs:read(dist_nextrabits)
  571.         local dist = dist_base + dist_extrabits
  572.  
  573.         --debug('BACK', len, dist)
  574.         for i=1,len do
  575.             local pos = (outstate.window_pos - 1 - dist) % 32768 + 1    -- 32K
  576.             output(outstate, assert(outstate.window[pos], 'invalid distance'))
  577.         end
  578.     end
  579.     return false
  580. end
  581.  
  582.  
  583. local function parse_block(bs, outstate)
  584.     local bfinal = bs:read(1)
  585.     local btype = bs:read(2)
  586.  
  587.     local BTYPE_NO_COMPRESSION = 0
  588.     local BTYPE_FIXED_HUFFMAN = 1
  589.     local BTYPE_DYNAMIC_HUFFMAN = 2
  590.     local BTYPE_RESERVED_ = 3
  591.  
  592.     if DEBUG then
  593.         debug('bfinal=', bfinal)
  594.         debug('btype=', btype)
  595.     end
  596.  
  597.     if btype == BTYPE_NO_COMPRESSION then
  598.         bs:read(bs:nbits_left_in_byte())
  599.         local len = bs:read(16)
  600.         local nlen_ = noeof(bs:read(16), 7)
  601.  
  602.         for i=1,len do
  603.             local by = noeof(bs:read(8), 8)
  604.             output(outstate, by)
  605.         end
  606.     elseif btype == BTYPE_FIXED_HUFFMAN or btype == BTYPE_DYNAMIC_HUFFMAN then
  607.         local littable, disttable
  608.         if btype == BTYPE_DYNAMIC_HUFFMAN then
  609.             littable, disttable = parse_huffmantables(bs)
  610.         else
  611.             littable    = HuffmanTable {0,8, 144,9, 256,7, 280,8, 288,nil}
  612.             disttable = HuffmanTable {0,5, 32,nil}
  613.         end
  614.  
  615.         repeat
  616.             local is_done = parse_compressed_item(
  617.                 bs, outstate, littable, disttable)
  618.         until is_done
  619.     else
  620.         runtime_error 'unrecognized compression type'
  621.     end
  622.  
  623.     return bfinal ~= 0
  624. end
  625.  
  626.  
  627. function M.inflate(t)
  628.     local bs = get_bitstream(t.input)
  629.     local outbs = get_obytestream(t.output)
  630.     local outstate = make_outstate(outbs)
  631.  
  632.     repeat
  633.         local is_final = parse_block(bs, outstate)
  634.     until is_final
  635. end
  636. local inflate = M.inflate
  637.  
  638.  
  639. function M.gunzip(t)
  640.     local bs = get_bitstream(t.input)
  641.     local outbs = get_obytestream(t.output)
  642.  
  643.     parse_gzip_header(bs)
  644.  
  645.     local data_crc32 = 0
  646.  
  647.     inflate{input=bs, output=outbs}
  648.  
  649.     bs:read(bs:nbits_left_in_byte())
  650.  
  651.     local expected_crc32 = bs:read(32)
  652.     local isize = bs:read(32) -- ignored
  653.     --[[
  654.     if DEBUG then
  655.         debug('crc32=', expected_crc32)
  656.         debug('isize=', isize)
  657.     end
  658.     ]]--
  659.     if bs:read() then
  660.         warn 'trailing garbage ignored'
  661.     end
  662. end
  663.  
  664.  
  665. function M.inflate_zlib(t)
  666.     local bs = get_bitstream(t.input)
  667.     local outbs = get_obytestream(t.output)
  668.    
  669.     local window_size_ = parse_zlib_header(bs)
  670.    
  671.     local data_adler32 = 1
  672.    
  673.     inflate{input=bs, output=outbs}
  674.  
  675.     bs:read(bs:nbits_left_in_byte())
  676.    
  677.    
  678.     local b3 = bs:read(8)
  679.     local b2 = bs:read(8)
  680.     local b1 = bs:read(8)
  681.     local b0 = bs:read(8)
  682.     --[[
  683.     local expected_adler32 = ((b3*256 + b2)*256 + b1)*256 + b0
  684.     if DEBUG then
  685.         debug('alder32=', expected_adler32)
  686.     end
  687.     if not disable_crc then
  688.         if data_adler32 ~= expected_adler32 then
  689.             runtime_error('invalid compressed data--crc error')
  690.         end    
  691.     end
  692.     ]]--
  693.     if bs:read() then
  694.         warn 'trailing garbage ignored'
  695.     end
  696. end
  697.  
  698.  
  699. return M
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement