--- a/Utilities/binplistlib.py Sun Jul 29 17:26:28 2012 +0200 +++ b/Utilities/binplistlib.py Sun Jul 29 18:05:03 2012 +0200 @@ -21,7 +21,7 @@ Date values can only be datetime.datetime objects. -The exceptions InvalidPlistException and NotBinaryPlistException may be +The exceptions InvalidPlistException and NotBinaryPlistException may be thrown to indicate that the data cannot be serialized or deserialized as a binary plist. @@ -68,7 +68,7 @@ # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of biplist nor the names of its contributors may be -# used to endorse or promote products derived from this software without +# used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" @@ -156,6 +156,7 @@ pathOrFile.close() return result + def writePlist(rootObject, pathOrFile, binary=True): """ Module function to write a plist file. @@ -178,6 +179,7 @@ pathOrFile.close() return + def readPlistFromBytes(data): """ Module function to read from a plist bytes object. @@ -188,6 +190,7 @@ """ return readPlist(BytesIO(data)) + def writePlistToBytes(rootObject, binary=True): """ Module function to write a plist bytes object. @@ -203,6 +206,7 @@ writer.writeRoot(rootObject) return io.getvalue() + def is_stream_binary_plist(stream): """ Module function to check, if the stream is a binary plist. @@ -223,6 +227,7 @@ 'nullBytes, boolBytes, intBytes, realBytes, dateBytes, dataBytes, stringBytes, ' 'uidBytes, arrayBytes, setBytes, dictBytes') + class PlistReader(object): """ Class implementing the plist reader. @@ -279,11 +284,11 @@ self.trailer = PlistTrailer._make(unpack("!xxxxxxBBQQQ", trailerContents)) offset_size = self.trailer.offsetSize * self.trailer.offsetCount offset = self.trailer.offsetTableOffset - offset_contents = self.contents[offset:offset+offset_size] + offset_contents = self.contents[offset:offset + offset_size] offset_i = 0 while offset_i < self.trailer.offsetCount: - begin = self.trailer.offsetSize*offset_i - tmp_contents = offset_contents[begin:begin+self.trailer.offsetSize] + begin = self.trailer.offsetSize * offset_i + tmp_contents = offset_contents[begin:begin + self.trailer.offsetSize] tmp_sized = self.getSizedInteger(tmp_contents, self.trailer.offsetSize) self.offsets.append(tmp_sized) offset_i += 1 @@ -308,7 +313,7 @@ @return unpickled object """ result = None - tmp_byte = self.contents[self.currentOffset:self.currentOffset+1] + tmp_byte = self.contents[self.currentOffset:self.currentOffset + 1] marker_byte = unpack("!B", tmp_byte)[0] format = (marker_byte >> 4) & 0x0f extra = marker_byte & 0x0f @@ -329,7 +334,7 @@ elif extra == 0b1001: result = True elif extra == 0b1111: - pass # fill byte + pass # fill byte else: raise InvalidPlistException( "Invalid object found at offset: {0}".format(self.currentOffset - 1)) @@ -371,7 +376,7 @@ elif format == 0b1101: extra = proc_extra(extra) result = self.readDict(extra) - else: + else: raise InvalidPlistException( "Invalid object found: {{format: {0}, extra: {1}}}".format( bin(format), bin(extra))) @@ -386,7 +391,7 @@ """ result = 0 original_offset = self.currentOffset - data = self.contents[self.currentOffset:self.currentOffset+bytes] + data = self.contents[self.currentOffset:self.currentOffset + bytes] result = self.getSizedInteger(data, bytes) self.currentOffset = original_offset + bytes return result @@ -400,17 +405,17 @@ """ result = 0.0 to_read = pow(2, length) - data = self.contents[self.currentOffset:self.currentOffset+to_read] - if length == 2: # 4 bytes + data = self.contents[self.currentOffset:self.currentOffset + to_read] + if length == 2: # 4 bytes result = unpack('>f', data)[0] - elif length == 3: # 8 bytes + elif length == 3: # 8 bytes result = unpack('>d', data)[0] else: raise InvalidPlistException( "Unknown real of length {0} bytes".format(to_read)) return result - def readRefs(self, count): + def readRefs(self, count): """ Private method to read References. @@ -421,7 +426,7 @@ i = 0 while i < count: fragment = self.contents[ - self.currentOffset:self.currentOffset+self.trailer.objectRefSize] + self.currentOffset:self.currentOffset + self.trailer.objectRefSize] ref = self.getSizedInteger(fragment, len(fragment)) refs.append(ref) self.currentOffset += self.trailer.objectRefSize @@ -473,7 +478,7 @@ @return ASCII encoded string """ result = str(unpack("!{0}s".format(length), - self.contents[self.currentOffset:self.currentOffset+length])[0], + self.contents[self.currentOffset:self.currentOffset + length])[0], encoding="ascii") self.currentOffset += length return result @@ -485,8 +490,8 @@ @param length length of the string (integer) @return unicode encoded string """ - actual_length = length*2 - data = self.contents[self.currentOffset:self.currentOffset+actual_length] + actual_length = length * 2 + data = self.contents[self.currentOffset:self.currentOffset + actual_length] # unpack not needed?!! data = unpack(">%ds" % (actual_length), data)[0] self.currentOffset += actual_length return data.decode('utf_16_be') @@ -498,7 +503,7 @@ @return date object (datetime.datetime) """ global apple_reference_date_offset - result = unpack(">d", self.contents[self.currentOffset:self.currentOffset+8])[0] + result = unpack(">d", self.contents[self.currentOffset:self.currentOffset + 8])[0] result = datetime.datetime.utcfromtimestamp(result + apple_reference_date_offset) self.currentOffset += 8 return result @@ -510,7 +515,7 @@ @param length number of bytes to read (integer) @return Data object """ - result = self.contents[self.currentOffset:self.currentOffset+length] + result = self.contents[self.currentOffset:self.currentOffset + length] self.currentOffset += length return Data(result) @@ -521,7 +526,7 @@ @param length length of the UID (integer) @return Uid object """ - return Uid(self.readInteger(length+1)) + return Uid(self.readInteger(length + 1)) def getSizedInteger(self, data, bytes): """ @@ -544,24 +549,29 @@ raise InvalidPlistException("Encountered integer longer than 8 bytes.") return result + class HashableWrapper(object): """ Class wrapping a hashable value. """ def __init__(self, value): self.value = value + def __repr__(self): return "<HashableWrapper: %s>" % [self.value] + class BoolWrapper(object): """ Class wrapping a boolean value. """ def __init__(self, value): self.value = value + def __repr__(self): return "<BoolWrapper: %s>" % self.value + class PlistWriter(object): """ Class implementing the plist writer. @@ -640,20 +650,20 @@ """ output = self.header wrapped_root = self.wrapRoot(root) - should_reference_root = True#not isinstance(wrapped_root, HashableWrapper) + should_reference_root = True # not isinstance(wrapped_root, HashableWrapper) self.computeOffsets(wrapped_root, asReference=should_reference_root, isRoot=True) self.trailer = self.trailer._replace( - **{'objectRefSize':self.intSize(len(self.computedUniques))}) + **{'objectRefSize': self.intSize(len(self.computedUniques))}) (_, output) = self.writeObjectReference(wrapped_root, output) output = self.writeObject(wrapped_root, output, setReferencePosition=True) # output size at this point is an upper bound on how big the # object reference offsets need to be. self.trailer = self.trailer._replace(**{ - 'offsetSize':self.intSize(len(output)), - 'offsetCount':len(self.computedUniques), - 'offsetTableOffset':len(output), - 'topLevelObjectNumber':0 + 'offsetSize': self.intSize(len(output)), + 'offsetCount': len(self.computedUniques), + 'offsetTableOffset': len(output), + 'topLevelObjectNumber': 0 }) output = self.writeOffsetTable(output) @@ -695,7 +705,7 @@ def incrementByteCount(self, field, incr=1): self.byteCounts = self.byteCounts._replace( - **{field:self.byteCounts.__getattribute__(field) + incr}) + **{field: self.byteCounts.__getattribute__(field) + incr}) def computeOffsets(self, obj, asReference=False, isRoot=False): def check_key(key): @@ -724,36 +734,36 @@ self.incrementByteCount('boolBytes') elif isinstance(obj, Uid): size = self.intSize(obj) - self.incrementByteCount('uidBytes', incr=1+size) + self.incrementByteCount('uidBytes', incr=1 + size) elif isinstance(obj, int): size = self.intSize(obj) - self.incrementByteCount('intBytes', incr=1+size) + self.incrementByteCount('intBytes', incr=1 + size) elif isinstance(obj, (float)): size = self.realSize(obj) - self.incrementByteCount('realBytes', incr=1+size) - elif isinstance(obj, datetime.datetime): + self.incrementByteCount('realBytes', incr=1 + size) + elif isinstance(obj, datetime.datetime): self.incrementByteCount('dateBytes', incr=2) elif isinstance(obj, Data): size = proc_size(len(obj)) - self.incrementByteCount('dataBytes', incr=1+size) + self.incrementByteCount('dataBytes', incr=1 + size) elif isinstance(obj, str): size = proc_size(len(obj)) - self.incrementByteCount('stringBytes', incr=1+size) + self.incrementByteCount('stringBytes', incr=1 + size) elif isinstance(obj, HashableWrapper): obj = obj.value if isinstance(obj, set): size = proc_size(len(obj)) - self.incrementByteCount('setBytes', incr=1+size) + self.incrementByteCount('setBytes', incr=1 + size) for value in obj: self.computeOffsets(value, asReference=True) elif isinstance(obj, (list, tuple)): size = proc_size(len(obj)) - self.incrementByteCount('arrayBytes', incr=1+size) + self.incrementByteCount('arrayBytes', incr=1 + size) for value in obj: self.computeOffsets(value, asReference=True) elif isinstance(obj, dict): size = proc_size(len(obj)) - self.incrementByteCount('dictBytes', incr=1+size) + self.incrementByteCount('dictBytes', incr=1 + size) for key, value in obj.items(): check_key(key) self.computeOffsets(key, asReference=True) @@ -838,7 +848,7 @@ elif isinstance(obj, str): # Python 3 uses unicode strings only bytes = obj.encode('utf_16_be') - output += proc_variable_length(0b0110, len(bytes)/2) + output += proc_variable_length(0b0110, len(bytes) / 2) output += bytes elif isinstance(obj, HashableWrapper): obj = obj.value @@ -885,7 +895,7 @@ all_positions = [] writtenReferences = list(self.writtenReferences.items()) writtenReferences.sort(key=lambda x: x[1]) - for obj,order in writtenReferences: + for obj, order in writtenReferences: position = self.referencePositions.get(obj) if position is None: raise InvalidPlistException( @@ -939,18 +949,18 @@ @return number of bytes required (integer) """ # SIGNED - if obj < 0: # Signed integer, always 8 bytes + if obj < 0: # Signed integer, always 8 bytes return 8 # UNSIGNED - elif obj <= 0xFF: # 1 byte + elif obj <= 0xFF: # 1 byte return 1 - elif obj <= 0xFFFF: # 2 bytes + elif obj <= 0xFFFF: # 2 bytes return 2 - elif obj <= 0xFFFFFFFF: # 4 bytes + elif obj <= 0xFFFFFFFF: # 4 bytes return 4 # SIGNED # 0x7FFFFFFFFFFFFFFF is the max. - elif obj <= 0x7FFFFFFFFFFFFFFF: # 8 bytes + elif obj <= 0x7FFFFFFFFFFFFFFF: # 8 bytes return 8 else: raise InvalidPlistException(