From a37aef7f53d701c43ca6ec65f4d5190df5d2422a Mon Sep 17 00:00:00 2001 From: Jayson Larose Date: Thu, 30 Nov 2017 13:14:28 -0800 Subject: [PATCH 1/3] * Battered into python3 submission. --- bplistlib/classes.py | 24 ++++++++++++++++++------ bplistlib/public.py | 12 +++++++++--- bplistlib/readwrite.py | 4 +++- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/bplistlib/classes.py b/bplistlib/classes.py index 295c1af..8599db9 100644 --- a/bplistlib/classes.py +++ b/bplistlib/classes.py @@ -33,7 +33,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 +144,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 +197,9 @@ def __init__(self): StringHandler.__init__(self) self.type_number = 6 self.encoding = 'utf_16_be' - self.types = unicode + # JL + #self.types = unicode + self.types = str def get_byte_length(self, object_length): """Return twice the object length.""" @@ -305,7 +311,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 +377,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 +426,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..7dc1245 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 @@ -20,7 +22,9 @@ def dump(obj, fp, binary=False): def dumps(obj, binary=False): - fp = StringIO() + # JL + #fp = StringIO() + fp = BytesIO() dump(obj, fp, binary) return fp.getvalue() @@ -40,7 +44,9 @@ def load(fp, binary=None): 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) From 7bef26191f7d382e2eee0580807e8f3ba16eda52 Mon Sep 17 00:00:00 2001 From: Jayson Larose Date: Fri, 13 Jul 2018 04:40:45 -0700 Subject: [PATCH 2/3] Fixed to work with python 2 and 3 --- bplistlib/classes.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/bplistlib/classes.py b/bplistlib/classes.py index 8599db9..95fc163 100644 --- a/bplistlib/classes.py +++ b/bplistlib/classes.py @@ -11,6 +11,8 @@ 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 class BooleanHandler(object): @@ -33,7 +35,7 @@ def get_byte_length(self, object_length): def encode_body(self, string, object_length): """Return an empty string.""" - # JL + # JL #return '' return b'' @@ -144,7 +146,7 @@ class DataHander(object): def __init__(self): self.type_number = 4 # this is ugly but maintains interop with plistlib. - # JL + # JL #self.types = type(Data('')) self.types = type(Data(''.encode())) @@ -197,9 +199,12 @@ def __init__(self): StringHandler.__init__(self) self.type_number = 6 self.encoding = 'utf_16_be' - # JL + # JL #self.types = unicode - self.types = str + 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.""" @@ -311,7 +316,7 @@ 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) - # JL + # JL #return ''.join((keys, values)) return b''.join((keys, values)) @@ -377,7 +382,7 @@ 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) - # JL + # JL #return ''.join((first_byte, body)) return b''.join((first_byte, body)) @@ -426,7 +431,7 @@ def encode_first_byte(self, type_number, length): value = (type_number << 4) + length encoded = pack('B', value) if big: - # JL + # JL #return ''.join((encoded, real_length)) return b''.join((encoded, real_length)) return encoded From e2bcfc63c12ce21811aacdfe94e1f1bceaec81be Mon Sep 17 00:00:00 2001 From: Jayson Larose Date: Mon, 14 Jun 2021 01:03:32 -0700 Subject: [PATCH 3/3] Break-fixes for deprecated plistlib functions removed in Python 3.9. --- bplistlib/classes.py | 56 +++++++++++++++++++++++++++++++++++++++++++- bplistlib/public.py | 16 +++++++++---- test/test.py | 4 +++- 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/bplistlib/classes.py b/bplistlib/classes.py index 95fc163..56cc119 100644 --- a/bplistlib/classes.py +++ b/bplistlib/classes.py @@ -6,7 +6,8 @@ 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 @@ -14,6 +15,59 @@ # 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.""" diff --git a/bplistlib/public.py b/bplistlib/public.py index 7dc1245..a0666ba 100644 --- a/bplistlib/public.py +++ b/bplistlib/public.py @@ -13,16 +13,23 @@ ## 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): - # JL + # JL #fp = StringIO() fp = BytesIO() dump(obj, fp, binary) @@ -39,12 +46,13 @@ 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): - # JL + # JL #return load(StringIO(s), binary) return load(BytesIO(s), binary) 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