dmg-builder 26.5.0 → 26.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/dmgUtil.d.ts +2 -3
- package/out/dmgUtil.js +41 -23
- package/out/dmgUtil.js.map +1 -1
- package/package.json +3 -4
- package/vendor/biplist/__init__.py +0 -977
- package/vendor/dmgbuild/__init__.py +0 -5
- package/vendor/dmgbuild/__main__.py +0 -70
- package/vendor/dmgbuild/badge.py +0 -169
- package/vendor/dmgbuild/colors.py +0 -504
- package/vendor/dmgbuild/core.py +0 -963
- package/vendor/dmgbuild/licensing.py +0 -331
- package/vendor/dmgbuild/resources/builtin-arrow.tiff +0 -0
- package/vendor/ds_store/__init__.py +0 -5
- package/vendor/ds_store/__main__.py +0 -102
- package/vendor/ds_store/buddy.py +0 -486
- package/vendor/ds_store/store.py +0 -1262
- package/vendor/mac_alias/__init__.py +0 -47
- package/vendor/mac_alias/alias.py +0 -772
- package/vendor/mac_alias/bookmark.py +0 -677
- package/vendor/mac_alias/osx.py +0 -1074
- package/vendor/mac_alias/utils.py +0 -20
- package/vendor/run_dmgbuild.py +0 -14
package/vendor/ds_store/buddy.py
DELETED
|
@@ -1,486 +0,0 @@
|
|
|
1
|
-
import binascii
|
|
2
|
-
import bisect
|
|
3
|
-
import os
|
|
4
|
-
import struct
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
class BuddyError(Exception):
|
|
8
|
-
pass
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class Block:
|
|
12
|
-
def __init__(self, allocator, offset, size):
|
|
13
|
-
self._allocator = allocator
|
|
14
|
-
self._offset = offset
|
|
15
|
-
self._size = size
|
|
16
|
-
self._value = bytearray(allocator.read(offset, size))
|
|
17
|
-
self._pos = 0
|
|
18
|
-
self._dirty = False
|
|
19
|
-
|
|
20
|
-
def __len__(self):
|
|
21
|
-
return self._size
|
|
22
|
-
|
|
23
|
-
def __enter__(self):
|
|
24
|
-
return self
|
|
25
|
-
|
|
26
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
|
27
|
-
self.close()
|
|
28
|
-
|
|
29
|
-
def close(self):
|
|
30
|
-
if self._dirty:
|
|
31
|
-
self.flush()
|
|
32
|
-
|
|
33
|
-
def flush(self):
|
|
34
|
-
if self._dirty:
|
|
35
|
-
self._dirty = False
|
|
36
|
-
self._allocator.write(self._offset, self._value)
|
|
37
|
-
|
|
38
|
-
def invalidate(self):
|
|
39
|
-
self._dirty = False
|
|
40
|
-
|
|
41
|
-
def zero_fill(self):
|
|
42
|
-
len = self._size - self._pos
|
|
43
|
-
zeroes = b"\0" * len
|
|
44
|
-
self._value[self._pos : self._size] = zeroes
|
|
45
|
-
self._dirty = True
|
|
46
|
-
|
|
47
|
-
def tell(self):
|
|
48
|
-
return self._pos
|
|
49
|
-
|
|
50
|
-
def seek(self, pos, whence=os.SEEK_SET):
|
|
51
|
-
if whence == os.SEEK_CUR:
|
|
52
|
-
pos += self._pos
|
|
53
|
-
elif whence == os.SEEK_END:
|
|
54
|
-
pos = self._size - pos
|
|
55
|
-
|
|
56
|
-
if pos < 0 or pos > self._size:
|
|
57
|
-
raise ValueError("Seek out of range in Block instance")
|
|
58
|
-
|
|
59
|
-
self._pos = pos
|
|
60
|
-
|
|
61
|
-
def read(self, size_or_format):
|
|
62
|
-
if isinstance(size_or_format, (str, bytes)):
|
|
63
|
-
size = struct.calcsize(size_or_format)
|
|
64
|
-
fmt = size_or_format
|
|
65
|
-
else:
|
|
66
|
-
size = size_or_format
|
|
67
|
-
fmt = None
|
|
68
|
-
|
|
69
|
-
if self._size - self._pos < size:
|
|
70
|
-
raise BuddyError("Unable to read %lu bytes in block" % size)
|
|
71
|
-
|
|
72
|
-
data = self._value[self._pos : self._pos + size]
|
|
73
|
-
self._pos += size
|
|
74
|
-
|
|
75
|
-
if fmt is not None:
|
|
76
|
-
if isinstance(data, bytearray):
|
|
77
|
-
return struct.unpack_from(fmt, bytes(data))
|
|
78
|
-
else:
|
|
79
|
-
return struct.unpack(fmt, data)
|
|
80
|
-
else:
|
|
81
|
-
return data
|
|
82
|
-
|
|
83
|
-
def write(self, data_or_format, *args):
|
|
84
|
-
if len(args):
|
|
85
|
-
data = struct.pack(data_or_format, *args)
|
|
86
|
-
else:
|
|
87
|
-
data = data_or_format
|
|
88
|
-
|
|
89
|
-
if self._pos + len(data) > self._size:
|
|
90
|
-
raise ValueError("Attempt to write past end of Block")
|
|
91
|
-
|
|
92
|
-
self._value[self._pos : self._pos + len(data)] = data
|
|
93
|
-
self._pos += len(data)
|
|
94
|
-
|
|
95
|
-
self._dirty = True
|
|
96
|
-
|
|
97
|
-
def insert(self, data_or_format, *args):
|
|
98
|
-
if len(args):
|
|
99
|
-
data = struct.pack(data_or_format, *args)
|
|
100
|
-
else:
|
|
101
|
-
data = data_or_format
|
|
102
|
-
|
|
103
|
-
del self._value[-len(data) :]
|
|
104
|
-
self._value[self._pos : self._pos] = data
|
|
105
|
-
self._pos += len(data)
|
|
106
|
-
|
|
107
|
-
self._dirty = True
|
|
108
|
-
|
|
109
|
-
def delete(self, size):
|
|
110
|
-
if self._pos + size > self._size:
|
|
111
|
-
raise ValueError("Attempt to delete past end of Block")
|
|
112
|
-
del self._value[self._pos : self._pos + size]
|
|
113
|
-
self._value += b"\0" * size
|
|
114
|
-
self._dirty = True
|
|
115
|
-
|
|
116
|
-
def __str__(self):
|
|
117
|
-
return binascii.b2a_hex(self._value)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class Allocator:
|
|
121
|
-
def __init__(self, the_file):
|
|
122
|
-
self._file = the_file
|
|
123
|
-
self._dirty = False
|
|
124
|
-
|
|
125
|
-
self._file.seek(0)
|
|
126
|
-
|
|
127
|
-
# Read the header
|
|
128
|
-
(magic1, magic2, offset, size, offset2, self._unknown1) = self.read(
|
|
129
|
-
-4, ">I4sIII16s"
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
if magic2 != b"Bud1" or magic1 != 1:
|
|
133
|
-
raise BuddyError("Not a buddy file")
|
|
134
|
-
|
|
135
|
-
if offset != offset2:
|
|
136
|
-
raise BuddyError("Root addresses differ")
|
|
137
|
-
|
|
138
|
-
self._root = Block(self, offset, size)
|
|
139
|
-
|
|
140
|
-
# Read the block offsets
|
|
141
|
-
count, self._unknown2 = self._root.read(">II")
|
|
142
|
-
self._offsets = []
|
|
143
|
-
c = (count + 255) & ~255
|
|
144
|
-
while c:
|
|
145
|
-
self._offsets += self._root.read(">256I")
|
|
146
|
-
c -= 256
|
|
147
|
-
self._offsets = self._offsets[:count]
|
|
148
|
-
|
|
149
|
-
# Read the TOC
|
|
150
|
-
self._toc = {}
|
|
151
|
-
count = self._root.read(">I")[0]
|
|
152
|
-
for n in range(count):
|
|
153
|
-
nlen = self._root.read("B")[0]
|
|
154
|
-
name = bytes(self._root.read(nlen))
|
|
155
|
-
value = self._root.read(">I")[0]
|
|
156
|
-
self._toc[name] = value
|
|
157
|
-
|
|
158
|
-
# Read the free lists
|
|
159
|
-
self._free = []
|
|
160
|
-
for n in range(32):
|
|
161
|
-
count = self._root.read(">I")
|
|
162
|
-
self._free.append(list(self._root.read(">%uI" % count)))
|
|
163
|
-
|
|
164
|
-
@classmethod
|
|
165
|
-
def open(cls, file_or_name, mode="r+"):
|
|
166
|
-
if isinstance(file_or_name, str):
|
|
167
|
-
if "b" not in mode:
|
|
168
|
-
mode = mode[:1] + "b" + mode[1:]
|
|
169
|
-
f = open(file_or_name, mode)
|
|
170
|
-
else:
|
|
171
|
-
f = file_or_name
|
|
172
|
-
|
|
173
|
-
if "w" in mode:
|
|
174
|
-
# Create an empty file in this case
|
|
175
|
-
f.truncate()
|
|
176
|
-
|
|
177
|
-
# An empty root block needs 1264 bytes:
|
|
178
|
-
#
|
|
179
|
-
# 0 4 offset count
|
|
180
|
-
# 4 4 unknown
|
|
181
|
-
# 8 4 root block offset (2048)
|
|
182
|
-
# 12 255 * 4 padding (offsets are in multiples of 256)
|
|
183
|
-
# 1032 4 toc count (0)
|
|
184
|
-
# 1036 228 free list
|
|
185
|
-
# total 1264
|
|
186
|
-
|
|
187
|
-
# The free list will contain the following:
|
|
188
|
-
#
|
|
189
|
-
# 0 5 * 4 no blocks of width less than 5
|
|
190
|
-
# 20 6 * 8 1 block each of widths 5 to 10
|
|
191
|
-
# 68 4 no blocks of width 11 (allocated for the root)
|
|
192
|
-
# 72 19 * 8 1 block each of widths 12 to 30
|
|
193
|
-
# 224 4 no blocks of width 31
|
|
194
|
-
# total 228
|
|
195
|
-
#
|
|
196
|
-
# (The reason for this layout is that we allocate 2**5 bytes for
|
|
197
|
-
# the header, which splits the initial 2GB region into every size
|
|
198
|
-
# below 2**31, including *two* blocks of size 2**5, one of which
|
|
199
|
-
# we take. The root block itself then needs a block of size
|
|
200
|
-
# 2**11. Conveniently, each of these initial blocks will be
|
|
201
|
-
# located at offset 2**n where n is its width.)
|
|
202
|
-
|
|
203
|
-
# Write the header
|
|
204
|
-
header = struct.pack(
|
|
205
|
-
b">I4sIII16s",
|
|
206
|
-
1,
|
|
207
|
-
b"Bud1",
|
|
208
|
-
2048,
|
|
209
|
-
1264,
|
|
210
|
-
2048,
|
|
211
|
-
b"\x00\x00\x10\x0c"
|
|
212
|
-
b"\x00\x00\x00\x87"
|
|
213
|
-
b"\x00\x00\x20\x0b"
|
|
214
|
-
b"\x00\x00\x00\x00",
|
|
215
|
-
)
|
|
216
|
-
f.write(header)
|
|
217
|
-
f.write(b"\0" * 2016)
|
|
218
|
-
|
|
219
|
-
# Write the root block
|
|
220
|
-
free_list = [struct.pack(b">5I", 0, 0, 0, 0, 0)]
|
|
221
|
-
for n in range(5, 11):
|
|
222
|
-
free_list.append(struct.pack(b">II", 1, 2**n))
|
|
223
|
-
free_list.append(struct.pack(b">I", 0))
|
|
224
|
-
for n in range(12, 31):
|
|
225
|
-
free_list.append(struct.pack(b">II", 1, 2**n))
|
|
226
|
-
free_list.append(struct.pack(b">I", 0))
|
|
227
|
-
|
|
228
|
-
root = b"".join(
|
|
229
|
-
[
|
|
230
|
-
struct.pack(b">III", 1, 0, 2048 | 5),
|
|
231
|
-
struct.pack(b">I", 0) * 255,
|
|
232
|
-
struct.pack(b">I", 0),
|
|
233
|
-
]
|
|
234
|
-
+ free_list
|
|
235
|
-
)
|
|
236
|
-
f.write(root)
|
|
237
|
-
|
|
238
|
-
return Allocator(f)
|
|
239
|
-
|
|
240
|
-
def __enter__(self):
|
|
241
|
-
return self
|
|
242
|
-
|
|
243
|
-
def __exit__(self, exc_type, exc_value, traceback):
|
|
244
|
-
self.close()
|
|
245
|
-
|
|
246
|
-
def close(self):
|
|
247
|
-
self.flush()
|
|
248
|
-
self._file.close()
|
|
249
|
-
|
|
250
|
-
def flush(self):
|
|
251
|
-
if self._dirty:
|
|
252
|
-
size = self._root_block_size()
|
|
253
|
-
self.allocate(size, 0)
|
|
254
|
-
with self.get_block(0) as rblk:
|
|
255
|
-
self._write_root_block_into(rblk)
|
|
256
|
-
|
|
257
|
-
addr = self._offsets[0]
|
|
258
|
-
offset = addr & ~0x1F
|
|
259
|
-
size = 1 << (addr & 0x1F)
|
|
260
|
-
|
|
261
|
-
self._file.seek(0, os.SEEK_SET)
|
|
262
|
-
self._file.write(
|
|
263
|
-
struct.pack(
|
|
264
|
-
b">I4sIII16s", 1, b"Bud1", offset, size, offset, self._unknown1
|
|
265
|
-
)
|
|
266
|
-
)
|
|
267
|
-
|
|
268
|
-
self._dirty = False
|
|
269
|
-
|
|
270
|
-
self._file.flush()
|
|
271
|
-
|
|
272
|
-
def read(self, offset, size_or_format):
|
|
273
|
-
"""Read data at `offset', or raise an exception.
|
|
274
|
-
|
|
275
|
-
`size_or_format' may either be a byte count, in which case we
|
|
276
|
-
return raw data, or a format string for `struct.unpack', in
|
|
277
|
-
which case we work out the size and unpack the data before
|
|
278
|
-
returning it.
|
|
279
|
-
"""
|
|
280
|
-
# N.B. There is a fixed offset of four bytes(!)
|
|
281
|
-
self._file.seek(offset + 4, os.SEEK_SET)
|
|
282
|
-
|
|
283
|
-
if isinstance(size_or_format, str):
|
|
284
|
-
size = struct.calcsize(size_or_format)
|
|
285
|
-
fmt = size_or_format
|
|
286
|
-
else:
|
|
287
|
-
size = size_or_format
|
|
288
|
-
fmt = None
|
|
289
|
-
|
|
290
|
-
ret = self._file.read(size)
|
|
291
|
-
if len(ret) < size:
|
|
292
|
-
ret += b"\0" * (size - len(ret))
|
|
293
|
-
|
|
294
|
-
if fmt is not None:
|
|
295
|
-
if isinstance(ret, bytearray):
|
|
296
|
-
ret = struct.unpack_from(fmt, bytes(ret))
|
|
297
|
-
else:
|
|
298
|
-
ret = struct.unpack(fmt, ret)
|
|
299
|
-
|
|
300
|
-
return ret
|
|
301
|
-
|
|
302
|
-
def write(self, offset, data_or_format, *args):
|
|
303
|
-
"""Write data at `offset', or raise an exception.
|
|
304
|
-
|
|
305
|
-
`data_or_format' may either be the data to write, or a format
|
|
306
|
-
string for `struct.pack', in which case we pack the additional
|
|
307
|
-
arguments and write the resulting data.
|
|
308
|
-
"""
|
|
309
|
-
# N.B. There is a fixed offset of four bytes(!)
|
|
310
|
-
self._file.seek(offset + 4, os.SEEK_SET)
|
|
311
|
-
|
|
312
|
-
if len(args):
|
|
313
|
-
data = struct.pack(data_or_format, *args)
|
|
314
|
-
else:
|
|
315
|
-
data = data_or_format
|
|
316
|
-
|
|
317
|
-
self._file.write(data)
|
|
318
|
-
|
|
319
|
-
def get_block(self, block):
|
|
320
|
-
try:
|
|
321
|
-
addr = self._offsets[block]
|
|
322
|
-
except IndexError:
|
|
323
|
-
return None
|
|
324
|
-
|
|
325
|
-
offset = addr & ~0x1F
|
|
326
|
-
size = 1 << (addr & 0x1F)
|
|
327
|
-
|
|
328
|
-
return Block(self, offset, size)
|
|
329
|
-
|
|
330
|
-
def _root_block_size(self):
|
|
331
|
-
"""Return the number of bytes required by the root block."""
|
|
332
|
-
# Offsets
|
|
333
|
-
size = 8
|
|
334
|
-
size += 4 * ((len(self._offsets) + 255) & ~255)
|
|
335
|
-
|
|
336
|
-
# TOC
|
|
337
|
-
size += 4
|
|
338
|
-
size += sum([5 + len(s) for s in self._toc])
|
|
339
|
-
|
|
340
|
-
# Free list
|
|
341
|
-
size += sum([4 + 4 * len(fl) for fl in self._free])
|
|
342
|
-
|
|
343
|
-
return size
|
|
344
|
-
|
|
345
|
-
def _write_root_block_into(self, block):
|
|
346
|
-
# Offsets
|
|
347
|
-
block.write(">II", len(self._offsets), self._unknown2)
|
|
348
|
-
block.write(">%uI" % len(self._offsets), *self._offsets)
|
|
349
|
-
extra = len(self._offsets) & 255
|
|
350
|
-
if extra:
|
|
351
|
-
block.write(b"\0\0\0\0" * (256 - extra))
|
|
352
|
-
|
|
353
|
-
# TOC
|
|
354
|
-
keys = list(self._toc.keys())
|
|
355
|
-
keys.sort()
|
|
356
|
-
|
|
357
|
-
block.write(">I", len(keys))
|
|
358
|
-
for k in keys:
|
|
359
|
-
block.write("B", len(k))
|
|
360
|
-
block.write(k)
|
|
361
|
-
block.write(">I", self._toc[k])
|
|
362
|
-
|
|
363
|
-
# Free list
|
|
364
|
-
for w, f in enumerate(self._free):
|
|
365
|
-
block.write(">I", len(f))
|
|
366
|
-
if len(f):
|
|
367
|
-
block.write(">%uI" % len(f), *f)
|
|
368
|
-
|
|
369
|
-
def _buddy(self, offset, width):
|
|
370
|
-
f = self._free[width]
|
|
371
|
-
b = offset ^ (1 << width)
|
|
372
|
-
|
|
373
|
-
try:
|
|
374
|
-
ndx = f.index(b)
|
|
375
|
-
except ValueError:
|
|
376
|
-
ndx = None
|
|
377
|
-
|
|
378
|
-
return (f, b, ndx)
|
|
379
|
-
|
|
380
|
-
def _release(self, offset, width):
|
|
381
|
-
# Coalesce
|
|
382
|
-
while True:
|
|
383
|
-
f, b, ndx = self._buddy(offset, width)
|
|
384
|
-
|
|
385
|
-
if ndx is None:
|
|
386
|
-
break
|
|
387
|
-
|
|
388
|
-
offset &= b
|
|
389
|
-
width += 1
|
|
390
|
-
del f[ndx]
|
|
391
|
-
|
|
392
|
-
# Add to the list
|
|
393
|
-
bisect.insort(f, offset)
|
|
394
|
-
|
|
395
|
-
# Mark as dirty
|
|
396
|
-
self._dirty = True
|
|
397
|
-
|
|
398
|
-
def _alloc(self, width):
|
|
399
|
-
w = width
|
|
400
|
-
while not self._free[w]:
|
|
401
|
-
w += 1
|
|
402
|
-
while w > width:
|
|
403
|
-
offset = self._free[w].pop(0)
|
|
404
|
-
w -= 1
|
|
405
|
-
self._free[w] = [offset, offset ^ (1 << w)]
|
|
406
|
-
self._dirty = True
|
|
407
|
-
return self._free[width].pop(0)
|
|
408
|
-
|
|
409
|
-
def allocate(self, bytes, block=None):
|
|
410
|
-
"""Allocate or reallocate a block such that it has space for at least
|
|
411
|
-
`bytes' bytes."""
|
|
412
|
-
if block is None:
|
|
413
|
-
# Find the first unused block
|
|
414
|
-
try:
|
|
415
|
-
block = self._offsets.index(0)
|
|
416
|
-
except ValueError:
|
|
417
|
-
block = len(self._offsets)
|
|
418
|
-
self._offsets.append(0)
|
|
419
|
-
|
|
420
|
-
# Compute block width
|
|
421
|
-
width = max(bytes.bit_length(), 5)
|
|
422
|
-
|
|
423
|
-
addr = self._offsets[block]
|
|
424
|
-
offset = addr & ~0x1F
|
|
425
|
-
|
|
426
|
-
if addr:
|
|
427
|
-
blkwidth = addr & 0x1F
|
|
428
|
-
if blkwidth == width:
|
|
429
|
-
return block
|
|
430
|
-
self._release(offset, width)
|
|
431
|
-
self._offsets[block] = 0
|
|
432
|
-
|
|
433
|
-
offset = self._alloc(width)
|
|
434
|
-
self._offsets[block] = offset | width
|
|
435
|
-
return block
|
|
436
|
-
|
|
437
|
-
def release(self, block):
|
|
438
|
-
addr = self._offsets[block]
|
|
439
|
-
|
|
440
|
-
if addr:
|
|
441
|
-
width = addr & 0x1F
|
|
442
|
-
offset = addr & ~0x1F
|
|
443
|
-
self._release(offset, width)
|
|
444
|
-
|
|
445
|
-
if block == len(self._offsets):
|
|
446
|
-
del self._offsets[block]
|
|
447
|
-
else:
|
|
448
|
-
self._offsets[block] = 0
|
|
449
|
-
|
|
450
|
-
def __len__(self):
|
|
451
|
-
return len(self._toc)
|
|
452
|
-
|
|
453
|
-
def __getitem__(self, key):
|
|
454
|
-
if not isinstance(key, str):
|
|
455
|
-
raise TypeError("Keys must be of string type")
|
|
456
|
-
if not isinstance(key, bytes):
|
|
457
|
-
key = key.encode("latin_1")
|
|
458
|
-
return self._toc[key]
|
|
459
|
-
|
|
460
|
-
def __setitem__(self, key, value):
|
|
461
|
-
if not isinstance(key, str):
|
|
462
|
-
raise TypeError("Keys must be of string type")
|
|
463
|
-
if not isinstance(key, bytes):
|
|
464
|
-
key = key.encode("latin_1")
|
|
465
|
-
self._toc[key] = value
|
|
466
|
-
self._dirty = True
|
|
467
|
-
|
|
468
|
-
def __delitem__(self, key):
|
|
469
|
-
if not isinstance(key, str):
|
|
470
|
-
raise TypeError("Keys must be of string type")
|
|
471
|
-
if not isinstance(key, bytes):
|
|
472
|
-
key = key.encode("latin_1")
|
|
473
|
-
del self._toc[key]
|
|
474
|
-
self._dirty = True
|
|
475
|
-
|
|
476
|
-
def iterkeys(self):
|
|
477
|
-
return self._toc.keys()
|
|
478
|
-
|
|
479
|
-
def keys(self):
|
|
480
|
-
return self._toc.keys()
|
|
481
|
-
|
|
482
|
-
def __iter__(self):
|
|
483
|
-
return self._toc.keys()
|
|
484
|
-
|
|
485
|
-
def __contains__(self, key):
|
|
486
|
-
return key in self._toc
|