diff options
Diffstat (limited to 'tex/context/base/mkiv/util-zip.lua')
-rw-r--r-- | tex/context/base/mkiv/util-zip.lua | 201 |
1 files changed, 159 insertions, 42 deletions
diff --git a/tex/context/base/mkiv/util-zip.lua b/tex/context/base/mkiv/util-zip.lua index e97f3a065..67c1a715f 100644 --- a/tex/context/base/mkiv/util-zip.lua +++ b/tex/context/base/mkiv/util-zip.lua @@ -21,6 +21,14 @@ local ioopen = io.open local loaddata, savedata = io.loaddata, io.savedata local filejoin, isdir, dirname, mkdirs = file.join, lfs.isdir, file.dirname, dir.mkdirs +gzip = gzip or { } -- so in luatex we keep the old ones too + +if not zlib then + zlib = xzip -- in luametatex we shadow the old one +elseif not xzip then + xzip = zlib +end + local files = utilities.files local openfile = files.open local closefile = files.close @@ -497,48 +505,157 @@ if xzip then -- flate then do end -zipfiles.gunzipfile = gzip.load +if not gzip.compress then + + -- todo: compress/decompress that work with offset in string + + -- We only have a few official methods here: + -- + -- local decompressed = gzip.load (filename) + -- local resultsize = gzip.save (filename,compresslevel) + -- local compressed = gzip.compress (str,compresslevel) + -- local decompressed = gzip.decompress (str) + -- local iscompressed = gzip.compressed (str) + -- local suffix, okay = gzip.suffix (filename) + -- + -- In LuaMetaTeX we have only xzip which implements a very few methods: + -- + -- compress (str,level,method,window,memory,strategy) + -- decompress (str,window) + -- adler32 (str,checksum) + -- crc32 (str,checksum) + -- + -- Special window values are: + -- + -- flate : - 15 + -- zlib : 15 + -- gzip : - 15 + + local suffix = file.suffix + local suffixes = file.suffixes + local find = string.find + local concat = table.concat + local openfile = io.open + + local gzipwindow = -15 -- miniz needs this + local gziplevel = 3 + local identifier = "\x1F\x8B" + local pattern = "^\x1F\x8B\x08" + + local compress = zlib.compress + local decompress = zlib.decompress + local crc32 = zlib.crc32 + + local streams = utilities.streams + local openstream = streams.openstring + local closestream = streams.close + local getposition = streams.getposition + local readbyte = streams.readbyte + local readcardinal4 = streams.readcardinal4le + local readcardinal2 = streams.readcardinal2le + local readstring = streams.readstring + local readcstring = streams.readcstring + local skipbytes = streams.skip + + local tocardinal1 = streams.tocardinal1 + local tocardinal4 = streams.tocardinal4le + + local function getdecompressed(str) + local s = openstream(str) + local identifier = readstring(s,2) + local method = readbyte(s,1) + local flags = readbyte(s,1) + local timestamp = readcardinal4(s) + local compression = readbyte(s,1) + local operating = readbyte(s,1) + local isjusttext = (flags & 0x01 ~= 0) and true or false + local extrasize = (flags & 0x04 ~= 0) and readcardinal2(s) or 0 + local filename = (flags & 0x08 ~= 0) and readcstring(s) or "" + local comment = (flags & 0x10 ~= 0) and readcstring(s) or "" + local checksum = (flags & 0x02 ~= 0) and readcardinal2(s) or 0 + local compressed = readstring(s,#str) + local data = decompress(compressed,gzipwindow) -- pass offset + return data + end --- if flate then --- --- local streams = utilities.streams --- local openfile = streams.open --- local closestream = streams.close --- local setposition = streams.setposition --- local getsize = streams.size --- local readcardinal4 = streams.readcardinal4le --- local getstring = streams.getstring --- local decompress = flate.gz_decompress --- --- -- id1=1 id2=1 method=1 flags=1 mtime=4(le) extra=1 os=1 --- -- flags:8 comment=...<nul> flags:4 name=...<nul> flags:2 extra=...<nul> flags:1 crc=2 --- -- data:? --- -- crc=4 size=4 --- --- function zipfiles.gunzipfile(filename) --- local strm = openfile(filename) --- if strm then --- setposition(strm,getsize(strm) - 4 + 1) --- local size = readcardinal4(strm) --- local data = decompress(getstring(strm),size) --- closestream(strm) --- return data --- end --- end --- --- elseif gzip then --- --- local openfile = gzip.open --- --- function zipfiles.gunzipfile(filename) --- local g = openfile(filename,"rb") --- if g then --- local d = g:read("*a") --- d:close() --- return d --- end --- end --- --- end + local function putcompressed(str,level,originalname) + return concat { + identifier, -- 2 identifier + tocardinal1(0x08), -- 1 method + tocardinal1(0x08), -- 1 flags + tocardinal4(os.time()), -- 4 mtime + tocardinal1(0x02), -- 1 compression (2 or 4) + tocardinal1(0xFF), -- 1 operating + (originalname or "unknownname") .. "\0", + compress(str,level,nil,gzipwindow), + tocardinal4(crc32(str)), -- 4 + tocardinal4(#str), -- 4 + } + end + + function gzip.load(filename) + local f = openfile(filename,"rb") + if not f then + -- invalid file + else + local data = f:read("*all") + f:close() + if data and data ~= "" then + if suffix(filename) == "gz" then + data = getdecompressed(data) + end + return data + end + end + end + + function gzip.save(filename,data,level,originalname) + if suffix(filename) ~= "gz" then + filename = filename .. ".gz" + end + local f = openfile(filename,"wb") + if f then + data = putcompressed(data or "",level or gziplevel,originalname) + f:write(data) + f:close() + return #data + end + end + + function gzip.suffix(filename) + local suffix, extra = suffixes(filename) + local gzipped = extra == "gz" + return suffix, gzipped + end + + function gzip.compressed(s) + return s and find(s,identifier) + end + + function gzip.compress(s,level) + if s and not find(s,identifier) then -- the find check might go away + if not level then + level = gziplevel + elseif level <= 0 then + return s + elseif level > 9 then + level = 9 + end + return putcompressed(s,level or gziplevel) or s + end + end + + function gzip.decompress(s) + if s and find(s,identifier) then + return getdecompressed(s) + else + return s + end + end + + +end + +zipfiles.gunzipfile = gzip.load return zipfiles |