summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/util-zip.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkiv/util-zip.lua')
-rw-r--r--tex/context/base/mkiv/util-zip.lua201
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