util-fil.lua /size: 11 Kb    last modification: 2021-10-28 13:50
1if not modules then modules = { } end modules ['util-fil'] = {
2    version   = 1.001,
3    optimize  = true,
4    comment   = "companion to luat-lib.mkiv",
5    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
6    copyright = "PRAGMA ADE / ConTeXt Development Team",
7    license   = "see context related readme files"
8}
9
10local tonumber = tonumber
11local byte = string.byte
12local char = string.char
13
14-- Here are a few helpers (the starting point were old ones I used for parsing
15-- flac files). In Lua 5.3 we can probably do this better. Some code will move
16-- here.
17
18-- We could comment those that are in fio and sio.
19
20utilities       = utilities or { }
21local files     = { }
22utilities.files = files
23
24-- we could have a gc method that closes but files auto close anyway
25
26local zerobased = { }
27
28function files.open(filename,zb)
29    local f = io.open(filename,"rb")
30    if f then
31        zerobased[f] = zb or false
32    end
33    return f
34end
35
36function files.close(f)
37    zerobased[f] = nil
38    f:close()
39end
40
41function files.size(f)
42    local current = f:seek()
43    local size = f:seek("end")
44    f:seek("set",current)
45    return size
46end
47
48files.getsize = files.size
49
50function files.setposition(f,n)
51    if zerobased[f] then
52        f:seek("set",n)
53    else
54        f:seek("set",n - 1)
55    end
56end
57
58function files.getposition(f)
59    if zerobased[f] then
60        return f:seek()
61    else
62        return f:seek() + 1
63    end
64end
65
66function files.look(f,n,chars)
67    local p = f:seek()
68    local s = f:read(n)
69    f:seek("set",p)
70    if chars then
71        return s
72    else
73        return byte(s,1,#s)
74    end
75end
76
77function files.skip(f,n)
78    if n == 1 then
79        f:read(n)
80    else
81        f:seek("set",f:seek()+n)
82    end
83end
84
85function files.readbyte(f)
86    return byte(f:read(1))
87end
88
89function files.readbytes(f,n)
90    return byte(f:read(n),1,n)
91end
92
93function files.readbytetable(f,n)
94 -- return { byte(f:read(n),1,n) }
95    local s = f:read(n or 1)
96    return { byte(s,1,#s) } -- best use the real length
97end
98
99function files.readchar(f)
100    return f:read(1)
101end
102
103function files.readstring(f,n)
104    return f:read(n or 1)
105end
106
107function files.readinteger1(f)  -- one byte
108    local n = byte(f:read(1))
109    if n >= 0x80 then
110        return n - 0x100
111    else
112        return n
113    end
114end
115
116files.readcardinal1  = files.readbyte  -- one byte
117files.readcardinal   = files.readcardinal1
118files.readinteger    = files.readinteger1
119files.readsignedbyte = files.readinteger1
120
121function files.readcardinal2(f)
122    local a, b = byte(f:read(2),1,2)
123    return 0x100 * a + b
124end
125
126function files.readcardinal2le(f)
127    local b, a = byte(f:read(2),1,2)
128    return 0x100 * a + b
129end
130
131function files.readinteger2(f)
132    local a, b = byte(f:read(2),1,2)
133    if a >= 0x80 then
134        return 0x100 * a + b - 0x10000
135    else
136        return 0x100 * a + b
137    end
138end
139
140function files.readinteger2le(f)
141    local b, a = byte(f:read(2),1,2)
142    if a >= 0x80 then
143        return 0x100 * a + b - 0x10000
144    else
145        return 0x100 * a + b
146    end
147end
148
149function files.readcardinal3(f)
150    local a, b, c = byte(f:read(3),1,3)
151    return 0x10000 * a + 0x100 * b + c
152end
153
154function files.readcardinal3le(f)
155    local c, b, a = byte(f:read(3),1,3)
156    return 0x10000 * a + 0x100 * b + c
157end
158
159function files.readinteger3(f)
160    local a, b, c = byte(f:read(3),1,3)
161    if a >= 0x80 then
162        return 0x10000 * a + 0x100 * b + c - 0x1000000
163    else
164        return 0x10000 * a + 0x100 * b + c
165    end
166end
167
168function files.readinteger3le(f)
169    local c, b, a = byte(f:read(3),1,3)
170    if a >= 0x80 then
171        return 0x10000 * a + 0x100 * b + c - 0x1000000
172    else
173        return 0x10000 * a + 0x100 * b + c
174    end
175end
176
177function files.readcardinal4(f)
178    local a, b, c, d = byte(f:read(4),1,4)
179    return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
180end
181
182function files.readcardinal4le(f)
183    local d, c, b, a = byte(f:read(4),1,4)
184    return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
185end
186
187function files.readinteger4(f)
188    local a, b, c, d = byte(f:read(4),1,4)
189    if a >= 0x80 then
190        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
191    else
192        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
193    end
194end
195
196function files.readinteger4le(f)
197    local d, c, b, a = byte(f:read(4),1,4)
198    if a >= 0x80 then
199        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
200    else
201        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
202    end
203end
204
205function files.readfixed2(f)
206    local n1, n2 = byte(f:read(2),1,2)
207    if n1 >= 0x80 then
208        n1 = n1 - 0x100
209    end
210    return n1 + n2/0xFF
211end
212
213-- (real) (n>>16) + ((n&0xffff)/65536.0)) but no cast in lua (we could use unpack)
214
215function files.readfixed4(f)
216    local a, b, c, d = byte(f:read(4),1,4)
217    local n1 = 0x100 * a + b
218    local n2 = 0x100 * c + d
219    if n1 >= 0x8000 then
220        n1 = n1 - 0x10000
221    end
222    return n1 + n2/0xFFFF
223end
224
225-- (real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0))
226
227if bit32 then
228
229    local extract = bit32.extract
230    local band    = bit32.band
231
232    function files.read2dot14(f)
233        local a, b = byte(f:read(2),1,2)
234        if a >= 0x80 then
235            local n = -(0x100 * a + b)
236            return - (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
237        else
238            local n =   0x100 * a + b
239            return   (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
240        end
241    end
242
243end
244
245function files.skipshort(f,n)
246    f:read(2*(n or 1))
247end
248
249function files.skiplong(f,n)
250    f:read(4*(n or 1))
251end
252
253-- writers (kind of slow)
254
255if bit32 then
256
257    local rshift = bit32.rshift
258
259    function files.writecardinal2(f,n)
260        local a = char(n % 256)
261        n = rshift(n,8)
262        local b = char(n % 256)
263        f:write(b,a)
264    end
265
266    function files.writecardinal4(f,n)
267        local a = char(n % 256)
268        n = rshift(n,8)
269        local b = char(n % 256)
270        n = rshift(n,8)
271        local c = char(n % 256)
272        n = rshift(n,8)
273        local d = char(n % 256)
274        f:write(d,c,b,a)
275    end
276
277    function files.writecardinal2le(f,n)
278        local a = char(n % 256)
279        n = rshift(n,8)
280        local b = char(n % 256)
281        f:write(a,b)
282    end
283
284    function files.writecardinal4le(f,n)
285        local a = char(n % 256)
286        n = rshift(n,8)
287        local b = char(n % 256)
288        n = rshift(n,8)
289        local c = char(n % 256)
290        n = rshift(n,8)
291        local d = char(n % 256)
292        f:write(a,b,c,d)
293    end
294
295else
296
297    local floor = math.floor
298
299    function files.writecardinal2(f,n)
300        local a = char(n % 256)
301        n = floor(n/256)
302        local b = char(n % 256)
303        f:write(b,a)
304    end
305
306    function files.writecardinal4(f,n)
307        local a = char(n % 256)
308        n = floor(n/256)
309        local b = char(n % 256)
310        n = floor(n/256)
311        local c = char(n % 256)
312        n = floor(n/256)
313        local d = char(n % 256)
314        f:write(d,c,b,a)
315    end
316
317    function files.writecardinal2le(f,n)
318        local a = char(n % 256)
319        n = floor(n/256)
320        local b = char(n % 256)
321        f:write(a,b)
322    end
323
324    function files.writecardinal4le(f,n)
325        local a = char(n % 256)
326        n = floor(n/256)
327        local b = char(n % 256)
328        n = floor(n/256)
329        local c = char(n % 256)
330        n = floor(n/256)
331        local d = char(n % 256)
332        f:write(a,b,c,d)
333    end
334
335end
336
337function files.writestring(f,s)
338    f:write(char(byte(s,1,#s)))
339end
340
341function files.writebyte(f,b)
342    f:write(char(b))
343end
344
345if fio and fio.readcardinal1 then
346
347    files.readcardinal1   = fio.readcardinal1
348    files.readcardinal2   = fio.readcardinal2
349    files.readcardinal3   = fio.readcardinal3
350    files.readcardinal4   = fio.readcardinal4
351
352    files.readcardinal1le = fio.readcardinal1le or files.readcardinal1le
353    files.readcardinal2le = fio.readcardinal2le or files.readcardinal2le
354    files.readcardinal3le = fio.readcardinal3le or files.readcardinal3le
355    files.readcardinal4le = fio.readcardinal4le or files.readcardinal4le
356
357    files.readinteger1    = fio.readinteger1
358    files.readinteger2    = fio.readinteger2
359    files.readinteger3    = fio.readinteger3
360    files.readinteger4    = fio.readinteger4
361
362    files.readinteger1le  = fio.readinteger1le or files.readinteger1le
363    files.readinteger2le  = fio.readinteger2le or files.readinteger2le
364    files.readinteger3le  = fio.readinteger3le or files.readinteger3le
365    files.readinteger4le  = fio.readinteger4le or files.readinteger4le
366
367    files.readfixed2      = fio.readfixed2
368    files.readfixed4      = fio.readfixed4
369    files.read2dot14      = fio.read2dot14
370    files.setposition     = fio.setposition
371    files.getposition     = fio.getposition
372
373    files.readbyte        = files.readcardinal1
374    files.readsignedbyte  = files.readinteger1
375    files.readcardinal    = files.readcardinal1
376    files.readinteger     = files.readinteger1
377
378    local skipposition    = fio.skipposition
379    files.skipposition    = skipposition
380
381    files.readbytes       = fio.readbytes
382    files.readbytetable   = fio.readbytetable
383
384    function files.skipshort(f,n)
385        skipposition(f,2*(n or 1))
386    end
387
388    function files.skiplong(f,n)
389        skipposition(f,4*(n or 1))
390    end
391
392end
393
394if fio and fio.writecardinal1 then
395
396    files.writecardinal1   = fio.writecardinal1
397    files.writecardinal2   = fio.writecardinal2
398    files.writecardinal3   = fio.writecardinal3
399    files.writecardinal4   = fio.writecardinal4
400
401    files.writecardinal1le = fio.writecardinal1le
402    files.writecardinal2le = fio.writecardinal2le
403    files.writecardinal3le = fio.writecardinal3le
404    files.writecardinal4le = fio.writecardinal4le
405
406    files.writeinteger1    = fio.writeinteger1 or fio.writecardinal1
407    files.writeinteger2    = fio.writeinteger2 or fio.writecardinal2
408    files.writeinteger3    = fio.writeinteger3 or fio.writecardinal3
409    files.writeinteger4    = fio.writeinteger4 or fio.writecardinal4
410
411    files.writeinteger1le  = files.writeinteger1le or fio.writecardinal1le
412    files.writeinteger2le  = files.writeinteger2le or fio.writecardinal2le
413    files.writeinteger3le  = files.writeinteger3le or fio.writecardinal3le
414    files.writeinteger4le  = files.writeinteger4le or fio.writecardinal4le
415
416end
417
418if fio and fio.readcardinaltable then
419
420    files.readcardinaltable = fio.readcardinaltable
421    files.readintegertable  = fio.readintegertable
422
423else
424
425    local readcardinal1 = files.readcardinal1
426    local readcardinal2 = files.readcardinal2
427    local readcardinal3 = files.readcardinal3
428    local readcardinal4 = files.readcardinal4
429
430    function files.readcardinaltable(f,n,b)
431        local t = { }
432            if b == 1 then for i=1,n do t[i] = readcardinal1(f) end
433        elseif b == 2 then for i=1,n do t[i] = readcardinal2(f) end
434        elseif b == 3 then for i=1,n do t[i] = readcardinal3(f) end
435        elseif b == 4 then for i=1,n do t[i] = readcardinal4(f) end end
436        return t
437    end
438
439    local readinteger1 = files.readinteger1
440    local readinteger2 = files.readinteger2
441    local readinteger3 = files.readinteger3
442    local readinteger4 = files.readinteger4
443
444    function files.readintegertable(f,n,b)
445        local t = { }
446            if b == 1 then for i=1,n do t[i] = readinteger1(f) end
447        elseif b == 2 then for i=1,n do t[i] = readinteger2(f) end
448        elseif b == 3 then for i=1,n do t[i] = readinteger3(f) end
449        elseif b == 4 then for i=1,n do t[i] = readinteger4(f) end end
450        return t
451    end
452
453end
454