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 |