dmg-builder 26.0.17 → 26.0.19

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