diff --git a/bplistlib/classes.py b/bplistlib/classes.py index 295c1af..56cc119 100644 --- a/bplistlib/classes.py +++ b/bplistlib/classes.py @@ -6,12 +6,68 @@ from struct import pack, unpack from datetime import datetime -from plistlib import Data +# JL +#from plistlib import Data from time import mktime from .functions import find_with_type, get_byte_width from .functions import flatten_object_list, unflatten_reference_list from .types import UID, Fill, FillType +# JL +import sys +# JL +# grafted in from python 3.8's plistlib, since it done +# got deprecated in python 3.9. +# Only the patchiest of the patch fixes here, since it +# seems like I'm the only person using this. + +def _encode_base64(s, maxlinelength=76): + # copied from base64.encodebytes(), with added maxlinelength argument + maxbinsize = (maxlinelength//4)*3 + pieces = [] + for i in range(0, len(s), maxbinsize): + chunk = s[i : i + maxbinsize] + pieces.append(binascii.b2a_base64(chunk)) + return b''.join(pieces) + +def _decode_base64(s): + if isinstance(s, str): + return binascii.a2b_base64(s.encode("utf-8")) + + else: + return binascii.a2b_base64(s) + +class Data: + """ + Wrapper for binary data. + + This class is deprecated, use a bytes object instead. + """ + + def __init__(self, data): + if not isinstance(data, bytes): + raise TypeError("data must be as bytes") + self.data = data + + @classmethod + def fromBase64(cls, data): + # base64.decodebytes just calls binascii.a2b_base64; + # it seems overkill to use both base64 and binascii. + return cls(_decode_base64(data)) + + def asBase64(self, maxlinelength=76): + return _encode_base64(self.data, maxlinelength) + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.data == other.data + elif isinstance(other, bytes): + return self.data == other + else: + return NotImplemented + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, repr(self.data)) class BooleanHandler(object): """Handler for boolean types in a binary plist.""" @@ -33,7 +89,9 @@ def get_byte_length(self, object_length): def encode_body(self, string, object_length): """Return an empty string.""" - return '' + # JL + #return '' + return b'' def decode_body(self, raw, object_length): """Return the decoded boolean value.""" @@ -142,7 +200,9 @@ class DataHander(object): def __init__(self): self.type_number = 4 # this is ugly but maintains interop with plistlib. - self.types = type(Data('')) + # JL + #self.types = type(Data('')) + self.types = type(Data(''.encode())) def get_object_length(self, data): """Get the length of the data stored inside the Data object.""" @@ -193,7 +253,12 @@ def __init__(self): StringHandler.__init__(self) self.type_number = 6 self.encoding = 'utf_16_be' - self.types = unicode + # JL + #self.types = unicode + if sys.version_info.major < 3: + self.types = unicode + else: + self.types = str def get_byte_length(self, object_length): """Return twice the object length.""" @@ -305,7 +370,9 @@ def encode_body(self, dictionary, object_length): keys = ArrayHandler.encode_body(self, dictionary.keys(), object_length) values = ArrayHandler.encode_body(self, dictionary.values(), object_length) - return ''.join((keys, values)) + # JL + #return ''.join((keys, values)) + return b''.join((keys, values)) def decode_body(self, raw, object_length): """ @@ -369,7 +436,9 @@ def encode(self, object_, handler=None): object_length = handler.get_object_length(object_) first_byte = self.encode_first_byte(handler.type_number, object_length) body = handler.encode_body(object_, object_length) - return ''.join((first_byte, body)) + # JL + #return ''.join((first_byte, body)) + return b''.join((first_byte, body)) def decode(self, file_object, handler=None): """Start reading in file_object, and decode the object found.""" @@ -416,7 +485,9 @@ def encode_first_byte(self, type_number, length): value = (type_number << 4) + length encoded = pack('B', value) if big: - return ''.join((encoded, real_length)) + # JL + #return ''.join((encoded, real_length)) + return b''.join((encoded, real_length)) return encoded def decode_first_byte(self, file_object): diff --git a/bplistlib/public.py b/bplistlib/public.py index 9852d90..a0666ba 100644 --- a/bplistlib/public.py +++ b/bplistlib/public.py @@ -2,7 +2,9 @@ """This file contains the public functions for the module bplistlib.""" -from cStringIO import StringIO +# JL +#from cStringIO import StringIO +from io import BytesIO import plistlib from .readwrite import read, write @@ -11,16 +13,25 @@ ## API ## ######### +# readPlist(pathOrFile) +# load(fp, *, fmt=None, use_builtin_types=True, dict_type=dict) +# loads(value, *, fmt=None, use_builtin_types=True, dict_type=dict) +# writePlist(value, pathOrFile) +# dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False) +# dumps(value, *, fmt=FMT_XML, skipkeys=False, sort_keys=True) def dump(obj, fp, binary=False): if binary is True: write(obj, fp) else: - plistlib.writePlist(obj, fp) + # JL + plistlib.dump(obj, fp) def dumps(obj, binary=False): - fp = StringIO() + # JL + #fp = StringIO() + fp = BytesIO() dump(obj, fp, binary) return fp.getvalue() @@ -35,12 +46,15 @@ def load(fp, binary=None): if binary is True: root_object = read(fp) elif binary is False: - root_object = plistlib.readPlist(fp) + # JL + root_object = plistlib.load(fp) return root_object def loads(s, binary=None): - return load(StringIO(s), binary) + # JL + #return load(StringIO(s), binary) + return load(BytesIO(s), binary) ################ diff --git a/bplistlib/readwrite.py b/bplistlib/readwrite.py index 038df11..6503005 100644 --- a/bplistlib/readwrite.py +++ b/bplistlib/readwrite.py @@ -51,7 +51,9 @@ def read_objects(file_object, offsets, reference_size, root): def write(root_object, file_object): """Write the root_object to file_object.""" - file_object.write('bplist00') + # JL + #file_object.write('bplist00') + file_object.write('bplist00'.encode()) offsets = write_objects(file_object, root_object) table_offset = write_table(file_object, offsets) write_trailer(file_object, offsets, table_offset) diff --git a/test/test.py b/test/test.py index e94f96e..6d821dc 100644 --- a/test/test.py +++ b/test/test.py @@ -6,7 +6,9 @@ # may be missed. from datetime import datetime -from plistlib import Data +# JL +#from plistlib import Data +from bplistlib.classes import Data from os import remove import unittest import random