util-sac.lua /size: 13 Kb    last modification: 2023-12-21 09:44
1if not modules then modules = { } end modules ['util-sac'] = {
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
10-- experimental string access (some 3 times faster than file access when messing
11-- with bytes)
12
13local byte, sub = string.byte, string.sub
14local tonumber = tonumber
15
16utilities         = utilities or { }
17local streams     = { }
18utilities.streams = streams
19
20function streams.open(filename,zerobased)
21    local f = filename and io.loaddata(filename)
22    if f then
23        return { f, 1, #f, zerobased or false }
24    end
25end
26
27function streams.openstring(f,zerobased)
28    if f then
29        return { f, 1, #f, zerobased or false }
30    end
31end
32
33function streams.getstring(f)
34    if f then
35        return f[1]
36    end
37end
38
39function streams.close()
40    -- dummy
41end
42
43function streams.size(f)
44    return f and f[3] or 0
45end
46
47streams.getsize = streams.size
48
49function streams.setposition(f,i)
50    if f[4] then
51        -- zerobased
52        if i <= 0 then
53            f[2] = 1
54        else
55            f[2] = i + 1
56        end
57    else
58        if i <= 1 then
59            f[2] = 1
60        else
61            f[2] = i
62        end
63    end
64end
65
66function streams.getposition(f)
67    if f[4] then
68        -- zerobased
69        return f[2] - 1
70    else
71        return f[2]
72    end
73end
74
75function streams.look(f,n,chars)
76    local b = f[2]
77    local e = b + n - 1
78    if chars then
79        return sub(f[1],b,e)
80    else
81        return byte(f[1],b,e)
82    end
83end
84
85function streams.skip(f,n)
86    f[2] = f[2] + n
87end
88
89function streams.readbyte(f)
90    local i = f[2]
91    f[2] = i + 1
92    return byte(f[1],i)
93end
94
95function streams.readbytes(f,n)
96    local i = f[2]
97    local j = i + n
98    f[2] = j
99    return byte(f[1],i,j-1)
100end
101
102function streams.readbytetable(f,n)
103    local i = f[2]
104    local j = i + n
105    f[2] = j
106    return { byte(f[1],i,j-1) }
107end
108
109function streams.skipbytes(f,n)
110    f[2] = f[2] + n
111end
112
113function streams.readchar(f)
114    local i = f[2]
115    f[2] = i + 1
116    return sub(f[1],i,i)
117end
118
119function streams.readstring(f,n)
120    local i = f[2]
121    local j = i + n
122    f[2] = j
123    return sub(f[1],i,j-1)
124end
125
126function streams.readinteger1(f)  -- one byte
127    local i = f[2]
128    f[2] = i + 1
129    local n = byte(f[1],i)
130    if n  >= 0x80 then
131        return n - 0x100
132    else
133        return n
134    end
135end
136
137streams.readcardinal1 = streams.readbyte  -- one byte
138streams.readcardinal  = streams.readcardinal1
139streams.readinteger   = streams.readinteger1
140
141function streams.readcardinal2(f)
142    local i = f[2]
143    local j = i + 1
144    f[2] = j + 1
145    local a, b = byte(f[1],i,j)
146    return 0x100 * a + b
147end
148
149function streams.readcardinal2le(f)
150    local i = f[2]
151    local j = i + 1
152    f[2] = j + 1
153    local b, a = byte(f[1],i,j)
154    return 0x100 * a + b
155end
156
157function streams.readinteger2(f)
158    local i = f[2]
159    local j = i + 1
160    f[2] = j + 1
161    local a, b = byte(f[1],i,j)
162    if a >= 0x80 then
163        return 0x100 * a + b - 0x10000
164    else
165        return 0x100 * a + b
166    end
167end
168
169function streams.readinteger2le(f)
170    local i = f[2]
171    local j = i + 1
172    f[2] = j + 1
173    local b, a = byte(f[1],i,j)
174    if a >= 0x80 then
175        return 0x100 * a + b - 0x10000
176    else
177        return 0x100 * a + b
178    end
179end
180
181function streams.readcardinal3(f)
182    local i = f[2]
183    local j = i + 2
184    f[2] = j + 1
185    local a, b, c = byte(f[1],i,j)
186    return 0x10000 * a + 0x100 * b + c
187end
188
189function streams.readcardinal3le(f)
190    local i = f[2]
191    local j = i + 2
192    f[2] = j + 1
193    local c, b, a = byte(f[1],i,j)
194    return 0x10000 * a + 0x100 * b + c
195end
196
197function streams.readinteger3(f)
198    local i = f[2]
199    local j = i + 3
200    f[2] = j + 1
201    local a, b, c = byte(f[1],i,j)
202    if a >= 0x80 then
203        return 0x10000 * a + 0x100 * b + c - 0x1000000
204    else
205        return 0x10000 * a + 0x100 * b + c
206    end
207end
208
209function streams.readinteger3le(f)
210    local i = f[2]
211    local j = i + 3
212    f[2] = j + 1
213    local c, b, a = byte(f[1],i,j)
214    if a >= 0x80 then
215        return 0x10000 * a + 0x100 * b + c - 0x1000000
216    else
217        return 0x10000 * a + 0x100 * b + c
218    end
219end
220
221function streams.readcardinal4(f)
222    local i = f[2]
223    local j = i + 3
224    f[2] = j + 1
225    local a, b, c, d = byte(f[1],i,j)
226    return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
227end
228
229function streams.readcardinal4le(f)
230    local i = f[2]
231    local j = i + 3
232    f[2] = j + 1
233    local d, c, b, a = byte(f[1],i,j)
234    return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
235end
236
237function streams.readinteger4(f)
238    local i = f[2]
239    local j = i + 3
240    f[2] = j + 1
241    local a, b, c, d = byte(f[1],i,j)
242    if a >= 0x80 then
243        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
244    else
245        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
246    end
247end
248
249function streams.readinteger4le(f)
250    local i = f[2]
251    local j = i + 3
252    f[2] = j + 1
253    local d, c, b, a = byte(f[1],i,j)
254    if a >= 0x80 then
255        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
256    else
257        return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
258    end
259end
260
261function streams.readfixed2(f)
262    local i = f[2]
263    local j = i + 1
264    f[2] = j + 1
265    local n1, n2 = byte(f[1],i,j)
266    if n1 >= 0x80 then
267        n1 = n1 - 0x100
268    end
269    return n1 + n2/0xFF
270end
271
272function streams.readfixed4(f)
273    local i = f[2]
274    local j = i + 3
275    f[2] = j + 1
276    local a, b, c, d = byte(f[1],i,j)
277    local n1 = 0x100 * a + b
278    local n2 = 0x100 * c + d
279    if n1 >= 0x8000 then
280        n1 = n1 - 0x10000
281    end
282    return n1 + n2/0xFFFF
283end
284
285if bit32 then
286
287    local extract = bit32.extract
288    local band    = bit32.band
289
290    function streams.read2dot14(f)
291        local i = f[2]
292        local j = i + 1
293        f[2] = j + 1
294        local a, b = byte(f[1],i,j)
295        if a >= 0x80 then
296            local n = -(0x100 * a + b)
297            return - (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
298        else
299            local n =   0x100 * a + b
300            return   (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
301        end
302    end
303
304end
305
306function streams.skipshort(f,n)
307    f[2] = f[2] + 2*(n or 1)
308end
309
310function streams.skiplong(f,n)
311    f[2] = f[2] + 4*(n or 1)
312end
313
314if sio and sio.readcardinal2 then
315
316    local readcardinal1  = sio.readcardinal1
317    local readcardinal2  = sio.readcardinal2
318    local readcardinal3  = sio.readcardinal3
319    local readcardinal4  = sio.readcardinal4
320    local readinteger1   = sio.readinteger1
321    local readinteger2   = sio.readinteger2
322    local readinteger3   = sio.readinteger3
323    local readinteger4   = sio.readinteger4
324    local readfixed2     = sio.readfixed2
325    local readfixed4     = sio.readfixed4
326    local read2dot14     = sio.read2dot14
327    local readbytes      = sio.readbytes
328    local readbytetable  = sio.readbytetable
329
330    function streams.readcardinal1(f)
331        local i = f[2]
332        f[2] = i + 1
333        return readcardinal1(f[1],i)
334    end
335    function streams.readcardinal2(f)
336        local i = f[2]
337        f[2] = i + 2
338        return readcardinal2(f[1],i)
339    end
340    function streams.readcardinal3(f)
341        local i = f[2]
342        f[2] = i + 3
343        return readcardinal3(f[1],i)
344    end
345    function streams.readcardinal4(f)
346        local i = f[2]
347        f[2] = i + 4
348        return readcardinal4(f[1],i)
349    end
350    function streams.readinteger1(f)
351        local i = f[2]
352        f[2] = i + 1
353        return readinteger1(f[1],i)
354    end
355    function streams.readinteger2(f)
356        local i = f[2]
357        f[2] = i + 2
358        return readinteger2(f[1],i)
359    end
360    function streams.readinteger3(f)
361        local i = f[2]
362        f[2] = i + 3
363        return readinteger3(f[1],i)
364    end
365    function streams.readinteger4(f)
366        local i = f[2]
367        f[2] = i + 4
368        return readinteger4(f[1],i)
369    end
370    function streams.readfixed2(f) -- needs recent luatex
371        local i = f[2]
372        f[2] = i + 2
373        return readfixed2(f[1],i)
374    end
375    function streams.readfixed4(f) -- needs recent luatex
376        local i = f[2]
377        f[2] = i + 4
378        return readfixed4(f[1],i)
379    end
380    function streams.read2dot14(f)
381        local i = f[2]
382        f[2] = i + 2
383        return read2dot14(f[1],i)
384    end
385    function streams.readbytes(f,n)
386        local i = f[2]
387        local s = f[3]
388        local p = i + n
389        if p > s then
390            f[2] = s + 1
391        else
392            f[2] = p
393        end
394        return readbytes(f[1],i,n)
395    end
396    function streams.readbytetable(f,n)
397        local i = f[2]
398        local s = f[3]
399        local p = i + n
400        if p > s then
401            f[2] = s + 1
402        else
403            f[2] = p
404        end
405        return readbytetable(f[1],i,n)
406    end
407
408    streams.readbyte       = streams.readcardinal1
409    streams.readsignedbyte = streams.readinteger1
410    streams.readcardinal   = streams.readcardinal1
411    streams.readinteger    = streams.readinteger1
412
413end
414
415if sio and sio.readcardinaltable then
416
417    local readcardinaltable = sio.readcardinaltable
418    local readintegertable  = sio.readintegertable
419
420    function utilities.streams.readcardinaltable(f,n,b)
421        local i = f[2]
422        local s = f[3]
423        local p = i + n * b
424        if p > s then
425            f[2] = s + 1
426        else
427            f[2] = p
428        end
429        return readcardinaltable(f[1],i,n,b)
430    end
431
432    function utilities.streams.readintegertable(f,n,b)
433        local i = f[2]
434        local s = f[3]
435        local p = i +  n * b
436        if p > s then
437            f[2] = s + 1
438        else
439            f[2] = p
440        end
441        return readintegertable(f[1],i,n,b)
442    end
443
444else
445
446    local readcardinal1 = streams.readcardinal1
447    local readcardinal2 = streams.readcardinal2
448    local readcardinal3 = streams.readcardinal3
449    local readcardinal4 = streams.readcardinal4
450
451    function streams.readcardinaltable(f,n,b)
452        local i = f[2]
453        local s = f[3]
454        local p = i + n * b
455        if p > s then
456            f[2] = s + 1
457        else
458            f[2] = p
459        end
460        local t = { }
461            if b == 1 then for i=1,n do t[i] = readcardinal1(f[1],i) end
462        elseif b == 2 then for i=1,n do t[i] = readcardinal2(f[1],i) end
463        elseif b == 3 then for i=1,n do t[i] = readcardinal3(f[1],i) end
464        elseif b == 4 then for i=1,n do t[i] = readcardinal4(f[1],i) end end
465        return t
466    end
467
468    local readinteger1 = streams.readinteger1
469    local readinteger2 = streams.readinteger2
470    local readinteger3 = streams.readinteger3
471    local readinteger4 = streams.readinteger4
472
473    function streams.readintegertable(f,n,b)
474        local i = f[2]
475        local s = f[3]
476        local p = i + n * b
477        if p > s then
478            f[2] = s + 1
479        else
480            f[2] = p
481        end
482        local t = { }
483            if b == 1 then for i=1,n do t[i] = readinteger1(f[1],i) end
484        elseif b == 2 then for i=1,n do t[i] = readinteger2(f[1],i) end
485        elseif b == 3 then for i=1,n do t[i] = readinteger3(f[1],i) end
486        elseif b == 4 then for i=1,n do t[i] = readinteger4(f[1],i) end end
487        return t
488    end
489
490end
491
492-- For practical reasons we put this here. It's less efficient but ok when we don't
493-- have much access.
494
495do
496
497    local files = utilities.files
498
499    if files then
500
501        local openfile     = files.open
502        local openstream   = streams.open
503        local openstring   = streams.openstring
504
505        local setmetatable = setmetatable
506
507        function io.newreader(str,method)
508            local f, m
509            if method == "string" then
510                f = openstring(str,true)
511                m = streams
512            elseif method == "stream" then
513                f = openstream(str,true)
514                m = streams
515            else
516                f = openfile(str,"rb")
517                m = files
518            end
519            if f then
520                local t = { }
521                setmetatable(t, {
522                    __index = function(t,k)
523                        local r = m[k]
524                        if k == "close" then
525                            -- maybe use __toclose
526                            if f then
527                                m.close(f)
528                                f = nil
529                            end
530                            return function() end
531                        elseif r then
532                            local v = function(_,a,b) return r(f,a,b) end
533                            t[k] = v
534                            return v
535                        else
536                            print("unknown key",k)
537                        end
538                    end
539                } )
540                return t
541            end
542        end
543
544    end
545
546end
547
548if bit32 and not streams.tocardinal1 then
549
550    local extract = bit32.extract
551    local char    = string.char
552
553             streams.tocardinal1           = char
554    function streams.tocardinal2(n)   return char(extract(n, 8,8),extract(n, 0,8)) end
555    function streams.tocardinal3(n)   return char(extract(n,16,8),extract(n, 8,8),extract(n,0,8)) end
556    function streams.tocardinal4(n)   return char(extract(n,24,8),extract(n,16,8),extract(n,8,8),extract(n,0,8)) end
557
558             streams.tocardinal1le         = char
559    function streams.tocardinal2le(n) return char(extract(n,0,8),extract(n,8,8)) end
560    function streams.tocardinal3le(n) return char(extract(n,0,8),extract(n,8,8),extract(n,16,8)) end
561    function streams.tocardinal4le(n) return char(extract(n,0,8),extract(n,8,8),extract(n,16,8),extract(n,24,8)) end
562
563end
564
565if not streams.readcstring then
566
567    local readchar = streams.readchar
568    local concat   = table.concat
569
570    function streams.readcstring(f)
571        local t = { }
572        while true do
573            local c = readchar(f)
574            if c and c ~= "\0" then
575                t[#t+1] = c
576            else
577                return concat(t)
578            end
579        end
580    end
581
582end
583