1-
1+ #! /usr/bin/env lua
22
33local function newbitstream (data )
44 local pos , bitbuf , bitcnt = 1 , 0 , 0
55 local function needbits (n )
66 while bitcnt < n do
7- local b = data :byte (pos ) or 0
7+ bitbuf = bitbuf + (( data :byte (pos ) or 0 ) << bitcnt )
88 pos = pos + 1
9- bitbuf = bitbuf + (b << bitcnt )
109 bitcnt = bitcnt + 8
1110 end
1211 end
1312 local function readbits (n )
1413 needbits (n )
1514 local v = bitbuf & ((1 << n ) - 1 )
16- bitbuf = (bitbuf >> n )
17- bitcnt = bitcnt - n
15+ bitbuf , bitcnt = (bitbuf >> n ), bitcnt - n
1816 return v
1917 end
2018 local function alignbyte () bitbuf , bitcnt = 0 , 0 end
21- local function getpos () return pos end
2219 local function skip (n ) pos = pos + n end
23- return { readbits = readbits , align = alignbyte , pos = getpos , skip = skip }
20+ return { readbits = readbits , align = alignbyte , pos = pos , skip = skip }
2421end
2522
2623local function revbits (x , bits )
@@ -33,48 +30,57 @@ local function revbits(x, bits)
3330end
3431
3532local function make_huff (lengths )
36- local maxlen , counts = 0 , {}
33+
34+ -- m = maximum length
35+ -- c = counts
36+ -- o = code
37+ -- n = next code
38+ -- t = tab
39+ local m , c , o , n , t = 0 , {}, 0 , {}, {}
40+
3741 for _ , len in ipairs (lengths ) do
3842 if len > 0 then
39- counts [len ] = (counts [len ] or 0 ) + 1
40- if len > maxlen then maxlen = len end
43+ c [len ] = (c [len ] or 0 ) + 1
44+ if len > m then m = len end
4145 end
4246 end
4347
44- local code = 0
45- local next_code = {}
46- for bits = 1 , maxlen do
47- code = (code + (counts [bits - 1 ] or 0 )) << 1
48- next_code [bits ] = code
48+ -- b = bits
49+ for b = 1 , m do
50+ o = (o + (c [b - 1 ] or 0 )) << 1
51+ n [b ] = o
4952 end
5053
51- local tab = {}
52- for sym , len in ipairs (lengths ) do
53- if len > 0 then
54- local c = revbits (next_code [len ], len )
55- tab [c ] = { sym = sym - 1 , len = len }
56- next_code [len ] = next_code [len ] + 1
54+ -- s = sym
55+ -- l = len
56+ for s , l in ipairs (lengths ) do
57+ if l > 0 then
58+ local r = revbits (n [l ], l )
59+ t [r ] = { sym = s - 1 , len = l }
60+ n [l ] = n [l ] + 1
5761 end
5862 end
5963
60- return { tab = tab , max = maxlen }
64+ return { tab = t , max = m }
6165end
6266
6367local function read_huff (bs , h )
64- local code = 0
65- for len = 1 , h .max do
66- code = code | (bs .readbits (1 ) << (len - 1 ))
67- local masked = code & ((1 << len ) - 1 )
68- local e = h .tab [masked ]
69- if e and e .len == len then return e .sym end
68+
69+ -- c = code
70+ local c = 0
71+
72+ -- l = len
73+ for l = 1 , h .max do
74+ c = c | (bs .readbits (1 ) << (l - 1 ))
75+ local e = h .tab [c & ((1 << l ) - 1 )]
76+ if e and e .len == l then return e .sym end
7077 end
78+
7179 error (" invalid Huffman code" )
7280end
7381
7482local function inflate (data )
75- local bs = newbitstream (data )
76- local out = {} -- out[i] = single-character string for byte i (1-based)
77- local outpos = 0
83+ local bs , out , outpos = newbitstream (data ), {}, 0
7884 local function append_byte (byte )
7985 outpos = outpos + 1
8086 out [outpos ] = string.char (byte )
@@ -152,15 +158,14 @@ local function inflate(data)
152158 dist = make_huff (dl )
153159 end
154160
155- local len_extra = {
161+ local len_extra , dist_extra = {
156162 [257 ]= {3 ,0 },[258 ]= {4 ,0 },[259 ]= {5 ,0 },[260 ]= {6 ,0 },[261 ]= {7 ,0 },
157163 [262 ]= {8 ,0 },[263 ]= {9 ,0 },[264 ]= {10 ,0 },[265 ]= {11 ,1 },[266 ]= {13 ,1 },
158164 [267 ]= {15 ,1 },[268 ]= {17 ,1 },[269 ]= {19 ,2 },[270 ]= {23 ,2 },[271 ]= {27 ,2 },
159165 [272 ]= {31 ,2 },[273 ]= {35 ,3 },[274 ]= {43 ,3 },[275 ]= {51 ,3 },[276 ]= {59 ,3 },
160166 [277 ]= {67 ,4 },[278 ]= {83 ,4 },[279 ]= {99 ,4 },[280 ]= {115 ,4 },[281 ]= {131 ,5 },
161167 [282 ]= {163 ,5 },[283 ]= {195 ,5 },[284 ]= {227 ,5 },[285 ]= {258 ,0 }
162- }
163- local dist_extra = {
168+ },{
164169 {1 ,0 },{2 ,0 },{3 ,0 },{4 ,0 },{5 ,1 },{7 ,1 },{9 ,2 },{13 ,2 },{17 ,3 },{25 ,3 },
165170 {33 ,4 },{49 ,4 },{65 ,5 },{97 ,5 },{129 ,6 },{193 ,6 },{257 ,7 },{385 ,7 },{513 ,8 },
166171 {769 ,8 },{1025 ,9 },{1537 ,9 },{2049 ,10 },{3073 ,10 },{4097 ,11 },{6145 ,11 },
@@ -177,8 +182,7 @@ local function inflate(data)
177182 local entry = len_extra [sym ]
178183 local base , extra = entry [1 ], entry [2 ]
179184 local add = extra > 0 and bs .readbits (extra ) or 0
180- local length = base + add
181- local dsym = read_huff (bs , dist )
185+ local length , dsym = base + add , read_huff (bs , dist )
182186 local dentry = dist_extra [dsym + 1 ]
183187 local dbase , dextra = dentry [1 ], dentry [2 ]
184188 local dadd = dextra > 0 and bs .readbits (dextra ) or 0
@@ -219,60 +223,65 @@ end
219223local function le16 (s , i ) local a ,b = s :byte (i ,i + 1 ); return a + b * 256 end
220224local function le32 (s , i )
221225 local a ,b ,c ,d = s :byte (i , i + 3 )
222- return a + b * 256 + c * 65536 + d * 16777216
226+ return a + b * 256 + c * 65536 + d * 16777216
223227end
224228
225229local function unzip (path )
226230 local f = assert (io.open (path , " rb" ))
227- local data = f :read (" *a" ); f :close ()
228- local pos = 1
231+ local data , pos = f :read (" *a" ), 1 f :close ()
229232 while true do
230233 if data :sub (pos , pos + 3 ) ~= " PK\3\4 " then break end
231- local _ = le16 (data , pos + 4 )
232- local _ = le16 (data , pos + 6 )
233- local cm = le16 (data , pos + 8 )
234- local crc_expected = le32 (data , pos + 14 )
235- local comp_size = le32 (data , pos + 18 )
236- local uncomp_size = le32 (data , pos + 22 )
237- local name_len = le16 (data , pos + 26 )
238- local extra_len = le16 (data , pos + 28 )
239- local filename = data :sub (pos + 30 , pos + 29 + name_len )
240- local start = pos + 30 + name_len + extra_len
241- local compdata = data :sub (start , start + comp_size - 1 )
242-
243- local outstr
234+ -- _ = version needed
235+ -- _ = flags
236+ -- cm = cm
237+ -- cr = Expected crc32 checksum
238+ -- cs = Compressed size
239+ -- us = Uncompressed size
240+ -- nl = Length of file name
241+ -- el = Extra length in the file name
242+
243+ local _ , _ , cm , cr , cs , us , nl , el = le16 (data , pos + 4 ), le16 (data , pos + 6 ), le16 (data , pos + 8 ), le32 (data , pos + 14 ), le32 (data , pos + 18 ), le32 (data , pos + 22 ), le16 (data , pos + 26 ), le16 (data , pos + 28 )
244+
245+ -- fn = The filename
246+ -- st = The file Start offset
247+ local fn , st = data :sub (pos + 30 , pos + 29 + nl ), pos + 30 + nl + el
248+
249+ -- cd = A buffer of the files data
250+ -- os = The output stream
251+ local cd , os = data :sub (st , st + cs - 1 )
252+
244253 if cm == 0 then
245- outstr = compdata
254+ os = cd
246255 elseif cm == 8 then
247- outstr = inflate (compdata )
256+ os = inflate (cd )
248257 else
249258 io.stderr :write (" Unsupported compression method: " .. tostring (cm ).. " \n " )
250259 end
251260
252- if outstr then
253- if # outstr ~= uncomp_size then
254- io.stderr :write (string.format (" Warning: uncompressed size mismatch for %s: expected %d, got %d\n " , filename , uncomp_size , # outstr ))
261+ if os then
262+ if # os ~= us then
263+ io.stderr :write (string.format (" Warning: uncompressed size mismatch for %s: expected %d, got %d\n " , fn , us , # os ))
255264 end
256- local gotcrc = crc32 (outstr )
257- if crc_expected ~= gotcrc then
258- io.stderr :write (string.format (" CRC mismatch for %s: expected %08x, got %08x\n " , filename , crc_expected , gotcrc ))
265+ local gotcrc = crc32 (os )
266+ if cr ~= gotcrc then
267+ io.stderr :write (string.format (" CRC mismatch for %s: expected %08x, got %08x\n " , fn , cr , gotcrc ))
259268 else
260269 print (string.format (" CRC OK: %08x" , gotcrc ))
261270 end
262271
263- local dir = filename :match (" (.+)/" )
272+ local dir = fn :match (" (.+)/" )
264273 if dir then
265274 if os.execute then
266275 -- portable make dir (POSIX/Windows-friendly-ish)
267276 os.execute (' mkdir -p "' .. dir .. ' "' )
268277 end
269278 end
270- local of = assert (io.open (filename , " wb" ))
271- of :write (outstr )
279+ local of = assert (io.open (fn , " wb" ))
280+ of :write (os )
272281 of :close ()
273282 end
274283
275- pos = start + comp_size
284+ pos = st + cs
276285 end
277286end
278287
0 commit comments