/
opt
/
alt
/
python37
/
lib64
/
python3.7
/
/opt/alt/python37/lib64/python3.7
mkdir
upload
Name
Size
Mode
Actions
asyncio/
-
0755
rm
collections/
-
0755
rm
concurrent/
-
0755
rm
config-3.7m/
-
0755
rm
ctypes/
-
0755
rm
curses/
-
0755
rm
dbm/
-
0755
rm
distutils/
-
0755
rm
email/
-
0755
rm
encodings/
-
0755
rm
ensurepip/
-
0755
rm
html/
-
0755
rm
http/
-
0755
rm
idlelib/
-
0755
rm
importlib/
-
0755
rm
json/
-
0755
rm
lib-dynload/
-
0755
rm
lib2to3/
-
0755
rm
logging/
-
0755
rm
multiprocessing/
-
0755
rm
pydoc_data/
-
0755
rm
site-packages/
-
0755
rm
sqlite3/
-
0755
rm
test/
-
0755
rm
unittest/
-
0755
rm
urllib/
-
0755
rm
venv/
-
0755
rm
wsgiref/
-
0755
rm
xml/
-
0755
rm
xmlrpc/
-
0755
rm
__pycache__/
-
0755
rm
abc.py
5580
0644
edit
dl
rm
aifc.py
32814
0644
edit
dl
rm
antigravity.py
477
0644
edit
dl
rm
argparse.py
95372
0644
edit
dl
rm
ast.py
12842
0644
edit
dl
rm
asynchat.py
11328
0644
edit
dl
rm
asyncore.py
20118
0644
edit
dl
rm
base64.py
20393
0755
edit
dl
rm
bdb.py
31730
0644
edit
dl
rm
binhex.py
13954
0644
edit
dl
rm
bisect.py
2557
0644
edit
dl
rm
bz2.py
12410
0644
edit
dl
rm
calendar.py
24826
0644
edit
dl
rm
cgi.py
35050
0755
edit
dl
rm
cgitb.py
12018
0644
edit
dl
rm
chunk.py
5435
0644
edit
dl
rm
cmd.py
14860
0644
edit
dl
rm
code.py
10622
0644
edit
dl
rm
codecs.py
36615
0644
edit
dl
rm
codeop.py
6275
0644
edit
dl
rm
colorsys.py
4064
0644
edit
dl
rm
compileall.py
13788
0644
edit
dl
rm
configparser.py
54283
0644
edit
dl
rm
contextlib.py
24763
0644
edit
dl
rm
contextvars.py
129
0644
edit
dl
rm
copy.py
8856
0644
edit
dl
rm
copyreg.py
7017
0644
edit
dl
rm
cProfile.py
6253
0755
edit
dl
rm
crypt.py
3346
0644
edit
dl
rm
csv.py
16180
0644
edit
dl
rm
dataclasses.py
49520
0644
edit
dl
rm
datetime.py
86544
0644
edit
dl
rm
decimal.py
320
0644
edit
dl
rm
difflib.py
84393
0644
edit
dl
rm
dis.py
19888
0644
edit
dl
rm
doctest.py
104560
0644
edit
dl
rm
dummy_threading.py
2815
0644
edit
dl
rm
enum.py
35043
0644
edit
dl
rm
filecmp.py
9830
0644
edit
dl
rm
fileinput.py
14625
0644
edit
dl
rm
fnmatch.py
4056
0644
edit
dl
rm
formatter.py
15143
0644
edit
dl
rm
fractions.py
23752
0644
edit
dl
rm
ftplib.py
35618
0644
edit
dl
rm
functools.py
32932
0644
edit
dl
rm
genericpath.py
4912
0644
edit
dl
rm
getopt.py
7489
0644
edit
dl
rm
getpass.py
5994
0644
edit
dl
rm
gettext.py
21967
0644
edit
dl
rm
glob.py
5638
0644
edit
dl
rm
gzip.py
20637
0644
edit
dl
rm
hashlib.py
9534
0644
edit
dl
rm
heapq.py
23017
0644
edit
dl
rm
hmac.py
6517
0644
edit
dl
rm
imaplib.py
53292
0644
edit
dl
rm
imghdr.py
3795
0644
edit
dl
rm
imp.py
10536
0644
edit
dl
rm
inspect.py
117635
0644
edit
dl
rm
io.py
3517
0644
edit
dl
rm
ipaddress.py
73578
0644
edit
dl
rm
keyword.py
2256
0755
edit
dl
rm
linecache.py
5330
0644
edit
dl
rm
locale.py
78191
0644
edit
dl
rm
lzma.py
12983
0644
edit
dl
rm
macpath.py
6123
0644
edit
dl
rm
mailbox.py
78654
0644
edit
dl
rm
mailcap.py
9067
0644
edit
dl
rm
mimetypes.py
21496
0644
edit
dl
rm
modulefinder.py
23035
0644
edit
dl
rm
netrc.py
5566
0644
edit
dl
rm
nntplib.py
43087
0644
edit
dl
rm
ntpath.py
22340
0644
edit
dl
rm
nturl2path.py
2584
0644
edit
dl
rm
numbers.py
10244
0644
edit
dl
rm
opcode.py
5824
0644
edit
dl
rm
operator.py
10863
0644
edit
dl
rm
optparse.py
60371
0644
edit
dl
rm
os.py
37901
0644
edit
dl
rm
pathlib.py
50329
0644
edit
dl
rm
pdb.py
62505
0755
edit
dl
rm
pickle.py
57994
0644
edit
dl
rm
pickletools.py
91220
0644
edit
dl
rm
pipes.py
8916
0644
edit
dl
rm
pkgutil.py
21461
0644
edit
dl
rm
platform.py
46994
0755
edit
dl
rm
plistlib.py
30709
0644
edit
dl
rm
poplib.py
14964
0644
edit
dl
rm
posixpath.py
15771
0644
edit
dl
rm
pprint.py
20884
0644
edit
dl
rm
profile.py
22494
0755
edit
dl
rm
pstats.py
27315
0644
edit
dl
rm
pty.py
4763
0644
edit
dl
rm
pyclbr.py
15137
0644
edit
dl
rm
pydoc.py
105876
0644
edit
dl
rm
py_compile.py
8001
0644
edit
dl
rm
queue.py
11359
0644
edit
dl
rm
quopri.py
7265
0755
edit
dl
rm
random.py
27557
0644
edit
dl
rm
re.py
15306
0644
edit
dl
rm
reprlib.py
5267
0644
edit
dl
rm
rlcompleter.py
7097
0644
edit
dl
rm
runpy.py
11959
0644
edit
dl
rm
sched.py
6442
0644
edit
dl
rm
secrets.py
2038
0644
edit
dl
rm
selectors.py
18561
0644
edit
dl
rm
shelve.py
8527
0644
edit
dl
rm
shlex.py
13100
0644
edit
dl
rm
shutil.py
41950
0644
edit
dl
rm
signal.py
2123
0644
edit
dl
rm
site.py
21575
0644
edit
dl
rm
smtpd.py
34722
0755
edit
dl
rm
smtplib.py
44443
0755
edit
dl
rm
sndhdr.py
7086
0644
edit
dl
rm
socket.py
27469
0644
edit
dl
rm
socketserver.py
26923
0644
edit
dl
rm
sre_compile.py
26872
0644
edit
dl
rm
sre_constants.py
7177
0644
edit
dl
rm
sre_parse.py
39156
0644
edit
dl
rm
ssl.py
45495
0644
edit
dl
rm
stat.py
5391
0644
edit
dl
rm
statistics.py
20651
0644
edit
dl
rm
string.py
11564
0644
edit
dl
rm
stringprep.py
12917
0644
edit
dl
rm
struct.py
257
0644
edit
dl
rm
subprocess.py
72649
0644
edit
dl
rm
sunau.py
18375
0644
edit
dl
rm
symbol.py
2142
0755
edit
dl
rm
symtable.py
7279
0644
edit
dl
rm
sysconfig.py
24440
0644
edit
dl
rm
tabnanny.py
11419
0755
edit
dl
rm
tarfile.py
92675
0755
edit
dl
rm
telnetlib.py
23135
0644
edit
dl
rm
tempfile.py
26730
0644
edit
dl
rm
textwrap.py
19407
0644
edit
dl
rm
this.py
1003
0644
edit
dl
rm
threading.py
49284
0644
edit
dl
rm
timeit.py
13493
0755
edit
dl
rm
token.py
3763
0644
edit
dl
rm
tokenize.py
27031
0644
edit
dl
rm
trace.py
28903
0755
edit
dl
rm
traceback.py
23437
0644
edit
dl
rm
tracemalloc.py
17076
0644
edit
dl
rm
tty.py
879
0644
edit
dl
rm
types.py
9897
0644
edit
dl
rm
typing.py
56438
0644
edit
dl
rm
uu.py
7277
0644
edit
dl
rm
uuid.py
29518
0644
edit
dl
rm
warnings.py
20080
0644
edit
dl
rm
wave.py
18230
0644
edit
dl
rm
weakref.py
21508
0644
edit
dl
rm
webbrowser.py
23715
0755
edit
dl
rm
xdrlib.py
5913
0644
edit
dl
rm
zipapp.py
7535
0644
edit
dl
rm
zipfile.py
81094
0644
edit
dl
rm
_bootlocale.py
1801
0644
edit
dl
rm
_collections_abc.py
26424
0644
edit
dl
rm
_compat_pickle.py
8749
0644
edit
dl
rm
_compression.py
5340
0644
edit
dl
rm
_dummy_thread.py
6027
0644
edit
dl
rm
_markupbase.py
14598
0644
edit
dl
rm
_osx_support.py
19600
0644
edit
dl
rm
_pydecimal.py
228690
0644
edit
dl
rm
_pyio.py
91616
0644
edit
dl
rm
_py_abc.py
6186
0644
edit
dl
rm
_sitebuiltins.py
3115
0644
edit
dl
rm
_strptime.py
25504
0644
edit
dl
rm
_sysconfigdata_dm_linux_x86_64-linux-gnu.py
29786
0644
edit
dl
rm
_sysconfigdata_m_linux_x86_64-linux-gnu.py
28651
0644
edit
dl
rm
_threading_local.py
7214
0644
edit
dl
rm
_weakrefset.py
5679
0644
edit
dl
rm
__future__.py
5101
0644
edit
dl
rm
__phello__.foo.py
64
0644
edit
dl
rm
Edit:
/opt/alt/python37/lib64/python3.7/plistlib.py
(30709B)
r"""plistlib.py -- a tool to generate and parse MacOSX .plist files. The property list (.plist) file format is a simple XML pickle supporting basic object types, like dictionaries, lists, numbers and strings. Usually the top level object is a dictionary. To write out a plist file, use the dump(value, file) function. 'value' is the top level object, 'file' is a (writable) file object. To parse a plist from a file, use the load(file) function, with a (readable) file object as the only argument. It returns the top level object (again, usually a dictionary). To work with plist data in bytes objects, you can use loads() and dumps(). Values can be strings, integers, floats, booleans, tuples, lists, dictionaries (but only with string keys), Data, bytes, bytearray, or datetime.datetime objects. Generate Plist example: pl = dict( aString = "Doodah", aList = ["A", "B", 12, 32.1, [1, 2, 3]], aFloat = 0.1, anInt = 728, aDict = dict( anotherString = "<hello & hi there!>", aUnicodeValue = "M\xe4ssig, Ma\xdf", aTrueValue = True, aFalseValue = False, ), someData = b"<binary gunk>", someMoreData = b"<lots of binary gunk>" * 10, aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())), ) with open(fileName, 'wb') as fp: dump(pl, fp) Parse Plist example: with open(fileName, 'rb') as fp: pl = load(fp) print(pl["aKey"]) """ __all__ = [ "readPlist", "writePlist", "readPlistFromBytes", "writePlistToBytes", "Data", "InvalidFileException", "FMT_XML", "FMT_BINARY", "load", "dump", "loads", "dumps" ] import binascii import codecs import contextlib import datetime import enum from io import BytesIO import itertools import os import re import struct from warnings import warn from xml.parsers.expat import ParserCreate PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__) globals().update(PlistFormat.__members__) # # # Deprecated functionality # # @contextlib.contextmanager def _maybe_open(pathOrFile, mode): if isinstance(pathOrFile, str): with open(pathOrFile, mode) as fp: yield fp else: yield pathOrFile def readPlist(pathOrFile): """ Read a .plist from a path or file. pathOrFile should either be a file name, or a readable binary file object. This function is deprecated, use load instead. """ warn("The readPlist function is deprecated, use load() instead", DeprecationWarning, 2) with _maybe_open(pathOrFile, 'rb') as fp: return load(fp, fmt=None, use_builtin_types=False) def writePlist(value, pathOrFile): """ Write 'value' to a .plist file. 'pathOrFile' may either be a file name or a (writable) file object. This function is deprecated, use dump instead. """ warn("The writePlist function is deprecated, use dump() instead", DeprecationWarning, 2) with _maybe_open(pathOrFile, 'wb') as fp: dump(value, fp, fmt=FMT_XML, sort_keys=True, skipkeys=False) def readPlistFromBytes(data): """ Read a plist data from a bytes object. Return the root object. This function is deprecated, use loads instead. """ warn("The readPlistFromBytes function is deprecated, use loads() instead", DeprecationWarning, 2) return load(BytesIO(data), fmt=None, use_builtin_types=False) def writePlistToBytes(value): """ Return 'value' as a plist-formatted bytes object. This function is deprecated, use dumps instead. """ warn("The writePlistToBytes function is deprecated, use dumps() instead", DeprecationWarning, 2) f = BytesIO() dump(value, f, fmt=FMT_XML, sort_keys=True, skipkeys=False) return f.getvalue() 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)) # # # End of deprecated functionality # # # # XML support # # XML 'header' PLISTHEADER = b"""\ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> """ # Regex to find any control chars, except for \t \n and \r _controlCharPat = re.compile( r"[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f" r"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]") 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) # Contents should conform to a subset of ISO 8601 # (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'. Smaller units # may be omitted with # a loss of precision) _dateParser = re.compile(r"(?P<year>\d\d\d\d)(?:-(?P<month>\d\d)(?:-(?P<day>\d\d)(?:T(?P<hour>\d\d)(?::(?P<minute>\d\d)(?::(?P<second>\d\d))?)?)?)?)?Z", re.ASCII) def _date_from_string(s): order = ('year', 'month', 'day', 'hour', 'minute', 'second') gd = _dateParser.match(s).groupdict() lst = [] for key in order: val = gd[key] if val is None: break lst.append(int(val)) return datetime.datetime(*lst) def _date_to_string(d): return '%04d-%02d-%02dT%02d:%02d:%02dZ' % ( d.year, d.month, d.day, d.hour, d.minute, d.second ) def _escape(text): m = _controlCharPat.search(text) if m is not None: raise ValueError("strings can't contains control characters; " "use bytes instead") text = text.replace("\r\n", "\n") # convert DOS line endings text = text.replace("\r", "\n") # convert Mac line endings text = text.replace("&", "&") # escape '&' text = text.replace("<", "<") # escape '<' text = text.replace(">", ">") # escape '>' return text class _PlistParser: def __init__(self, use_builtin_types, dict_type): self.stack = [] self.current_key = None self.root = None self._use_builtin_types = use_builtin_types self._dict_type = dict_type def parse(self, fileobj): self.parser = ParserCreate() self.parser.StartElementHandler = self.handle_begin_element self.parser.EndElementHandler = self.handle_end_element self.parser.CharacterDataHandler = self.handle_data self.parser.EntityDeclHandler = self.handle_entity_decl self.parser.ParseFile(fileobj) return self.root def handle_entity_decl(self, entity_name, is_parameter_entity, value, base, system_id, public_id, notation_name): # Reject plist files with entity declarations to avoid XML vulnerabilies in expat. # Regular plist files don't contain those declerations, and Apple's plutil tool does not # accept them either. raise InvalidFileException("XML entity declarations are not supported in plist files") def handle_begin_element(self, element, attrs): self.data = [] handler = getattr(self, "begin_" + element, None) if handler is not None: handler(attrs) def handle_end_element(self, element): handler = getattr(self, "end_" + element, None) if handler is not None: handler() def handle_data(self, data): self.data.append(data) def add_object(self, value): if self.current_key is not None: if not isinstance(self.stack[-1], type({})): raise ValueError("unexpected element at line %d" % self.parser.CurrentLineNumber) self.stack[-1][self.current_key] = value self.current_key = None elif not self.stack: # this is the root object self.root = value else: if not isinstance(self.stack[-1], type([])): raise ValueError("unexpected element at line %d" % self.parser.CurrentLineNumber) self.stack[-1].append(value) def get_data(self): data = ''.join(self.data) self.data = [] return data # element handlers def begin_dict(self, attrs): d = self._dict_type() self.add_object(d) self.stack.append(d) def end_dict(self): if self.current_key: raise ValueError("missing value for key '%s' at line %d" % (self.current_key,self.parser.CurrentLineNumber)) self.stack.pop() def end_key(self): if self.current_key or not isinstance(self.stack[-1], type({})): raise ValueError("unexpected key at line %d" % self.parser.CurrentLineNumber) self.current_key = self.get_data() def begin_array(self, attrs): a = [] self.add_object(a) self.stack.append(a) def end_array(self): self.stack.pop() def end_true(self): self.add_object(True) def end_false(self): self.add_object(False) def end_integer(self): self.add_object(int(self.get_data())) def end_real(self): self.add_object(float(self.get_data())) def end_string(self): self.add_object(self.get_data()) def end_data(self): if self._use_builtin_types: self.add_object(_decode_base64(self.get_data())) else: self.add_object(Data.fromBase64(self.get_data())) def end_date(self): self.add_object(_date_from_string(self.get_data())) class _DumbXMLWriter: def __init__(self, file, indent_level=0, indent="\t"): self.file = file self.stack = [] self._indent_level = indent_level self.indent = indent def begin_element(self, element): self.stack.append(element) self.writeln("<%s>" % element) self._indent_level += 1 def end_element(self, element): assert self._indent_level > 0 assert self.stack.pop() == element self._indent_level -= 1 self.writeln("</%s>" % element) def simple_element(self, element, value=None): if value is not None: value = _escape(value) self.writeln("<%s>%s</%s>" % (element, value, element)) else: self.writeln("<%s/>" % element) def writeln(self, line): if line: # plist has fixed encoding of utf-8 # XXX: is this test needed? if isinstance(line, str): line = line.encode('utf-8') self.file.write(self._indent_level * self.indent) self.file.write(line) self.file.write(b'\n') class _PlistWriter(_DumbXMLWriter): def __init__( self, file, indent_level=0, indent=b"\t", writeHeader=1, sort_keys=True, skipkeys=False): if writeHeader: file.write(PLISTHEADER) _DumbXMLWriter.__init__(self, file, indent_level, indent) self._sort_keys = sort_keys self._skipkeys = skipkeys def write(self, value): self.writeln("<plist version=\"1.0\">") self.write_value(value) self.writeln("</plist>") def write_value(self, value): if isinstance(value, str): self.simple_element("string", value) elif value is True: self.simple_element("true") elif value is False: self.simple_element("false") elif isinstance(value, int): if -1 << 63 <= value < 1 << 64: self.simple_element("integer", "%d" % value) else: raise OverflowError(value) elif isinstance(value, float): self.simple_element("real", repr(value)) elif isinstance(value, dict): self.write_dict(value) elif isinstance(value, Data): self.write_data(value) elif isinstance(value, (bytes, bytearray)): self.write_bytes(value) elif isinstance(value, datetime.datetime): self.simple_element("date", _date_to_string(value)) elif isinstance(value, (tuple, list)): self.write_array(value) else: raise TypeError("unsupported type: %s" % type(value)) def write_data(self, data): self.write_bytes(data.data) def write_bytes(self, data): self.begin_element("data") self._indent_level -= 1 maxlinelength = max( 16, 76 - len(self.indent.replace(b"\t", b" " * 8) * self._indent_level)) for line in _encode_base64(data, maxlinelength).split(b"\n"): if line: self.writeln(line) self._indent_level += 1 self.end_element("data") def write_dict(self, d): if d: self.begin_element("dict") if self._sort_keys: items = sorted(d.items()) else: items = d.items() for key, value in items: if not isinstance(key, str): if self._skipkeys: continue raise TypeError("keys must be strings") self.simple_element("key", key) self.write_value(value) self.end_element("dict") else: self.simple_element("dict") def write_array(self, array): if array: self.begin_element("array") for value in array: self.write_value(value) self.end_element("array") else: self.simple_element("array") def _is_fmt_xml(header): prefixes = (b'<?xml', b'<plist') for pfx in prefixes: if header.startswith(pfx): return True # Also check for alternative XML encodings, this is slightly # overkill because the Apple tools (and plistlib) will not # generate files with these encodings. for bom, encoding in ( (codecs.BOM_UTF8, "utf-8"), (codecs.BOM_UTF16_BE, "utf-16-be"), (codecs.BOM_UTF16_LE, "utf-16-le"), # expat does not support utf-32 #(codecs.BOM_UTF32_BE, "utf-32-be"), #(codecs.BOM_UTF32_LE, "utf-32-le"), ): if not header.startswith(bom): continue for start in prefixes: prefix = bom + start.decode('ascii').encode(encoding) if header[:len(prefix)] == prefix: return True return False # # Binary Plist # class InvalidFileException (ValueError): def __init__(self, message="Invalid file"): ValueError.__init__(self, message) _BINARY_FORMAT = {1: 'B', 2: 'H', 4: 'L', 8: 'Q'} _undefined = object() class _BinaryPlistParser: """ Read or write a binary plist file, following the description of the binary format. Raise InvalidFileException in case of error, otherwise return the root object. see also: http://opensource.apple.com/source/CF/CF-744.18/CFBinaryPList.c """ def __init__(self, use_builtin_types, dict_type): self._use_builtin_types = use_builtin_types self._dict_type = dict_type def parse(self, fp): try: # The basic file format: # HEADER # object... # refid->offset... # TRAILER self._fp = fp self._fp.seek(-32, os.SEEK_END) trailer = self._fp.read(32) if len(trailer) != 32: raise InvalidFileException() ( offset_size, self._ref_size, num_objects, top_object, offset_table_offset ) = struct.unpack('>6xBBQQQ', trailer) self._fp.seek(offset_table_offset) self._object_offsets = self._read_ints(num_objects, offset_size) self._objects = [_undefined] * num_objects return self._read_object(top_object) except (OSError, IndexError, struct.error, OverflowError, ValueError): raise InvalidFileException() def _get_size(self, tokenL): """ return the size of the next object.""" if tokenL == 0xF: m = self._fp.read(1)[0] & 0x3 s = 1 << m f = '>' + _BINARY_FORMAT[s] return struct.unpack(f, self._fp.read(s))[0] return tokenL def _read_ints(self, n, size): data = self._fp.read(size * n) if size in _BINARY_FORMAT: return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data) else: if not size or len(data) != size * n: raise InvalidFileException() return tuple(int.from_bytes(data[i: i + size], 'big') for i in range(0, size * n, size)) def _read_refs(self, n): return self._read_ints(n, self._ref_size) def _read_object(self, ref): """ read the object by reference. May recursively read sub-objects (content of an array/dict/set) """ result = self._objects[ref] if result is not _undefined: return result offset = self._object_offsets[ref] self._fp.seek(offset) token = self._fp.read(1)[0] tokenH, tokenL = token & 0xF0, token & 0x0F if token == 0x00: result = None elif token == 0x08: result = False elif token == 0x09: result = True # The referenced source code also mentions URL (0x0c, 0x0d) and # UUID (0x0e), but neither can be generated using the Cocoa libraries. elif token == 0x0f: result = b'' elif tokenH == 0x10: # int result = int.from_bytes(self._fp.read(1 << tokenL), 'big', signed=tokenL >= 3) elif token == 0x22: # real result = struct.unpack('>f', self._fp.read(4))[0] elif token == 0x23: # real result = struct.unpack('>d', self._fp.read(8))[0] elif token == 0x33: # date f = struct.unpack('>d', self._fp.read(8))[0] # timestamp 0 of binary plists corresponds to 1/1/2001 # (year of Mac OS X 10.0), instead of 1/1/1970. result = (datetime.datetime(2001, 1, 1) + datetime.timedelta(seconds=f)) elif tokenH == 0x40: # data s = self._get_size(tokenL) result = self._fp.read(s) if len(result) != s: raise InvalidFileException() if not self._use_builtin_types: result = Data(result) elif tokenH == 0x50: # ascii string s = self._get_size(tokenL) data = self._fp.read(s) if len(data) != s: raise InvalidFileException() result = data.decode('ascii') elif tokenH == 0x60: # unicode string s = self._get_size(tokenL) * 2 data = self._fp.read(s) if len(data) != s: raise InvalidFileException() result = data.decode('utf-16be') # tokenH == 0x80 is documented as 'UID' and appears to be used for # keyed-archiving, not in plists. elif tokenH == 0xA0: # array s = self._get_size(tokenL) obj_refs = self._read_refs(s) result = [] self._objects[ref] = result result.extend(self._read_object(x) for x in obj_refs) # tokenH == 0xB0 is documented as 'ordset', but is not actually # implemented in the Apple reference code. # tokenH == 0xC0 is documented as 'set', but sets cannot be used in # plists. elif tokenH == 0xD0: # dict s = self._get_size(tokenL) key_refs = self._read_refs(s) obj_refs = self._read_refs(s) result = self._dict_type() self._objects[ref] = result try: for k, o in zip(key_refs, obj_refs): result[self._read_object(k)] = self._read_object(o) except TypeError: raise InvalidFileException() else: raise InvalidFileException() self._objects[ref] = result return result def _count_to_size(count): if count < 1 << 8: return 1 elif count < 1 << 16: return 2 elif count << 1 << 32: return 4 else: return 8 _scalars = (str, int, float, datetime.datetime, bytes) class _BinaryPlistWriter (object): def __init__(self, fp, sort_keys, skipkeys): self._fp = fp self._sort_keys = sort_keys self._skipkeys = skipkeys def write(self, value): # Flattened object list: self._objlist = [] # Mappings from object->objectid # First dict has (type(object), object) as the key, # second dict is used when object is not hashable and # has id(object) as the key. self._objtable = {} self._objidtable = {} # Create list of all objects in the plist self._flatten(value) # Size of object references in serialized containers # depends on the number of objects in the plist. num_objects = len(self._objlist) self._object_offsets = [0]*num_objects self._ref_size = _count_to_size(num_objects) self._ref_format = _BINARY_FORMAT[self._ref_size] # Write file header self._fp.write(b'bplist00') # Write object list for obj in self._objlist: self._write_object(obj) # Write refnum->object offset table top_object = self._getrefnum(value) offset_table_offset = self._fp.tell() offset_size = _count_to_size(offset_table_offset) offset_format = '>' + _BINARY_FORMAT[offset_size] * num_objects self._fp.write(struct.pack(offset_format, *self._object_offsets)) # Write trailer sort_version = 0 trailer = ( sort_version, offset_size, self._ref_size, num_objects, top_object, offset_table_offset ) self._fp.write(struct.pack('>5xBBBQQQ', *trailer)) def _flatten(self, value): # First check if the object is in the object table, not used for # containers to ensure that two subcontainers with the same contents # will be serialized as distinct values. if isinstance(value, _scalars): if (type(value), value) in self._objtable: return elif isinstance(value, Data): if (type(value.data), value.data) in self._objtable: return elif id(value) in self._objidtable: return # Add to objectreference map refnum = len(self._objlist) self._objlist.append(value) if isinstance(value, _scalars): self._objtable[(type(value), value)] = refnum elif isinstance(value, Data): self._objtable[(type(value.data), value.data)] = refnum else: self._objidtable[id(value)] = refnum # And finally recurse into containers if isinstance(value, dict): keys = [] values = [] items = value.items() if self._sort_keys: items = sorted(items) for k, v in items: if not isinstance(k, str): if self._skipkeys: continue raise TypeError("keys must be strings") keys.append(k) values.append(v) for o in itertools.chain(keys, values): self._flatten(o) elif isinstance(value, (list, tuple)): for o in value: self._flatten(o) def _getrefnum(self, value): if isinstance(value, _scalars): return self._objtable[(type(value), value)] elif isinstance(value, Data): return self._objtable[(type(value.data), value.data)] else: return self._objidtable[id(value)] def _write_size(self, token, size): if size < 15: self._fp.write(struct.pack('>B', token | size)) elif size < 1 << 8: self._fp.write(struct.pack('>BBB', token | 0xF, 0x10, size)) elif size < 1 << 16: self._fp.write(struct.pack('>BBH', token | 0xF, 0x11, size)) elif size < 1 << 32: self._fp.write(struct.pack('>BBL', token | 0xF, 0x12, size)) else: self._fp.write(struct.pack('>BBQ', token | 0xF, 0x13, size)) def _write_object(self, value): ref = self._getrefnum(value) self._object_offsets[ref] = self._fp.tell() if value is None: self._fp.write(b'\x00') elif value is False: self._fp.write(b'\x08') elif value is True: self._fp.write(b'\x09') elif isinstance(value, int): if value < 0: try: self._fp.write(struct.pack('>Bq', 0x13, value)) except struct.error: raise OverflowError(value) from None elif value < 1 << 8: self._fp.write(struct.pack('>BB', 0x10, value)) elif value < 1 << 16: self._fp.write(struct.pack('>BH', 0x11, value)) elif value < 1 << 32: self._fp.write(struct.pack('>BL', 0x12, value)) elif value < 1 << 63: self._fp.write(struct.pack('>BQ', 0x13, value)) elif value < 1 << 64: self._fp.write(b'\x14' + value.to_bytes(16, 'big', signed=True)) else: raise OverflowError(value) elif isinstance(value, float): self._fp.write(struct.pack('>Bd', 0x23, value)) elif isinstance(value, datetime.datetime): f = (value - datetime.datetime(2001, 1, 1)).total_seconds() self._fp.write(struct.pack('>Bd', 0x33, f)) elif isinstance(value, Data): self._write_size(0x40, len(value.data)) self._fp.write(value.data) elif isinstance(value, (bytes, bytearray)): self._write_size(0x40, len(value)) self._fp.write(value) elif isinstance(value, str): try: t = value.encode('ascii') self._write_size(0x50, len(value)) except UnicodeEncodeError: t = value.encode('utf-16be') self._write_size(0x60, len(t) // 2) self._fp.write(t) elif isinstance(value, (list, tuple)): refs = [self._getrefnum(o) for o in value] s = len(refs) self._write_size(0xA0, s) self._fp.write(struct.pack('>' + self._ref_format * s, *refs)) elif isinstance(value, dict): keyRefs, valRefs = [], [] if self._sort_keys: rootItems = sorted(value.items()) else: rootItems = value.items() for k, v in rootItems: if not isinstance(k, str): if self._skipkeys: continue raise TypeError("keys must be strings") keyRefs.append(self._getrefnum(k)) valRefs.append(self._getrefnum(v)) s = len(keyRefs) self._write_size(0xD0, s) self._fp.write(struct.pack('>' + self._ref_format * s, *keyRefs)) self._fp.write(struct.pack('>' + self._ref_format * s, *valRefs)) else: raise TypeError(value) def _is_fmt_binary(header): return header[:8] == b'bplist00' # # Generic bits # _FORMATS={ FMT_XML: dict( detect=_is_fmt_xml, parser=_PlistParser, writer=_PlistWriter, ), FMT_BINARY: dict( detect=_is_fmt_binary, parser=_BinaryPlistParser, writer=_BinaryPlistWriter, ) } def load(fp, *, fmt=None, use_builtin_types=True, dict_type=dict): """Read a .plist file. 'fp' should be a readable and binary file object. Return the unpacked root object (which usually is a dictionary). """ if fmt is None: header = fp.read(32) fp.seek(0) for info in _FORMATS.values(): if info['detect'](header): P = info['parser'] break else: raise InvalidFileException() else: P = _FORMATS[fmt]['parser'] p = P(use_builtin_types=use_builtin_types, dict_type=dict_type) return p.parse(fp) def loads(value, *, fmt=None, use_builtin_types=True, dict_type=dict): """Read a .plist file from a bytes object. Return the unpacked root object (which usually is a dictionary). """ fp = BytesIO(value) return load( fp, fmt=fmt, use_builtin_types=use_builtin_types, dict_type=dict_type) def dump(value, fp, *, fmt=FMT_XML, sort_keys=True, skipkeys=False): """Write 'value' to a .plist file. 'fp' should be a writable, binary file object. """ if fmt not in _FORMATS: raise ValueError("Unsupported format: %r"%(fmt,)) writer = _FORMATS[fmt]["writer"](fp, sort_keys=sort_keys, skipkeys=skipkeys) writer.write(value) def dumps(value, *, fmt=FMT_XML, skipkeys=False, sort_keys=True): """Return a bytes object with the contents for a .plist file. """ fp = BytesIO() dump(value, fp, fmt=fmt, skipkeys=skipkeys, sort_keys=sort_keys) return fp.getvalue()
Save
cmd:
run