Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python3 fixes #1

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 78 additions & 7 deletions bplistlib/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand All @@ -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."""
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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."""
Expand Down Expand Up @@ -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):
Expand Down
24 changes: 19 additions & 5 deletions bplistlib/public.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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()

Expand All @@ -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)


################
Expand Down
4 changes: 3 additions & 1 deletion bplistlib/readwrite.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 3 additions & 1 deletion test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down