dmg-builder 26.0.16 → 26.0.18

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,59 +1,38 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
1
  # This file implements the Apple "bookmark" format, which is the replacement
4
2
  # for the old-fashioned alias format. The details of this format were
5
3
  # reverse engineered; some things are still not entirely clear.
6
4
  #
7
- from __future__ import unicode_literals, print_function
8
-
9
- import struct
10
- import uuid
11
5
  import datetime
12
6
  import os
7
+ import struct
13
8
  import sys
14
- import pprint
15
-
16
- try:
17
- from urlparse import urljoin
18
- except ImportError:
19
- from urllib.parse import urljoin
9
+ import uuid
10
+ from urllib.parse import urljoin
20
11
 
21
- if sys.platform == 'darwin':
12
+ if sys.platform == "darwin":
22
13
  from . import osx
23
14
 
24
- def iteritems(x):
25
- return x.iteritems()
26
-
27
- try:
28
- unicode
29
- except NameError:
30
- unicode = str
31
- long = int
32
- xrange = range
33
- def iteritems(x):
34
- return x.items()
35
-
36
- from .utils import *
15
+ from .utils import osx_epoch
37
16
 
38
- BMK_DATA_TYPE_MASK = 0xffffff00
39
- BMK_DATA_SUBTYPE_MASK = 0x000000ff
17
+ BMK_DATA_TYPE_MASK = 0xFFFFFF00
18
+ BMK_DATA_SUBTYPE_MASK = 0x000000FF
40
19
 
41
- BMK_STRING = 0x0100
42
- BMK_DATA = 0x0200
43
- BMK_NUMBER = 0x0300
44
- BMK_DATE = 0x0400
20
+ BMK_STRING = 0x0100
21
+ BMK_DATA = 0x0200
22
+ BMK_NUMBER = 0x0300
23
+ BMK_DATE = 0x0400
45
24
  BMK_BOOLEAN = 0x0500
46
- BMK_ARRAY = 0x0600
47
- BMK_DICT = 0x0700
48
- BMK_UUID = 0x0800
49
- BMK_URL = 0x0900
50
- BMK_NULL = 0x0a00
25
+ BMK_ARRAY = 0x0600
26
+ BMK_DICT = 0x0700
27
+ BMK_UUID = 0x0800
28
+ BMK_URL = 0x0900
29
+ BMK_NULL = 0x0A00
51
30
 
52
31
  BMK_ST_ZERO = 0x0000
53
- BMK_ST_ONE = 0x0001
32
+ BMK_ST_ONE = 0x0001
54
33
 
55
34
  BMK_BOOLEAN_ST_FALSE = 0x0000
56
- BMK_BOOLEAN_ST_TRUE = 0x0001
35
+ BMK_BOOLEAN_ST_TRUE = 0x0001
57
36
 
58
37
  # Subtypes for BMK_NUMBER are really CFNumberType values
59
38
  kCFNumberSInt8Type = 1
@@ -74,123 +53,123 @@ kCFNumberNSIntegerType = 15
74
53
  kCFNumberCGFloatType = 16
75
54
 
76
55
  # Resource property flags (from CFURLPriv.h)
77
- kCFURLResourceIsRegularFile = 0x00000001
78
- kCFURLResourceIsDirectory = 0x00000002
79
- kCFURLResourceIsSymbolicLink = 0x00000004
80
- kCFURLResourceIsVolume = 0x00000008
81
- kCFURLResourceIsPackage = 0x00000010
82
- kCFURLResourceIsSystemImmutable = 0x00000020
83
- kCFURLResourceIsUserImmutable = 0x00000040
84
- kCFURLResourceIsHidden = 0x00000080
56
+ kCFURLResourceIsRegularFile = 0x00000001
57
+ kCFURLResourceIsDirectory = 0x00000002
58
+ kCFURLResourceIsSymbolicLink = 0x00000004
59
+ kCFURLResourceIsVolume = 0x00000008
60
+ kCFURLResourceIsPackage = 0x00000010
61
+ kCFURLResourceIsSystemImmutable = 0x00000020
62
+ kCFURLResourceIsUserImmutable = 0x00000040
63
+ kCFURLResourceIsHidden = 0x00000080
85
64
  kCFURLResourceHasHiddenExtension = 0x00000100
86
- kCFURLResourceIsApplication = 0x00000200
87
- kCFURLResourceIsCompressed = 0x00000400
65
+ kCFURLResourceIsApplication = 0x00000200
66
+ kCFURLResourceIsCompressed = 0x00000400
88
67
  kCFURLResourceIsSystemCompressed = 0x00000400
89
- kCFURLCanSetHiddenExtension = 0x00000800
90
- kCFURLResourceIsReadable = 0x00001000
91
- kCFURLResourceIsWriteable = 0x00002000
92
- kCFURLResourceIsExecutable = 0x00004000
93
- kCFURLIsAliasFile = 0x00008000
94
- kCFURLIsMountTrigger = 0x00010000
68
+ kCFURLCanSetHiddenExtension = 0x00000800
69
+ kCFURLResourceIsReadable = 0x00001000
70
+ kCFURLResourceIsWriteable = 0x00002000
71
+ kCFURLResourceIsExecutable = 0x00004000
72
+ kCFURLIsAliasFile = 0x00008000
73
+ kCFURLIsMountTrigger = 0x00010000
95
74
 
96
75
  # Volume property flags (from CFURLPriv.h)
97
- kCFURLVolumeIsLocal = 0x1 #
98
- kCFURLVolumeIsAutomount = 0x2 #
99
- kCFURLVolumeDontBrowse = 0x4 #
100
- kCFURLVolumeIsReadOnly = 0x8 #
101
- kCFURLVolumeIsQuarantined = 0x10
102
- kCFURLVolumeIsEjectable = 0x20 #
103
- kCFURLVolumeIsRemovable = 0x40 #
104
- kCFURLVolumeIsInternal = 0x80 #
105
- kCFURLVolumeIsExternal = 0x100 #
106
- kCFURLVolumeIsDiskImage = 0x200 #
107
- kCFURLVolumeIsFileVault = 0x400
108
- kCFURLVolumeIsLocaliDiskMirror = 0x800
109
- kCFURLVolumeIsiPod = 0x1000 #
110
- kCFURLVolumeIsiDisk = 0x2000
111
- kCFURLVolumeIsCD = 0x4000
112
- kCFURLVolumeIsDVD = 0x8000
113
- kCFURLVolumeIsDeviceFileSystem = 0x10000
114
- kCFURLVolumeSupportsPersistentIDs = 0x100000000
115
- kCFURLVolumeSupportsSearchFS = 0x200000000
116
- kCFURLVolumeSupportsExchange = 0x400000000
76
+ kCFURLVolumeIsLocal = 0x1
77
+ kCFURLVolumeIsAutomount = 0x2
78
+ kCFURLVolumeDontBrowse = 0x4
79
+ kCFURLVolumeIsReadOnly = 0x8
80
+ kCFURLVolumeIsQuarantined = 0x10
81
+ kCFURLVolumeIsEjectable = 0x20
82
+ kCFURLVolumeIsRemovable = 0x40
83
+ kCFURLVolumeIsInternal = 0x80
84
+ kCFURLVolumeIsExternal = 0x100
85
+ kCFURLVolumeIsDiskImage = 0x200
86
+ kCFURLVolumeIsFileVault = 0x400
87
+ kCFURLVolumeIsLocaliDiskMirror = 0x800
88
+ kCFURLVolumeIsiPod = 0x1000
89
+ kCFURLVolumeIsiDisk = 0x2000
90
+ kCFURLVolumeIsCD = 0x4000
91
+ kCFURLVolumeIsDVD = 0x8000
92
+ kCFURLVolumeIsDeviceFileSystem = 0x10000
93
+ kCFURLVolumeSupportsPersistentIDs = 0x100000000
94
+ kCFURLVolumeSupportsSearchFS = 0x200000000
95
+ kCFURLVolumeSupportsExchange = 0x400000000
117
96
  # reserved 0x800000000
118
- kCFURLVolumeSupportsSymbolicLinks = 0x1000000000
119
- kCFURLVolumeSupportsDenyModes = 0x2000000000
120
- kCFURLVolumeSupportsCopyFile = 0x4000000000
121
- kCFURLVolumeSupportsReadDirAttr = 0x8000000000
122
- kCFURLVolumeSupportsJournaling = 0x10000000000
123
- kCFURLVolumeSupportsRename = 0x20000000000
124
- kCFURLVolumeSupportsFastStatFS = 0x40000000000
125
- kCFURLVolumeSupportsCaseSensitiveNames = 0x80000000000
126
- kCFURLVolumeSupportsCasePreservedNames = 0x100000000000
127
- kCFURLVolumeSupportsFLock = 0x200000000000
128
- kCFURLVolumeHasNoRootDirectoryTimes = 0x400000000000
129
- kCFURLVolumeSupportsExtendedSecurity = 0x800000000000
130
- kCFURLVolumeSupports2TBFileSize = 0x1000000000000
131
- kCFURLVolumeSupportsHardLinks = 0x2000000000000
132
- kCFURLVolumeSupportsMandatoryByteRangeLocks = 0x4000000000000
133
- kCFURLVolumeSupportsPathFromID = 0x8000000000000
97
+ kCFURLVolumeSupportsSymbolicLinks = 0x1000000000
98
+ kCFURLVolumeSupportsDenyModes = 0x2000000000
99
+ kCFURLVolumeSupportsCopyFile = 0x4000000000
100
+ kCFURLVolumeSupportsReadDirAttr = 0x8000000000
101
+ kCFURLVolumeSupportsJournaling = 0x10000000000
102
+ kCFURLVolumeSupportsRename = 0x20000000000
103
+ kCFURLVolumeSupportsFastStatFS = 0x40000000000
104
+ kCFURLVolumeSupportsCaseSensitiveNames = 0x80000000000
105
+ kCFURLVolumeSupportsCasePreservedNames = 0x100000000000
106
+ kCFURLVolumeSupportsFLock = 0x200000000000
107
+ kCFURLVolumeHasNoRootDirectoryTimes = 0x400000000000
108
+ kCFURLVolumeSupportsExtendedSecurity = 0x800000000000
109
+ kCFURLVolumeSupports2TBFileSize = 0x1000000000000
110
+ kCFURLVolumeSupportsHardLinks = 0x2000000000000
111
+ kCFURLVolumeSupportsMandatoryByteRangeLocks = 0x4000000000000
112
+ kCFURLVolumeSupportsPathFromID = 0x8000000000000
134
113
  # reserved 0x10000000000000
135
- kCFURLVolumeIsJournaling = 0x20000000000000
136
- kCFURLVolumeSupportsSparseFiles = 0x40000000000000
137
- kCFURLVolumeSupportsZeroRuns = 0x80000000000000
138
- kCFURLVolumeSupportsVolumeSizes = 0x100000000000000
139
- kCFURLVolumeSupportsRemoteEvents = 0x200000000000000
140
- kCFURLVolumeSupportsHiddenFiles = 0x400000000000000
141
- kCFURLVolumeSupportsDecmpFSCompression = 0x800000000000000
142
- kCFURLVolumeHas64BitObjectIDs = 0x1000000000000000
143
- kCFURLVolumePropertyFlagsAll = 0xffffffffffffffff
114
+ kCFURLVolumeIsJournaling = 0x20000000000000
115
+ kCFURLVolumeSupportsSparseFiles = 0x40000000000000
116
+ kCFURLVolumeSupportsZeroRuns = 0x80000000000000
117
+ kCFURLVolumeSupportsVolumeSizes = 0x100000000000000
118
+ kCFURLVolumeSupportsRemoteEvents = 0x200000000000000
119
+ kCFURLVolumeSupportsHiddenFiles = 0x400000000000000
120
+ kCFURLVolumeSupportsDecmpFSCompression = 0x800000000000000
121
+ kCFURLVolumeHas64BitObjectIDs = 0x1000000000000000
122
+ kCFURLVolumePropertyFlagsAll = 0xFFFFFFFFFFFFFFFF
144
123
 
145
124
  BMK_URL_ST_ABSOLUTE = 0x0001
146
125
  BMK_URL_ST_RELATIVE = 0x0002
147
126
 
148
127
  # Bookmark keys
149
- kBookmarkURL = 0x1003 # A URL
150
- kBookmarkPath = 0x1004 # Array of path components
151
- kBookmarkCNIDPath = 0x1005 # Array of CNIDs
152
- kBookmarkFileProperties = 0x1010 # (CFURL rp flags,
153
- # CFURL rp flags asked for,
154
- # 8 bytes NULL)
155
- kBookmarkFileName = 0x1020
156
- kBookmarkFileID = 0x1030
157
- kBookmarkFileCreationDate = 0x1040
158
- # = 0x1054 # ?
159
- # = 0x1055 # ?
160
- # = 0x1056 # ?
161
- # = 0x1101 # ?
162
- # = 0x1102 # ?
163
- kBookmarkTOCPath = 0x2000 # A list of (TOC id, ?) pairs
164
- kBookmarkVolumePath = 0x2002
165
- kBookmarkVolumeURL = 0x2005
166
- kBookmarkVolumeName = 0x2010
167
- kBookmarkVolumeUUID = 0x2011 # Stored (perversely) as a string
168
- kBookmarkVolumeSize = 0x2012
128
+ kBookmarkURL = 0x1003 # A URL
129
+ kBookmarkPath = 0x1004 # Array of path components
130
+ kBookmarkCNIDPath = 0x1005 # Array of CNIDs
131
+ kBookmarkFileProperties = (
132
+ 0x1010 # (CFURL rp flags, CFURL rp flags asked for, 8 bytes NULL)
133
+ )
134
+ kBookmarkFileName = 0x1020
135
+ kBookmarkFileID = 0x1030
136
+ kBookmarkFileCreationDate = 0x1040
137
+ # = 0x1054 # ?
138
+ # = 0x1055 # ?
139
+ # = 0x1056 # ?
140
+ # = 0x1101 # ?
141
+ # = 0x1102 # ?
142
+ kBookmarkTOCPath = 0x2000 # A list of (TOC id, ?) pairs
143
+ kBookmarkVolumePath = 0x2002
144
+ kBookmarkVolumeURL = 0x2005
145
+ kBookmarkVolumeName = 0x2010
146
+ kBookmarkVolumeUUID = 0x2011 # Stored (perversely) as a string
147
+ kBookmarkVolumeSize = 0x2012
169
148
  kBookmarkVolumeCreationDate = 0x2013
170
- kBookmarkVolumeProperties = 0x2020 # (CFURL vp flags,
171
- # CFURL vp flags asked for,
172
- # 8 bytes NULL)
173
- kBookmarkVolumeIsRoot = 0x2030 # True if volume is FS root
174
- kBookmarkVolumeBookmark = 0x2040 # Embedded bookmark for disk image (TOC id)
175
- kBookmarkVolumeMountPoint = 0x2050 # A URL
176
- # = 0x2070
177
- kBookmarkContainingFolder = 0xc001 # Index of containing folder in path
178
- kBookmarkUserName = 0xc011 # User that created bookmark
179
- kBookmarkUID = 0xc012 # UID that created bookmark
180
- kBookmarkWasFileReference = 0xd001 # True if the URL was a file reference
181
- kBookmarkCreationOptions = 0xd010
182
- kBookmarkURLLengths = 0xe003 # See below
183
- kBookmarkDisplayName = 0xf017
184
- kBookmarkIconData = 0xf020
185
- kBookmarkIconRef = 0xf021
186
- kBookmarkTypeBindingData = 0xf022
187
- kBookmarkCreationTime = 0xf030
188
- kBookmarkSandboxRwExtension = 0xf080
189
- kBookmarkSandboxRoExtension = 0xf081
190
- kBookmarkAliasData = 0xfe00
149
+ kBookmarkVolumeProperties = (
150
+ 0x2020 # (CFURL vp flags, CFURL vp flags asked for, 8 bytes NULL)
151
+ )
152
+ kBookmarkVolumeIsRoot = 0x2030 # True if volume is FS root
153
+ kBookmarkVolumeBookmark = 0x2040 # Embedded bookmark for disk image (TOC id)
154
+ kBookmarkVolumeMountPoint = 0x2050 # A URL
155
+ # = 0x2070
156
+ kBookmarkContainingFolder = 0xC001 # Index of containing folder in path
157
+ kBookmarkUserName = 0xC011 # User that created bookmark
158
+ kBookmarkUID = 0xC012 # UID that created bookmark
159
+ kBookmarkWasFileReference = 0xD001 # True if the URL was a file reference
160
+ kBookmarkCreationOptions = 0xD010
161
+ kBookmarkURLLengths = 0xE003 # See below
162
+ kBookmarkDisplayName = 0xF017
163
+ kBookmarkIconData = 0xF020
164
+ kBookmarkIconRef = 0xF021
165
+ kBookmarkTypeBindingData = 0xF022
166
+ kBookmarkCreationTime = 0xF030
167
+ kBookmarkSandboxRwExtension = 0xF080
168
+ kBookmarkSandboxRoExtension = 0xF081
169
+ kBookmarkAliasData = 0xFE00
191
170
 
192
171
  # Alias for backwards compatibility
193
- kBookmarkSecurityExtension = kBookmarkSandboxRwExtension
172
+ kBookmarkSecurityExtension = kBookmarkSandboxRwExtension
194
173
 
195
174
  # kBookmarkURLLengths is an array that is set if the URL encoded by the
196
175
  # bookmark had a base URL; in that case, each entry is the length of the
@@ -205,15 +184,16 @@ kBookmarkSecurityExtension = kBookmarkSandboxRwExtension
205
184
  # would result in [1, 2, 1, 1]
206
185
 
207
186
 
208
- class Data (object):
187
+ class Data:
209
188
  def __init__(self, bytedata=None):
210
189
  #: The bytes, stored as a byte string
211
190
  self.bytes = bytes(bytedata)
212
191
 
213
192
  def __repr__(self):
214
- return 'Data(%r)' % self.bytes
193
+ return "Data(%r)" % self.bytes
215
194
 
216
- class URL (object):
195
+
196
+ class URL:
217
197
  def __init__(self, base, rel=None):
218
198
  if rel is not None:
219
199
  #: The base URL, if any (a :class:`URL`)
@@ -230,13 +210,13 @@ class URL (object):
230
210
  if self.base is None:
231
211
  return self.relative
232
212
  else:
233
- base_abs = self.base.absolute
234
213
  return urljoin(self.base.absolute, self.relative)
235
214
 
236
215
  def __repr__(self):
237
- return 'URL(%r)' % self.absolute
216
+ return "URL(%r)" % self.absolute
217
+
238
218
 
239
- class Bookmark (object):
219
+ class Bookmark:
240
220
  def __init__(self, tocs=None):
241
221
  if tocs is None:
242
222
  #: The TOCs for this Bookmark
@@ -248,39 +228,39 @@ class Bookmark (object):
248
228
  def _get_item(cls, data, hdrsize, offset):
249
229
  offset += hdrsize
250
230
  if offset > len(data) - 8:
251
- raise ValueError('Offset out of range')
231
+ raise ValueError("Offset out of range")
252
232
 
253
- length,typecode = struct.unpack(b'<II', data[offset:offset+8])
233
+ length, typecode = struct.unpack(b"<II", data[offset : offset + 8])
254
234
 
255
235
  if len(data) - offset < 8 + length:
256
- raise ValueError('Data item truncated')
236
+ raise ValueError("Data item truncated")
257
237
 
258
- databytes = data[offset+8:offset+8+length]
238
+ databytes = data[offset + 8 : offset + 8 + length]
259
239
 
260
240
  dsubtype = typecode & BMK_DATA_SUBTYPE_MASK
261
241
  dtype = typecode & BMK_DATA_TYPE_MASK
262
242
 
263
243
  if dtype == BMK_STRING:
264
- return databytes.decode('utf-8')
244
+ return databytes.decode("utf-8")
265
245
  elif dtype == BMK_DATA:
266
246
  return Data(databytes)
267
247
  elif dtype == BMK_NUMBER:
268
248
  if dsubtype == kCFNumberSInt8Type:
269
249
  return ord(databytes[0])
270
250
  elif dsubtype == kCFNumberSInt16Type:
271
- return struct.unpack(b'<h', databytes)[0]
251
+ return struct.unpack(b"<h", databytes)[0]
272
252
  elif dsubtype == kCFNumberSInt32Type:
273
- return struct.unpack(b'<i', databytes)[0]
253
+ return struct.unpack(b"<i", databytes)[0]
274
254
  elif dsubtype == kCFNumberSInt64Type:
275
- return struct.unpack(b'<q', databytes)[0]
255
+ return struct.unpack(b"<q", databytes)[0]
276
256
  elif dsubtype == kCFNumberFloat32Type:
277
- return struct.unpack(b'<f', databytes)[0]
257
+ return struct.unpack(b"<f", databytes)[0]
278
258
  elif dsubtype == kCFNumberFloat64Type:
279
- return struct.unpack(b'<d', databytes)[0]
259
+ return struct.unpack(b"<d", databytes)[0]
280
260
  elif dtype == BMK_DATE:
281
261
  # Yes, dates really are stored as *BIG-endian* doubles; everything
282
262
  # else is little-endian
283
- secs = datetime.timedelta(seconds=struct.unpack(b'>d', databytes)[0])
263
+ secs = datetime.timedelta(seconds=struct.unpack(b">d", databytes)[0])
284
264
  return osx_epoch + secs
285
265
  elif dtype == BMK_BOOLEAN:
286
266
  if dsubtype == BMK_BOOLEAN_ST_TRUE:
@@ -291,22 +271,22 @@ class Bookmark (object):
291
271
  return uuid.UUID(bytes=databytes)
292
272
  elif dtype == BMK_URL:
293
273
  if dsubtype == BMK_URL_ST_ABSOLUTE:
294
- return URL(databytes.decode('utf-8'))
274
+ return URL(databytes.decode("utf-8"))
295
275
  elif dsubtype == BMK_URL_ST_RELATIVE:
296
- baseoff,reloff = struct.unpack(b'<II', databytes)
276
+ baseoff, reloff = struct.unpack(b"<II", databytes)
297
277
  base = cls._get_item(data, hdrsize, baseoff)
298
278
  rel = cls._get_item(data, hdrsize, reloff)
299
279
  return URL(base, rel)
300
280
  elif dtype == BMK_ARRAY:
301
281
  result = []
302
- for aoff in xrange(offset+8,offset+8+length,4):
303
- eltoff, = struct.unpack(b'<I', data[aoff:aoff+4])
282
+ for aoff in range(offset + 8, offset + 8 + length, 4):
283
+ (eltoff,) = struct.unpack(b"<I", data[aoff : aoff + 4])
304
284
  result.append(cls._get_item(data, hdrsize, eltoff))
305
285
  return result
306
286
  elif dtype == BMK_DICT:
307
287
  result = {}
308
- for eoff in xrange(offset+8,offset+8+length,8):
309
- keyoff,valoff = struct.unpack(b'<II', data[eoff:eoff+8])
288
+ for eoff in range(offset + 8, offset + 8 + length, 8):
289
+ keyoff, valoff = struct.unpack(b"<II", data[eoff : eoff + 8])
310
290
  key = cls._get_item(data, hdrsize, keyoff)
311
291
  val = cls._get_item(data, hdrsize, valoff)
312
292
  result[key] = val
@@ -314,7 +294,7 @@ class Bookmark (object):
314
294
  elif dtype == BMK_NULL:
315
295
  return None
316
296
 
317
- print('Unknown data type %08x' % typecode)
297
+ print("Unknown data type %08x" % typecode)
318
298
  return (typecode, databytes)
319
299
 
320
300
  @classmethod
@@ -322,58 +302,56 @@ class Bookmark (object):
322
302
  """Create a :class:`Bookmark` given byte data."""
323
303
 
324
304
  if len(data) < 16:
325
- raise ValueError('Not a bookmark file (too short)')
305
+ raise ValueError("Not a bookmark file (too short)")
326
306
 
327
307
  if isinstance(data, bytearray):
328
308
  data = bytes(data)
329
309
 
330
- magic,size,dummy,hdrsize = struct.unpack(b'<4sIII', data[0:16])
310
+ magic, size, dummy, hdrsize = struct.unpack(b"<4sIII", data[0:16])
331
311
 
332
- if magic not in (b'book', b'alis'):
333
- raise ValueError('Not a bookmark file (bad magic) %r' % magic)
312
+ if magic not in (b"book", b"alis"):
313
+ raise ValueError("Not a bookmark file (bad magic) %r" % magic)
334
314
 
335
315
  if hdrsize < 16:
336
- raise ValueError('Not a bookmark file (header size too short)')
316
+ raise ValueError("Not a bookmark file (header size too short)")
337
317
 
338
318
  if hdrsize > size:
339
- raise ValueError('Not a bookmark file (header size too large)')
319
+ raise ValueError("Not a bookmark file (header size too large)")
340
320
 
341
321
  if size != len(data):
342
- raise ValueError('Not a bookmark file (truncated)')
322
+ raise ValueError("Not a bookmark file (truncated)")
343
323
 
344
- tocoffset, = struct.unpack(b'<I', data[hdrsize:hdrsize+4])
324
+ (tocoffset,) = struct.unpack(b"<I", data[hdrsize : hdrsize + 4])
345
325
 
346
326
  tocs = []
347
327
 
348
328
  while tocoffset != 0:
349
329
  tocbase = hdrsize + tocoffset
350
- if tocoffset > size - hdrsize \
351
- or size - tocbase < 20:
352
- raise ValueError('TOC offset out of range')
330
+ if (tocoffset > size - hdrsize) or (size - tocbase < 20):
331
+ raise ValueError("TOC offset out of range")
353
332
 
354
- tocsize,tocmagic,tocid,nexttoc,toccount \
355
- = struct.unpack(b'<IIIII',
356
- data[tocbase:tocbase+20])
333
+ (tocsize, tocmagic, tocid, nexttoc, toccount) = struct.unpack(
334
+ b"<IIIII", data[tocbase : tocbase + 20]
335
+ )
357
336
 
358
- if tocmagic != 0xfffffffe:
337
+ if tocmagic != 0xFFFFFFFE:
359
338
  break
360
339
 
361
340
  tocsize += 8
362
341
 
363
342
  if size - tocbase < tocsize:
364
- raise ValueError('TOC truncated')
343
+ raise ValueError("TOC truncated")
365
344
 
366
345
  if tocsize < 12 * toccount:
367
- raise ValueError('TOC entries overrun TOC size')
346
+ raise ValueError("TOC entries overrun TOC size")
368
347
 
369
348
  toc = {}
370
- for n in xrange(0,toccount):
349
+ for n in range(0, toccount):
371
350
  ebase = tocbase + 20 + 12 * n
372
- eid,eoffset,edummy = struct.unpack(b'<III',
373
- data[ebase:ebase+12])
351
+ eid, eoffset, edummy = struct.unpack(b"<III", data[ebase : ebase + 12])
374
352
 
375
353
  if eid & 0x80000000:
376
- eid = cls._get_item(data, hdrsize, eid & 0x7fffffff)
354
+ eid = cls._get_item(data, hdrsize, eid & 0x7FFFFFFF)
377
355
 
378
356
  toc[eid] = cls._get_item(data, hdrsize, eoffset)
379
357
 
@@ -384,10 +362,10 @@ class Bookmark (object):
384
362
  return cls(tocs)
385
363
 
386
364
  def __getitem__(self, key):
387
- for tid,toc in self.tocs:
365
+ for tid, toc in self.tocs:
388
366
  if key in toc:
389
367
  return toc[key]
390
- raise KeyError('Key not found')
368
+ raise KeyError("Key not found")
391
369
 
392
370
  def __setitem__(self, key, value):
393
371
  if len(self.tocs) == 0:
@@ -397,7 +375,7 @@ class Bookmark (object):
397
375
  def get(self, key, default=None):
398
376
  """Lookup the value for a given key, returning a default if not
399
377
  present."""
400
- for tid,toc in self.tocs:
378
+ for tid, toc in self.tocs:
401
379
  if key in toc:
402
380
  return toc[key]
403
381
  return default
@@ -405,87 +383,89 @@ class Bookmark (object):
405
383
  @classmethod
406
384
  def _encode_item(cls, item, offset):
407
385
  if item is True:
408
- result = struct.pack(b'<II', 0, BMK_BOOLEAN | BMK_BOOLEAN_ST_TRUE)
386
+ result = struct.pack(b"<II", 0, BMK_BOOLEAN | BMK_BOOLEAN_ST_TRUE)
409
387
  elif item is False:
410
- result = struct.pack(b'<II', 0, BMK_BOOLEAN | BMK_BOOLEAN_ST_FALSE)
411
- elif isinstance(item, unicode):
412
- encoded = item.encode('utf-8')
413
- result = (struct.pack(b'<II', len(encoded), BMK_STRING | BMK_ST_ONE)
414
- + encoded)
388
+ result = struct.pack(b"<II", 0, BMK_BOOLEAN | BMK_BOOLEAN_ST_FALSE)
389
+ elif isinstance(item, str):
390
+ encoded = item.encode("utf-8")
391
+ result = (
392
+ struct.pack(b"<II", len(encoded), BMK_STRING | BMK_ST_ONE) + encoded
393
+ )
415
394
  elif isinstance(item, bytes):
416
- result = (struct.pack(b'<II', len(item), BMK_STRING | BMK_ST_ONE)
417
- + item)
395
+ result = struct.pack(b"<II", len(item), BMK_STRING | BMK_ST_ONE) + item
418
396
  elif isinstance(item, Data):
419
- result = (struct.pack(b'<II', len(item.bytes),
420
- BMK_DATA | BMK_ST_ONE)
421
- + bytes(item.bytes))
397
+ result = struct.pack(
398
+ b"<II", len(item.bytes), BMK_DATA | BMK_ST_ONE
399
+ ) + bytes(item.bytes)
422
400
  elif isinstance(item, bytearray):
423
- result = (struct.pack(b'<II', len(item),
424
- BMK_DATA | BMK_ST_ONE)
425
- + bytes(item))
426
- elif isinstance(item, int) or isinstance(item, long):
427
- if item > -0x80000000 and item < 0x7fffffff:
428
- result = struct.pack(b'<IIi', 4,
429
- BMK_NUMBER | kCFNumberSInt32Type, item)
401
+ result = struct.pack(b"<II", len(item), BMK_DATA | BMK_ST_ONE) + bytes(item)
402
+ elif isinstance(item, int):
403
+ if item > -0x80000000 and item < 0x7FFFFFFF:
404
+ result = struct.pack(b"<IIi", 4, BMK_NUMBER | kCFNumberSInt32Type, item)
430
405
  else:
431
- result = struct.pack(b'<IIq', 8,
432
- BMK_NUMBER | kCFNumberSInt64Type, item)
406
+ result = struct.pack(b"<IIq", 8, BMK_NUMBER | kCFNumberSInt64Type, item)
433
407
  elif isinstance(item, float):
434
- result = struct.pack(b'<IId', 8,
435
- BMK_NUMBER | kCFNumberFloat64Type, item)
408
+ result = struct.pack(b"<IId", 8, BMK_NUMBER | kCFNumberFloat64Type, item)
436
409
  elif isinstance(item, datetime.datetime):
437
410
  secs = item - osx_epoch
438
- result = struct.pack(b'<II', 8, BMK_DATE | BMK_ST_ZERO) \
439
- + struct.pack(b'>d', float(secs.total_seconds()))
411
+ result = struct.pack(b"<II", 8, BMK_DATE | BMK_ST_ZERO) + struct.pack(
412
+ b">d", float(secs.total_seconds())
413
+ )
414
+
440
415
  elif isinstance(item, uuid.UUID):
441
- result = struct.pack(b'<II', 16, BMK_UUID | BMK_ST_ONE) \
442
- + item.bytes
416
+ result = struct.pack(b"<II", 16, BMK_UUID | BMK_ST_ONE) + item.bytes
443
417
  elif isinstance(item, URL):
444
418
  if item.base:
445
419
  baseoff = offset + 16
446
420
  reloff, baseenc = cls._encode_item(item.base, baseoff)
447
421
  xoffset, relenc = cls._encode_item(item.relative, reloff)
448
- result = b''.join([
449
- struct.pack(b'<IIII', 8, BMK_URL | BMK_URL_ST_RELATIVE,
450
- baseoff, reloff),
451
- baseenc,
452
- relenc])
422
+ result = b"".join(
423
+ [
424
+ struct.pack(
425
+ b"<IIII", 8, BMK_URL | BMK_URL_ST_RELATIVE, baseoff, reloff
426
+ ),
427
+ baseenc,
428
+ relenc,
429
+ ]
430
+ )
453
431
  else:
454
- encoded = item.relative.encode('utf-8')
455
- result = struct.pack(b'<II', len(encoded),
456
- BMK_URL | BMK_URL_ST_ABSOLUTE) + encoded
432
+ encoded = item.relative.encode("utf-8")
433
+ result = (
434
+ struct.pack(b"<II", len(encoded), BMK_URL | BMK_URL_ST_ABSOLUTE)
435
+ + encoded
436
+ )
457
437
  elif isinstance(item, list):
458
438
  ioffset = offset + 8 + len(item) * 4
459
- result = [struct.pack(b'<II', len(item) * 4, BMK_ARRAY | BMK_ST_ONE)]
439
+ result = [struct.pack(b"<II", len(item) * 4, BMK_ARRAY | BMK_ST_ONE)]
460
440
  enc = []
461
441
  for elt in item:
462
- result.append(struct.pack(b'<I', ioffset))
442
+ result.append(struct.pack(b"<I", ioffset))
463
443
  ioffset, ienc = cls._encode_item(elt, ioffset)
464
444
  enc.append(ienc)
465
- result = b''.join(result + enc)
445
+ result = b"".join(result + enc)
466
446
  elif isinstance(item, dict):
467
447
  ioffset = offset + 8 + len(item) * 8
468
- result = [struct.pack(b'<II', len(item) * 8, BMK_DICT | BMK_ST_ONE)]
448
+ result = [struct.pack(b"<II", len(item) * 8, BMK_DICT | BMK_ST_ONE)]
469
449
  enc = []
470
- for k,v in iteritems(item):
471
- result.append(struct.pack(b'<I', ioffset))
450
+ for k, v in item.items():
451
+ result.append(struct.pack(b"<I", ioffset))
472
452
  ioffset, ienc = cls._encode_item(k, ioffset)
473
453
  enc.append(ienc)
474
- result.append(struct.pack(b'<I', ioffset))
454
+ result.append(struct.pack(b"<I", ioffset))
475
455
  ioffset, ienc = cls._encode_item(v, ioffset)
476
456
  enc.append(ienc)
477
- result = b''.join(result + enc)
457
+ result = b"".join(result + enc)
478
458
  elif item is None:
479
- result = struct.pack(b'<II', 0, BMK_NULL | BMK_ST_ONE)
459
+ result = struct.pack(b"<II", 0, BMK_NULL | BMK_ST_ONE)
480
460
  else:
481
- raise ValueError('Unknown item type when encoding: %s' % item)
461
+ raise ValueError("Unknown item type when encoding: %s" % item)
482
462
 
483
463
  offset += len(result)
484
464
 
485
465
  # Pad to a multiple of 4 bytes
486
466
  if offset & 3:
487
467
  extra = 4 - (offset & 3)
488
- result += b'\0' * extra
468
+ result += b"\0" * extra
489
469
  offset += extra
490
470
 
491
471
  return (offset, result)
@@ -498,11 +478,11 @@ class Bookmark (object):
498
478
  offset = 4 # For the offset to the first TOC
499
479
 
500
480
  # Generate the data and build the TOCs
501
- for tid,toc in self.tocs:
481
+ for tid, toc in self.tocs:
502
482
  entries = []
503
483
 
504
- for k,v in iteritems(toc):
505
- if isinstance(k, (str, unicode)):
484
+ for k, v in toc.items():
485
+ if isinstance(k, str):
506
486
  noffset = offset
507
487
  voffset, enc = self._encode_item(k, offset)
508
488
  result.append(enc)
@@ -518,39 +498,52 @@ class Bookmark (object):
518
498
  # binary search to find data
519
499
  entries.sort()
520
500
 
521
- tocs.append((tid, b''.join([struct.pack(b'<III',k,o,0)
522
- for k,o in entries])))
501
+ tocs.append(
502
+ (tid, b"".join([struct.pack(b"<III", k, o, 0) for k, o in entries]))
503
+ )
523
504
 
524
505
  first_toc_offset = offset
525
506
 
526
507
  # Now generate the TOC headers
527
- for ndx,toc in enumerate(tocs):
508
+ for ndx, toc in enumerate(tocs):
528
509
  tid, data = toc
529
510
  if ndx == len(tocs) - 1:
530
511
  next_offset = 0
531
512
  else:
532
513
  next_offset = offset + 20 + len(data)
533
514
 
534
- result.append(struct.pack(b'<IIIII', len(data) - 8,
535
- 0xfffffffe,
536
- tid,
537
- next_offset,
538
- len(data) // 12))
515
+ result.append(
516
+ struct.pack(
517
+ b"<IIIII",
518
+ len(data) - 8,
519
+ 0xFFFFFFFE,
520
+ tid,
521
+ next_offset,
522
+ len(data) // 12,
523
+ )
524
+ )
539
525
  result.append(data)
540
526
 
541
527
  offset += 20 + len(data)
542
528
 
543
529
  # Finally, add the header (and the first TOC offset, which isn't part
544
530
  # of the header, but goes just after it)
545
- header = struct.pack(b'<4sIIIQQQQI', b'book',
546
- offset + 48,
547
- 0x10040000,
548
- 48,
549
- 0, 0, 0, 0, first_toc_offset)
531
+ header = struct.pack(
532
+ b"<4sIIIQQQQI",
533
+ b"book",
534
+ offset + 48,
535
+ 0x10040000,
536
+ 48,
537
+ 0,
538
+ 0,
539
+ 0,
540
+ 0,
541
+ first_toc_offset,
542
+ )
550
543
 
551
544
  result.insert(0, header)
552
545
 
553
- return b''.join(result)
546
+ return b"".join(result)
554
547
 
555
548
  @classmethod
556
549
  def for_file(cls, path):
@@ -558,14 +551,16 @@ class Bookmark (object):
558
551
 
559
552
  # Find the filesystem
560
553
  st = osx.statfs(path)
561
- vol_path = st.f_mntonname.decode('utf-8')
554
+ vol_path = st.f_mntonname.decode("utf-8")
562
555
 
563
556
  # Grab its attributes
564
- attrs = [osx.ATTR_CMN_CRTIME,
565
- osx.ATTR_VOL_SIZE
566
- | osx.ATTR_VOL_NAME
567
- | osx.ATTR_VOL_UUID,
568
- 0, 0, 0]
557
+ attrs = [
558
+ osx.ATTR_CMN_CRTIME,
559
+ osx.ATTR_VOL_SIZE | osx.ATTR_VOL_NAME | osx.ATTR_VOL_UUID,
560
+ 0,
561
+ 0,
562
+ 0,
563
+ ]
569
564
  volinfo = osx.getattrlist(vol_path, attrs, 0)
570
565
 
571
566
  vol_crtime = volinfo[0]
@@ -574,9 +569,13 @@ class Bookmark (object):
574
569
  vol_uuid = volinfo[3]
575
570
 
576
571
  # Also grab various attributes of the file
577
- attrs = [(osx.ATTR_CMN_OBJTYPE
578
- | osx.ATTR_CMN_CRTIME
579
- | osx.ATTR_CMN_FILEID), 0, 0, 0, 0]
572
+ attrs = [
573
+ (osx.ATTR_CMN_OBJTYPE | osx.ATTR_CMN_CRTIME | osx.ATTR_CMN_FILEID),
574
+ 0,
575
+ 0,
576
+ 0,
577
+ 0,
578
+ ]
580
579
  info = osx.getattrlist(path, attrs, osx.FSOPT_NOFOLLOW)
581
580
 
582
581
  cnid = info[2]
@@ -603,7 +602,7 @@ class Bookmark (object):
603
602
  head, tail = os.path.split(head)
604
603
  dirname = os.path.join(curdir, dirname)
605
604
 
606
- foldername = os.path.basename(dirname)
605
+ # ?? foldername = os.path.basename(dirname)
607
606
 
608
607
  rel_path = os.path.relpath(path, vol_path)
609
608
 
@@ -627,9 +626,15 @@ class Bookmark (object):
627
626
 
628
627
  url_lengths = [relcount, len(name_path) - relcount]
629
628
 
630
- fileprops = Data(struct.pack(b'<QQQ', flags, 0x0f, 0))
631
- volprops = Data(struct.pack(b'<QQQ', 0x81 | kCFURLVolumeSupportsPersistentIDs,
632
- 0x13ef | kCFURLVolumeSupportsPersistentIDs, 0))
629
+ fileprops = Data(struct.pack(b"<QQQ", flags, 0x0F, 0))
630
+ volprops = Data(
631
+ struct.pack(
632
+ b"<QQQ",
633
+ 0x81 | kCFURLVolumeSupportsPersistentIDs,
634
+ 0x13EF | kCFURLVolumeSupportsPersistentIDs,
635
+ 0,
636
+ )
637
+ )
633
638
 
634
639
  toc = {
635
640
  kBookmarkPath: name_path,
@@ -638,8 +643,8 @@ class Bookmark (object):
638
643
  kBookmarkFileProperties: fileprops,
639
644
  kBookmarkContainingFolder: len(name_path) - 2,
640
645
  kBookmarkVolumePath: vol_path,
641
- kBookmarkVolumeIsRoot: vol_path == '/',
642
- kBookmarkVolumeURL: URL('file://' + vol_path),
646
+ kBookmarkVolumeIsRoot: vol_path == "/",
647
+ kBookmarkVolumeURL: URL("file://" + vol_path),
643
648
  kBookmarkVolumeName: vol_name,
644
649
  kBookmarkVolumeSize: vol_size,
645
650
  kBookmarkVolumeCreationDate: vol_crtime,
@@ -647,7 +652,7 @@ class Bookmark (object):
647
652
  kBookmarkVolumeProperties: volprops,
648
653
  kBookmarkCreationOptions: 512,
649
654
  kBookmarkWasFileReference: True,
650
- kBookmarkUserName: 'unknown',
655
+ kBookmarkUserName: "unknown",
651
656
  kBookmarkUID: 99,
652
657
  }
653
658
 
@@ -657,16 +662,16 @@ class Bookmark (object):
657
662
  return Bookmark([(1, toc)])
658
663
 
659
664
  def __repr__(self):
660
- result = ['Bookmark([']
661
- for tid,toc in self.tocs:
662
- result.append('(0x%x, {\n' % tid)
663
- for k,v in iteritems(toc):
664
- if isinstance(k, (str, unicode)):
665
+ result = ["Bookmark(["]
666
+ for tid, toc in self.tocs:
667
+ result.append("(0x%x, {\n" % tid)
668
+ for k, v in toc.items():
669
+ if isinstance(k, str):
665
670
  kf = repr(k)
666
671
  else:
667
- kf = '0x%04x' % k
668
- result.append(' %s: %r\n' % (kf, v))
669
- result.append('}),\n')
670
- result.append('])')
672
+ kf = "0x%04x" % k
673
+ result.append(f" {kf}: {v!r}\n")
674
+ result.append("}),\n")
675
+ result.append("])")
671
676
 
672
- return ''.join(result)
677
+ return "".join(result)