1if not modules then modules = { } end modules ['data-zip'] = {
2 version = 1.001,
3 comment = "companion to luat-lib.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11local format, find, match = string.format, string.find, string.match
12
13local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
14
15local report_zip = logs.reporter("resolvers","zip")
16
17
18
19
20
21
22
23
24
25local resolvers = resolvers
26local findfile = resolvers.findfile
27local registerfile = resolvers.registerfile
28local splitmethod = resolvers.splitmethod
29local prependhash = resolvers.prependhash
30local starttiming = resolvers.starttiming
31local extendtexmf = resolvers.extendtexmfvariable
32local stoptiming = resolvers.stoptiming
33
34local urlquery = url.query
35
36zip = zip or { }
37local zip = zip
38
39local archives = zip.archives or { }
40zip.archives = archives
41
42local registeredfiles = zip.registeredfiles or { }
43zip.registeredfiles = registeredfiles
44
45local zipfiles = utilities.zipfiles
46
47local openzip, closezip, validfile, wholefile, filehandle, traversezip
48
49if zipfiles then
50
51 local ipairs = ipairs
52
53 openzip = zipfiles.open
54 closezip = zipfiles.close
55 validfile = zipfiles.found
56 wholefile = zipfiles.unzip
57
58 local listzip = zipfiles.list
59
60 traversezip = function(zfile)
61 return ipairs(listzip(zfile))
62 end
63
64 local streams = utilities.streams
65 local openstream = streams.open
66 local readstring = streams.readstring
67 local streamsize = streams.size
68
69 local metatable = {
70 close = streams.close,
71 read = function(stream,n)
72 readstring(stream,n == "*a" and streamsize(stream) or n)
73 end
74 }
75
76 filehandle = function(zfile,queryname)
77 local data = wholefile(zfile,queryname)
78 if data then
79 local stream = openstream(data)
80 if stream then
81 return setmetatableindex(stream,metatable)
82 end
83 end
84 end
85
86else
87
88 openzip = zip.open
89 closezip = zip.close
90
91 validfile = function(zfile,queryname)
92 local dfile = zfile:open(queryname)
93 if dfile then
94 dfile:close()
95 return true
96 end
97 return false
98 end
99
100 traversezip = function(zfile)
101 return z:files()
102 end
103
104 wholefile = function(zfile,queryname)
105 local dfile = zfile:open(queryname)
106 if dfile then
107 local s = dfile:read("*all")
108 dfile:close()
109 return s
110 end
111 end
112
113 filehandle = function(zfile,queryname)
114 local dfile = zfile:open(queryname)
115 if dfile then
116 return dfile
117 end
118 end
119
120end
121
122local function validzip(str)
123 if not find(str,"^zip://") then
124 return "zip:///" .. str
125 else
126 return str
127 end
128end
129
130local function openarchive(name)
131 if not name or name == "" then
132 return nil
133 else
134 local arch = archives[name]
135 if not arch then
136 local full = findfile(name) or ""
137 arch = full ~= "" and openzip(full) or false
138 archives[name] = arch
139 end
140 return arch
141 end
142end
143
144local function closearchive(name)
145 if not name or (name == "" and archives[name]) then
146 closezip(archives[name])
147 archives[name] = nil
148 end
149end
150
151zip.openarchive = openarchive
152zip.closearchive = closearchive
153
154function resolvers.locators.zip(specification)
155 local archive = specification.filename
156 local zipfile = archive and archive ~= "" and openarchive(archive)
157 if trace_locating then
158 if zipfile then
159 report_zip("locator: archive %a found",archive)
160 else
161 report_zip("locator: archive %a not found",archive)
162 end
163 end
164end
165
166function resolvers.concatinators.zip(zipfile,path,name)
167 if not path or path == "" then
168 return format('%s?name=%s',zipfile,name)
169 else
170 return format('%s?name=%s/%s',zipfile,path,name)
171 end
172end
173
174local finders = resolvers.finders
175local notfound = finders.notfound
176
177function finders.zip(specification)
178 local original = specification.original
179 local archive = specification.filename
180 if archive then
181 local query = urlquery(specification.query)
182 local queryname = query.name
183 if queryname then
184 local zfile = openarchive(archive)
185 if zfile then
186 if trace_locating then
187 report_zip("finder: archive %a found",archive)
188 end
189 if validfile(zfile,queryname) then
190 if trace_locating then
191 report_zip("finder: file %a found",queryname)
192 end
193 return specification.original
194 elseif trace_locating then
195 report_zip("finder: file %a not found",queryname)
196 end
197 elseif trace_locating then
198 report_zip("finder: unknown archive %a",archive)
199 end
200 end
201 end
202 if trace_locating then
203 report_zip("finder: %a not found",original)
204 end
205 return notfound()
206end
207
208local openers = resolvers.openers
209local notfound = openers.notfound
210local textopener = openers.helpers.textopener
211
212function openers.zip(specification)
213 local original = specification.original
214 local archive = specification.filename
215 if archive then
216 local query = urlquery(specification.query)
217 local queryname = query.name
218 if queryname then
219 local zfile = openarchive(archive)
220 if zfile then
221 if trace_locating then
222 report_zip("opener; archive %a opened",archive)
223 end
224 local handle = filehandle(zfile,queryname)
225 if handle then
226 if trace_locating then
227 report_zip("opener: file %a found",queryname)
228 end
229 return textopener('zip',original,handle)
230 elseif trace_locating then
231 report_zip("opener: file %a not found",queryname)
232 end
233 elseif trace_locating then
234 report_zip("opener: unknown archive %a",archive)
235 end
236 end
237 end
238 if trace_locating then
239 report_zip("opener: %a not found",original)
240 end
241 return notfound()
242end
243
244local loaders = resolvers.loaders
245local notfound = loaders.notfound
246
247function loaders.zip(specification)
248 local original = specification.original
249 local archive = specification.filename
250 if archive then
251 local query = urlquery(specification.query)
252 local queryname = query.name
253 if queryname then
254 local zfile = openarchive(archive)
255 if zfile then
256 if trace_locating then
257 report_zip("loader: archive %a opened",archive)
258 end
259 local data = wholefile(zfile,queryname)
260 if data then
261 if trace_locating then
262 report_zip("loader; file %a loaded",original)
263 end
264 return true, data, #data
265 elseif trace_locating then
266 report_zip("loader: file %a not found",queryname)
267 end
268 elseif trace_locating then
269 report_zip("loader; unknown archive %a",archive)
270 end
271 end
272 end
273 if trace_locating then
274 report_zip("loader: %a not found",original)
275 end
276 return notfound()
277end
278
279
280
281
282local function registerzipfile(z,tree)
283 local names = { }
284 local files = { }
285 local remap = { }
286 local n = 0
287 local filter = tree == "" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree)
288 if trace_locating then
289 report_zip("registering: using filter %a",filter)
290 end
291 starttiming()
292 for i in traversezip(z) do
293 local filename = i.filename
294 local path, name = match(filename,filter)
295 if not path then
296 n = n + 1
297 registerfile(names,filename,"")
298 local usedname = lower(filename)
299 files[usedname] = ""
300 if usedname ~= filename then
301 remap[usedname] = filename
302 end
303 elseif name and name ~= "" then
304 n = n + 1
305 register(names,name,path)
306 local usedname = lower(name)
307 files[usedname] = path
308 if usedname ~= name then
309 remap[usedname] = name
310 end
311 else
312
313 end
314 end
315 stoptiming()
316 report_zip("registering: %s files registered",n)
317 return {
318
319 files = files,
320 remap = remap,
321 }
322end
323
324local function usezipfile(archive)
325 local specification = splitmethod(archive)
326 local archive = specification.filename
327 if archive and not registeredfiles[archive] then
328 local z = openarchive(archive)
329 if z then
330 local tree = urlquery(specification.query).tree or ""
331 if trace_locating then
332 report_zip("registering: archive %a",archive)
333 end
334 prependhash('zip',archive)
335 extendtexmf(archive)
336 registeredfiles[archive] = z
337 registerfilehash(archive,registerzipfile(z,tree))
338 elseif trace_locating then
339 report_zip("registering: unknown archive %a",archive)
340 end
341 elseif trace_locating then
342 report_zip("registering: archive %a not found",archive)
343 end
344end
345
346resolvers.usezipfile = usezipfile
347resolvers.registerzipfile = registerzipfile
348
349function resolvers.hashers.zip(specification)
350 local archive = specification.filename
351 if trace_locating then
352 report_zip("loading file %a",archive)
353 end
354 usezipfile(specification.original)
355end
356 |