1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
--[[
File l3build-zip.lua Copyright (C) 2021 The LaTeX Project
It may be distributed and/or modified under the conditions of the
LaTeX Project Public License (LPPL), either version 1.3c of this
license or (at your option) any later version. The latest version
of this license is in the file
http://www.latex-project.org/lppl.txt
This file is part of the "l3build bundle" (The Work in LPPL)
and all files in that bundle must be distributed together.
-----------------------------------------------------------------------
The development version of the bundle can be found at
https://github.com/latex3/l3build
for those people who are interested.
--]]
local concat = table.concat
local open = io.open
local osdate = os.date
local pack = string.pack
local setmetatable = setmetatable
local iotype = io.type
local compress = zlib.compress
local crc32 = zlib.crc32
local function encode_time(unix)
local t = osdate('*t', unix)
local date = t.day | (t.month << 5) | ((t.year-1980) << 9)
local time = (t.sec//2) | (t.min << 5) | (t.hour << 11)
return date, time
end
local meta = {__index = {
add = function(z, filename, innername, binary, executable)
innername = innername or filename
local offset = z.f:seek'cur'
local content do
local f = iotype(filename) and filename or assert(open(filename, binary and 'rb' or 'r'))
content = f:read'*a'
f:close()
end
local crc32 = crc32(crc32(), content)
local compressed = compress(content, nil, nil, -15)
if #compressed >= #content then
compressed = nil
end
local date, time = encode_time(nil)
z.f:write(pack("<c4I2I2I2I2I2I4I4I4I2I2",
'PK\3\4',
compressed and 20 or 10, -- ZIP 2.0 to allow deflate
0, -- We never set flags
compressed and 8 or 0, -- Always use deflate
time,
date,
crc32,
compressed and #compressed or #content,
#content,
#innername,
0),
innername,
compressed or content)
local central = pack("<c4I2I2I2I2I2I2I4I4I4I2I2I2I2I2I4I4",
'PK\1\2',
(3 << 8) | 63, -- Use UNIX attributes, written against ZIP 6.3
compressed and 20 or 10, -- ZIP 2.0 to allow deflate
0, -- We never set flags
compressed and 8 or 0, -- Always use deflate
time,
date,
crc32,
compressed and #compressed or #content,
#content,
#innername,
0, -- no extra data
0, -- no comment
0, -- Disc 0
binary and 0 or 1,
(executable and 0x81ED--[[0100755]] or 0x81A4--[[0100644]]) << 16,
offset)
z.central[#z.central+1] = central .. innername
end,
close = function(z, comment)
comment = comment or ''
local offset = z.f:seek'cur'
local central = concat(z.central)
z.f:write(central, pack("<c4I2I2I2I2I4I4I2",
'PK\5\6',
0, -- This is disc 0
0, -- central dictionary started on disc 0
#z.central, -- Central disctionary entries on this disc
#z.central, -- Central disctionary entries on all discs
#central,
offset,
#comment), comment)
return z.f:close()
end,
}}
return function(filename)
local f, msg = open(filename, 'wb')
if not f then return f, msg end
return setmetatable({
f = f,
offset = 1,
central = {},
}, meta)
end
|