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