Skip to content

Commit 28b2db4

Browse files
committed
Read only what is required from file in the unzip function.
1 parent 9419b64 commit 28b2db4

File tree

1 file changed

+73
-26
lines changed

1 file changed

+73
-26
lines changed

util/UNZIP.LUA

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ local function nbs(data)
3131
-- s = skip
3232
local function s(n) p = p + n end
3333

34-
return { r = rb, a = ab, p = p, s = s }
34+
-- TODO: inflate() currently expects bs.p() callable, change that
35+
local function gp() return p end
36+
37+
return { r = rb, a = ab, p = gp, s = s }
3538
end
3639

3740
-- rv = revbits
@@ -261,46 +264,90 @@ local function crc32(s)
261264
return c ~ x
262265
end
263266

264-
local function le16(s, i) local a,b = s:byte(i,i+1) return a + b*256 end
265-
local function le32(s, i) local a,b,c,d = s:byte(i, i+3) return a + b * 256 + c * 65536 + d * 16777216 end
266-
267267
local function unzip(path)
268268

269+
-- C = read chunk size
269270
-- f = file
270-
-- d = data (or error string string if file can't be opened)
271-
-- p = position
272-
local f, d, p = io.open(path, "rb")
273-
if d then print(d) os.exit(1) end
274-
d, p = f:read("*a"), 1 f:close()
271+
local C, f = 4096
272+
273+
f, E = io.open(path, "rb")
274+
if E then print(E) os.exit(1) end
275+
276+
-- R = read bytes
277+
local function R(n)
278+
local s, E = f:read(n)
279+
if E then print(E) os.exit(1) end
280+
return s
281+
end
282+
283+
local function S(n) f:seek("cur", n) end
284+
285+
local function le16() local a, b = R(2):byte(1, 2) return a + b * 256 end
286+
local function le32() local a, b, c, d = R(4):byte(1, 4) return a + b * 256 + c * 65536 + d * 16777216 end
287+
288+
-- RB = read n bytes chunked
289+
local function RB(n)
290+
291+
-- p = parts
292+
-- g = got
293+
-- w = want
294+
-- d = data
295+
local p, g, w, d = {}, 0
296+
297+
while g < n do
298+
w = math.min(C, n - g)
299+
d, E = R(w)
300+
if E then return nil, E end
301+
p[#p + 1] = d
302+
g = g + #d
303+
end
304+
305+
return table.concat(p)
306+
end
275307

276308
while true do
277-
if d:sub(p, p +3) ~= "PK\3\4" then break end
278309

279-
-- _ = version needed
280-
-- _ = flags
281-
-- cm = cm
310+
-- s = signature
311+
-- v = version needed
312+
-- fl = flags
313+
-- cm = method
282314
-- cr = Expected crc32 checksum
283315
-- cs = Compressed size
284316
-- us = Uncompressed size
285317
-- nl = Length of file name
286318
-- el = Extra length in the file name
287-
local _, _, cm, cr, cs, us, nl, el = le16(d, p +4), le16(d, p +6), le16(d, p +8), le32(d, p +14), le32(d, p +18), le32(d, p +22), le16(d, p +26), le16(d, p +28)
288-
289-
-- fn = The filename
290-
-- st = The file Start offset
291-
local fn, st = d:sub(p +30, p +29 + nl), p + 30 + nl + el
292-
293319
-- cd = A buffer of the files data
294320
-- os = The output stream
295-
local cd, os = d:sub(st, st + cs - 1)
321+
local s, v, fl, cm, ok, cr, cs, us, nl, el, fn, cd, os = f:read(4)
322+
if not s or #s < 4 then break end
323+
if s ~= "PK\3\4" then break end
324+
325+
v, E = le16() if not v then break end -- version
326+
fl, E = le16() if not fl then break end -- flags
327+
cm, E = le16() if not cm then break end -- method
328+
S(4) -- modification time and date
329+
cr, E = le32() if not cr then break end -- crc32
330+
cs, E = le32() if not cs then break end -- compressed size
331+
us, E = le32() if not us then break end -- uncompressed size
332+
nl, E = le16() if not nl then break end -- name length
333+
el, E = le16() if not el then break end -- extra name length
334+
335+
fn, E = R(nl) if not fn then break end -- filename
336+
if el > 0 then S(el) end
296337

297338
print("Extracting: " .. fn)
298339

340+
cd, E = RB(cs)
341+
if not cd then
342+
print(e)
343+
break
344+
end
345+
299346
if cm == 0 then
300347
-- no compression
301348
os = cd
302349
elseif cm == 8 then
303-
-- deflate
350+
-- deflate (still in-memory per entry)
304351
os = inflate(cd)
305352
else
306353
-- unsupported compression
@@ -325,16 +372,16 @@ local function unzip(path)
325372
end
326373
end
327374

328-
of, di = io.open(fn, "wb")
329-
if di then
330-
print(di)
375+
of, E = io.open(fn, "wb")
376+
if not of then
377+
print(E)
331378
else
332379
of:write(os) of:close()
333380
end
334381
end
335-
336-
p = st + cs
337382
end
383+
384+
f:close()
338385
end
339386

340387
if #arg < 1 then

0 commit comments

Comments
 (0)