Utilities/binplistlib.py

changeset 1965
96f5a76e1845
parent 1720
201622cf8a01
child 2302
f29e9405c851
equal deleted inserted replaced
1964:6a6a53f2d086 1965:96f5a76e1845
19 To generate plists with NSData/CFData values, wrap the values with the 19 To generate plists with NSData/CFData values, wrap the values with the
20 Data object. The value must be a bytes object. 20 Data object. The value must be a bytes object.
21 21
22 Date values can only be datetime.datetime objects. 22 Date values can only be datetime.datetime objects.
23 23
24 The exceptions InvalidPlistException and NotBinaryPlistException may be 24 The exceptions InvalidPlistException and NotBinaryPlistException may be
25 thrown to indicate that the data cannot be serialized or deserialized as 25 thrown to indicate that the data cannot be serialized or deserialized as
26 a binary plist. 26 a binary plist.
27 27
28 Plist generation example: 28 Plist generation example:
29 <pre> 29 <pre>
66 # this list of conditions and the following disclaimer. 66 # this list of conditions and the following disclaimer.
67 # * Redistributions in binary form must reproduce the above copyright 67 # * Redistributions in binary form must reproduce the above copyright
68 # notice, this list of conditions and the following disclaimer in the 68 # notice, this list of conditions and the following disclaimer in the
69 # documentation and/or other materials provided with the distribution. 69 # documentation and/or other materials provided with the distribution.
70 # * Neither the name of biplist nor the names of its contributors may be 70 # * Neither the name of biplist nor the names of its contributors may be
71 # used to endorse or promote products derived from this software without 71 # used to endorse or promote products derived from this software without
72 # specific prior written permission. 72 # specific prior written permission.
73 # 73 #
74 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 74 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
75 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 75 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 76 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
154 raise InvalidPlistException(e) 154 raise InvalidPlistException(e)
155 if didOpen: 155 if didOpen:
156 pathOrFile.close() 156 pathOrFile.close()
157 return result 157 return result
158 158
159
159 def writePlist(rootObject, pathOrFile, binary=True): 160 def writePlist(rootObject, pathOrFile, binary=True):
160 """ 161 """
161 Module function to write a plist file. 162 Module function to write a plist file.
162 163
163 @param rootObject reference to the object to be written 164 @param rootObject reference to the object to be written
176 writer.writeRoot(rootObject) 177 writer.writeRoot(rootObject)
177 if didOpen: 178 if didOpen:
178 pathOrFile.close() 179 pathOrFile.close()
179 return 180 return
180 181
182
181 def readPlistFromBytes(data): 183 def readPlistFromBytes(data):
182 """ 184 """
183 Module function to read from a plist bytes object. 185 Module function to read from a plist bytes object.
184 186
185 @param data plist data (bytes) 187 @param data plist data (bytes)
186 @return reference to the read object 188 @return reference to the read object
187 @exception InvalidPlistException raised to signal an invalid plist file 189 @exception InvalidPlistException raised to signal an invalid plist file
188 """ 190 """
189 return readPlist(BytesIO(data)) 191 return readPlist(BytesIO(data))
192
190 193
191 def writePlistToBytes(rootObject, binary=True): 194 def writePlistToBytes(rootObject, binary=True):
192 """ 195 """
193 Module function to write a plist bytes object. 196 Module function to write a plist bytes object.
194 197
201 io = BytesIO() 204 io = BytesIO()
202 writer = PlistWriter(io) 205 writer = PlistWriter(io)
203 writer.writeRoot(rootObject) 206 writer.writeRoot(rootObject)
204 return io.getvalue() 207 return io.getvalue()
205 208
209
206 def is_stream_binary_plist(stream): 210 def is_stream_binary_plist(stream):
207 """ 211 """
208 Module function to check, if the stream is a binary plist. 212 Module function to check, if the stream is a binary plist.
209 213
210 @param stream plist stream (file object) 214 @param stream plist stream (file object)
220 PlistTrailer = namedtuple('PlistTrailer', 224 PlistTrailer = namedtuple('PlistTrailer',
221 'offsetSize, objectRefSize, offsetCount, topLevelObjectNumber, offsetTableOffset') 225 'offsetSize, objectRefSize, offsetCount, topLevelObjectNumber, offsetTableOffset')
222 PlistByteCounts = namedtuple('PlistByteCounts', 226 PlistByteCounts = namedtuple('PlistByteCounts',
223 'nullBytes, boolBytes, intBytes, realBytes, dateBytes, dataBytes, stringBytes, ' 227 'nullBytes, boolBytes, intBytes, realBytes, dateBytes, dataBytes, stringBytes, '
224 'uidBytes, arrayBytes, setBytes, dictBytes') 228 'uidBytes, arrayBytes, setBytes, dictBytes')
229
225 230
226 class PlistReader(object): 231 class PlistReader(object):
227 """ 232 """
228 Class implementing the plist reader. 233 Class implementing the plist reader.
229 """ 234 """
277 trailerContents = self.contents[-32:] 282 trailerContents = self.contents[-32:]
278 try: 283 try:
279 self.trailer = PlistTrailer._make(unpack("!xxxxxxBBQQQ", trailerContents)) 284 self.trailer = PlistTrailer._make(unpack("!xxxxxxBBQQQ", trailerContents))
280 offset_size = self.trailer.offsetSize * self.trailer.offsetCount 285 offset_size = self.trailer.offsetSize * self.trailer.offsetCount
281 offset = self.trailer.offsetTableOffset 286 offset = self.trailer.offsetTableOffset
282 offset_contents = self.contents[offset:offset+offset_size] 287 offset_contents = self.contents[offset:offset + offset_size]
283 offset_i = 0 288 offset_i = 0
284 while offset_i < self.trailer.offsetCount: 289 while offset_i < self.trailer.offsetCount:
285 begin = self.trailer.offsetSize*offset_i 290 begin = self.trailer.offsetSize * offset_i
286 tmp_contents = offset_contents[begin:begin+self.trailer.offsetSize] 291 tmp_contents = offset_contents[begin:begin + self.trailer.offsetSize]
287 tmp_sized = self.getSizedInteger(tmp_contents, self.trailer.offsetSize) 292 tmp_sized = self.getSizedInteger(tmp_contents, self.trailer.offsetSize)
288 self.offsets.append(tmp_sized) 293 self.offsets.append(tmp_sized)
289 offset_i += 1 294 offset_i += 1
290 self.setCurrentOffsetToObjectNumber(self.trailer.topLevelObjectNumber) 295 self.setCurrentOffsetToObjectNumber(self.trailer.topLevelObjectNumber)
291 result = self.readObject() 296 result = self.readObject()
306 Private method to read the object data. 311 Private method to read the object data.
307 312
308 @return unpickled object 313 @return unpickled object
309 """ 314 """
310 result = None 315 result = None
311 tmp_byte = self.contents[self.currentOffset:self.currentOffset+1] 316 tmp_byte = self.contents[self.currentOffset:self.currentOffset + 1]
312 marker_byte = unpack("!B", tmp_byte)[0] 317 marker_byte = unpack("!B", tmp_byte)[0]
313 format = (marker_byte >> 4) & 0x0f 318 format = (marker_byte >> 4) & 0x0f
314 extra = marker_byte & 0x0f 319 extra = marker_byte & 0x0f
315 self.currentOffset += 1 320 self.currentOffset += 1
316 321
327 elif extra == 0b1000: 332 elif extra == 0b1000:
328 result = False 333 result = False
329 elif extra == 0b1001: 334 elif extra == 0b1001:
330 result = True 335 result = True
331 elif extra == 0b1111: 336 elif extra == 0b1111:
332 pass # fill byte 337 pass # fill byte
333 else: 338 else:
334 raise InvalidPlistException( 339 raise InvalidPlistException(
335 "Invalid object found at offset: {0}".format(self.currentOffset - 1)) 340 "Invalid object found at offset: {0}".format(self.currentOffset - 1))
336 # int 341 # int
337 elif format == 0b0001: 342 elif format == 0b0001:
369 result = set(self.readArray(extra)) 374 result = set(self.readArray(extra))
370 # dict 375 # dict
371 elif format == 0b1101: 376 elif format == 0b1101:
372 extra = proc_extra(extra) 377 extra = proc_extra(extra)
373 result = self.readDict(extra) 378 result = self.readDict(extra)
374 else: 379 else:
375 raise InvalidPlistException( 380 raise InvalidPlistException(
376 "Invalid object found: {{format: {0}, extra: {1}}}".format( 381 "Invalid object found: {{format: {0}, extra: {1}}}".format(
377 bin(format), bin(extra))) 382 bin(format), bin(extra)))
378 return result 383 return result
379 384
384 @param bytes length of the object (integer) 389 @param bytes length of the object (integer)
385 @return integer object 390 @return integer object
386 """ 391 """
387 result = 0 392 result = 0
388 original_offset = self.currentOffset 393 original_offset = self.currentOffset
389 data = self.contents[self.currentOffset:self.currentOffset+bytes] 394 data = self.contents[self.currentOffset:self.currentOffset + bytes]
390 result = self.getSizedInteger(data, bytes) 395 result = self.getSizedInteger(data, bytes)
391 self.currentOffset = original_offset + bytes 396 self.currentOffset = original_offset + bytes
392 return result 397 return result
393 398
394 def readReal(self, length): 399 def readReal(self, length):
398 @param length length of the object (integer) 403 @param length length of the object (integer)
399 @return float object 404 @return float object
400 """ 405 """
401 result = 0.0 406 result = 0.0
402 to_read = pow(2, length) 407 to_read = pow(2, length)
403 data = self.contents[self.currentOffset:self.currentOffset+to_read] 408 data = self.contents[self.currentOffset:self.currentOffset + to_read]
404 if length == 2: # 4 bytes 409 if length == 2: # 4 bytes
405 result = unpack('>f', data)[0] 410 result = unpack('>f', data)[0]
406 elif length == 3: # 8 bytes 411 elif length == 3: # 8 bytes
407 result = unpack('>d', data)[0] 412 result = unpack('>d', data)[0]
408 else: 413 else:
409 raise InvalidPlistException( 414 raise InvalidPlistException(
410 "Unknown real of length {0} bytes".format(to_read)) 415 "Unknown real of length {0} bytes".format(to_read))
411 return result 416 return result
412 417
413 def readRefs(self, count): 418 def readRefs(self, count):
414 """ 419 """
415 Private method to read References. 420 Private method to read References.
416 421
417 @param count amount of the references (integer) 422 @param count amount of the references (integer)
418 @return list of references (list of integers) 423 @return list of references (list of integers)
419 """ 424 """
420 refs = [] 425 refs = []
421 i = 0 426 i = 0
422 while i < count: 427 while i < count:
423 fragment = self.contents[ 428 fragment = self.contents[
424 self.currentOffset:self.currentOffset+self.trailer.objectRefSize] 429 self.currentOffset:self.currentOffset + self.trailer.objectRefSize]
425 ref = self.getSizedInteger(fragment, len(fragment)) 430 ref = self.getSizedInteger(fragment, len(fragment))
426 refs.append(ref) 431 refs.append(ref)
427 self.currentOffset += self.trailer.objectRefSize 432 self.currentOffset += self.trailer.objectRefSize
428 i += 1 433 i += 1
429 return refs 434 return refs
471 476
472 @param length length of the string (integer) 477 @param length length of the string (integer)
473 @return ASCII encoded string 478 @return ASCII encoded string
474 """ 479 """
475 result = str(unpack("!{0}s".format(length), 480 result = str(unpack("!{0}s".format(length),
476 self.contents[self.currentOffset:self.currentOffset+length])[0], 481 self.contents[self.currentOffset:self.currentOffset + length])[0],
477 encoding="ascii") 482 encoding="ascii")
478 self.currentOffset += length 483 self.currentOffset += length
479 return result 484 return result
480 485
481 def readUnicode(self, length): 486 def readUnicode(self, length):
483 Private method to read an Unicode encoded string. 488 Private method to read an Unicode encoded string.
484 489
485 @param length length of the string (integer) 490 @param length length of the string (integer)
486 @return unicode encoded string 491 @return unicode encoded string
487 """ 492 """
488 actual_length = length*2 493 actual_length = length * 2
489 data = self.contents[self.currentOffset:self.currentOffset+actual_length] 494 data = self.contents[self.currentOffset:self.currentOffset + actual_length]
490 # unpack not needed?!! data = unpack(">%ds" % (actual_length), data)[0] 495 # unpack not needed?!! data = unpack(">%ds" % (actual_length), data)[0]
491 self.currentOffset += actual_length 496 self.currentOffset += actual_length
492 return data.decode('utf_16_be') 497 return data.decode('utf_16_be')
493 498
494 def readDate(self): 499 def readDate(self):
496 Private method to read a date. 501 Private method to read a date.
497 502
498 @return date object (datetime.datetime) 503 @return date object (datetime.datetime)
499 """ 504 """
500 global apple_reference_date_offset 505 global apple_reference_date_offset
501 result = unpack(">d", self.contents[self.currentOffset:self.currentOffset+8])[0] 506 result = unpack(">d", self.contents[self.currentOffset:self.currentOffset + 8])[0]
502 result = datetime.datetime.utcfromtimestamp(result + apple_reference_date_offset) 507 result = datetime.datetime.utcfromtimestamp(result + apple_reference_date_offset)
503 self.currentOffset += 8 508 self.currentOffset += 8
504 return result 509 return result
505 510
506 def readData(self, length): 511 def readData(self, length):
508 Private method to read some bytes. 513 Private method to read some bytes.
509 514
510 @param length number of bytes to read (integer) 515 @param length number of bytes to read (integer)
511 @return Data object 516 @return Data object
512 """ 517 """
513 result = self.contents[self.currentOffset:self.currentOffset+length] 518 result = self.contents[self.currentOffset:self.currentOffset + length]
514 self.currentOffset += length 519 self.currentOffset += length
515 return Data(result) 520 return Data(result)
516 521
517 def readUid(self, length): 522 def readUid(self, length):
518 """ 523 """
519 Private method to read a UID. 524 Private method to read a UID.
520 525
521 @param length length of the UID (integer) 526 @param length length of the UID (integer)
522 @return Uid object 527 @return Uid object
523 """ 528 """
524 return Uid(self.readInteger(length+1)) 529 return Uid(self.readInteger(length + 1))
525 530
526 def getSizedInteger(self, data, bytes): 531 def getSizedInteger(self, data, bytes):
527 """ 532 """
528 Private method to read an integer of a specific size. 533 Private method to read an integer of a specific size.
529 534
542 result = unpack('>q', data)[0] 547 result = unpack('>q', data)[0]
543 else: 548 else:
544 raise InvalidPlistException("Encountered integer longer than 8 bytes.") 549 raise InvalidPlistException("Encountered integer longer than 8 bytes.")
545 return result 550 return result
546 551
552
547 class HashableWrapper(object): 553 class HashableWrapper(object):
548 """ 554 """
549 Class wrapping a hashable value. 555 Class wrapping a hashable value.
550 """ 556 """
551 def __init__(self, value): 557 def __init__(self, value):
552 self.value = value 558 self.value = value
559
553 def __repr__(self): 560 def __repr__(self):
554 return "<HashableWrapper: %s>" % [self.value] 561 return "<HashableWrapper: %s>" % [self.value]
555 562
563
556 class BoolWrapper(object): 564 class BoolWrapper(object):
557 """ 565 """
558 Class wrapping a boolean value. 566 Class wrapping a boolean value.
559 """ 567 """
560 def __init__(self, value): 568 def __init__(self, value):
561 self.value = value 569 self.value = value
570
562 def __repr__(self): 571 def __repr__(self):
563 return "<BoolWrapper: %s>" % self.value 572 return "<BoolWrapper: %s>" % self.value
573
564 574
565 class PlistWriter(object): 575 class PlistWriter(object):
566 """ 576 """
567 Class implementing the plist writer. 577 Class implementing the plist writer.
568 """ 578 """
638 648
639 @param root reference to the object to be written 649 @param root reference to the object to be written
640 """ 650 """
641 output = self.header 651 output = self.header
642 wrapped_root = self.wrapRoot(root) 652 wrapped_root = self.wrapRoot(root)
643 should_reference_root = True#not isinstance(wrapped_root, HashableWrapper) 653 should_reference_root = True # not isinstance(wrapped_root, HashableWrapper)
644 self.computeOffsets(wrapped_root, asReference=should_reference_root, isRoot=True) 654 self.computeOffsets(wrapped_root, asReference=should_reference_root, isRoot=True)
645 self.trailer = self.trailer._replace( 655 self.trailer = self.trailer._replace(
646 **{'objectRefSize':self.intSize(len(self.computedUniques))}) 656 **{'objectRefSize': self.intSize(len(self.computedUniques))})
647 (_, output) = self.writeObjectReference(wrapped_root, output) 657 (_, output) = self.writeObjectReference(wrapped_root, output)
648 output = self.writeObject(wrapped_root, output, setReferencePosition=True) 658 output = self.writeObject(wrapped_root, output, setReferencePosition=True)
649 659
650 # output size at this point is an upper bound on how big the 660 # output size at this point is an upper bound on how big the
651 # object reference offsets need to be. 661 # object reference offsets need to be.
652 self.trailer = self.trailer._replace(**{ 662 self.trailer = self.trailer._replace(**{
653 'offsetSize':self.intSize(len(output)), 663 'offsetSize': self.intSize(len(output)),
654 'offsetCount':len(self.computedUniques), 664 'offsetCount': len(self.computedUniques),
655 'offsetTableOffset':len(output), 665 'offsetTableOffset': len(output),
656 'topLevelObjectNumber':0 666 'topLevelObjectNumber': 0
657 }) 667 })
658 668
659 output = self.writeOffsetTable(output) 669 output = self.writeOffsetTable(output)
660 output += pack('!xxxxxxBBQQQ', *self.trailer) 670 output += pack('!xxxxxxBBQQQ', *self.trailer)
661 self.file.write(output) 671 self.file.write(output)
693 else: 703 else:
694 return root 704 return root
695 705
696 def incrementByteCount(self, field, incr=1): 706 def incrementByteCount(self, field, incr=1):
697 self.byteCounts = self.byteCounts._replace( 707 self.byteCounts = self.byteCounts._replace(
698 **{field:self.byteCounts.__getattribute__(field) + incr}) 708 **{field: self.byteCounts.__getattribute__(field) + incr})
699 709
700 def computeOffsets(self, obj, asReference=False, isRoot=False): 710 def computeOffsets(self, obj, asReference=False, isRoot=False):
701 def check_key(key): 711 def check_key(key):
702 if key is None: 712 if key is None:
703 raise InvalidPlistException('Dictionary keys cannot be null in plists.') 713 raise InvalidPlistException('Dictionary keys cannot be null in plists.')
722 self.incrementByteCount('nullBytes') 732 self.incrementByteCount('nullBytes')
723 elif isinstance(obj, BoolWrapper): 733 elif isinstance(obj, BoolWrapper):
724 self.incrementByteCount('boolBytes') 734 self.incrementByteCount('boolBytes')
725 elif isinstance(obj, Uid): 735 elif isinstance(obj, Uid):
726 size = self.intSize(obj) 736 size = self.intSize(obj)
727 self.incrementByteCount('uidBytes', incr=1+size) 737 self.incrementByteCount('uidBytes', incr=1 + size)
728 elif isinstance(obj, int): 738 elif isinstance(obj, int):
729 size = self.intSize(obj) 739 size = self.intSize(obj)
730 self.incrementByteCount('intBytes', incr=1+size) 740 self.incrementByteCount('intBytes', incr=1 + size)
731 elif isinstance(obj, (float)): 741 elif isinstance(obj, (float)):
732 size = self.realSize(obj) 742 size = self.realSize(obj)
733 self.incrementByteCount('realBytes', incr=1+size) 743 self.incrementByteCount('realBytes', incr=1 + size)
734 elif isinstance(obj, datetime.datetime): 744 elif isinstance(obj, datetime.datetime):
735 self.incrementByteCount('dateBytes', incr=2) 745 self.incrementByteCount('dateBytes', incr=2)
736 elif isinstance(obj, Data): 746 elif isinstance(obj, Data):
737 size = proc_size(len(obj)) 747 size = proc_size(len(obj))
738 self.incrementByteCount('dataBytes', incr=1+size) 748 self.incrementByteCount('dataBytes', incr=1 + size)
739 elif isinstance(obj, str): 749 elif isinstance(obj, str):
740 size = proc_size(len(obj)) 750 size = proc_size(len(obj))
741 self.incrementByteCount('stringBytes', incr=1+size) 751 self.incrementByteCount('stringBytes', incr=1 + size)
742 elif isinstance(obj, HashableWrapper): 752 elif isinstance(obj, HashableWrapper):
743 obj = obj.value 753 obj = obj.value
744 if isinstance(obj, set): 754 if isinstance(obj, set):
745 size = proc_size(len(obj)) 755 size = proc_size(len(obj))
746 self.incrementByteCount('setBytes', incr=1+size) 756 self.incrementByteCount('setBytes', incr=1 + size)
747 for value in obj: 757 for value in obj:
748 self.computeOffsets(value, asReference=True) 758 self.computeOffsets(value, asReference=True)
749 elif isinstance(obj, (list, tuple)): 759 elif isinstance(obj, (list, tuple)):
750 size = proc_size(len(obj)) 760 size = proc_size(len(obj))
751 self.incrementByteCount('arrayBytes', incr=1+size) 761 self.incrementByteCount('arrayBytes', incr=1 + size)
752 for value in obj: 762 for value in obj:
753 self.computeOffsets(value, asReference=True) 763 self.computeOffsets(value, asReference=True)
754 elif isinstance(obj, dict): 764 elif isinstance(obj, dict):
755 size = proc_size(len(obj)) 765 size = proc_size(len(obj))
756 self.incrementByteCount('dictBytes', incr=1+size) 766 self.incrementByteCount('dictBytes', incr=1 + size)
757 for key, value in obj.items(): 767 for key, value in obj.items():
758 check_key(key) 768 check_key(key)
759 self.computeOffsets(key, asReference=True) 769 self.computeOffsets(key, asReference=True)
760 self.computeOffsets(value, asReference=True) 770 self.computeOffsets(value, asReference=True)
761 else: 771 else:
836 output += proc_variable_length(0b0100, len(obj)) 846 output += proc_variable_length(0b0100, len(obj))
837 output += obj 847 output += obj
838 elif isinstance(obj, str): 848 elif isinstance(obj, str):
839 # Python 3 uses unicode strings only 849 # Python 3 uses unicode strings only
840 bytes = obj.encode('utf_16_be') 850 bytes = obj.encode('utf_16_be')
841 output += proc_variable_length(0b0110, len(bytes)/2) 851 output += proc_variable_length(0b0110, len(bytes) / 2)
842 output += bytes 852 output += bytes
843 elif isinstance(obj, HashableWrapper): 853 elif isinstance(obj, HashableWrapper):
844 obj = obj.value 854 obj = obj.value
845 if isinstance(obj, (set, list, tuple)): 855 if isinstance(obj, (set, list, tuple)):
846 if isinstance(obj, set): 856 if isinstance(obj, set):
883 @return new output (bytes) 893 @return new output (bytes)
884 """ 894 """
885 all_positions = [] 895 all_positions = []
886 writtenReferences = list(self.writtenReferences.items()) 896 writtenReferences = list(self.writtenReferences.items())
887 writtenReferences.sort(key=lambda x: x[1]) 897 writtenReferences.sort(key=lambda x: x[1])
888 for obj,order in writtenReferences: 898 for obj, order in writtenReferences:
889 position = self.referencePositions.get(obj) 899 position = self.referencePositions.get(obj)
890 if position is None: 900 if position is None:
891 raise InvalidPlistException( 901 raise InvalidPlistException(
892 "Error while writing offsets table. Object not found. {0}" 902 "Error while writing offsets table. Object not found. {0}"
893 .format(obj)) 903 .format(obj))
937 947
938 @param obj integer object 948 @param obj integer object
939 @return number of bytes required (integer) 949 @return number of bytes required (integer)
940 """ 950 """
941 # SIGNED 951 # SIGNED
942 if obj < 0: # Signed integer, always 8 bytes 952 if obj < 0: # Signed integer, always 8 bytes
943 return 8 953 return 8
944 # UNSIGNED 954 # UNSIGNED
945 elif obj <= 0xFF: # 1 byte 955 elif obj <= 0xFF: # 1 byte
946 return 1 956 return 1
947 elif obj <= 0xFFFF: # 2 bytes 957 elif obj <= 0xFFFF: # 2 bytes
948 return 2 958 return 2
949 elif obj <= 0xFFFFFFFF: # 4 bytes 959 elif obj <= 0xFFFFFFFF: # 4 bytes
950 return 4 960 return 4
951 # SIGNED 961 # SIGNED
952 # 0x7FFFFFFFFFFFFFFF is the max. 962 # 0x7FFFFFFFFFFFFFFF is the max.
953 elif obj <= 0x7FFFFFFFFFFFFFFF: # 8 bytes 963 elif obj <= 0x7FFFFFFFFFFFFFFF: # 8 bytes
954 return 8 964 return 8
955 else: 965 else:
956 raise InvalidPlistException( 966 raise InvalidPlistException(
957 "Core Foundation can't handle integers with size greater than 8 bytes.") 967 "Core Foundation can't handle integers with size greater than 8 bytes.")
958 968

eric ide

mercurial