diff options
Diffstat (limited to 'Mac/Lib/plistlib.py')
-rw-r--r-- | Mac/Lib/plistlib.py | 436 |
1 files changed, 0 insertions, 436 deletions
diff --git a/Mac/Lib/plistlib.py b/Mac/Lib/plistlib.py deleted file mode 100644 index 9c914d2..0000000 --- a/Mac/Lib/plistlib.py +++ /dev/null @@ -1,436 +0,0 @@ -"""plistlib.py -- a tool to generate and parse MacOSX .plist files. - -The main class in this module is Plist. It takes a set of arbitrary -keyword arguments, which will be the top level elements of the plist -dictionary. After instantiation you can add more elements by assigning -new attributes to the Plist instance. - -To write out a plist file, call the write() method of the Plist -instance with a filename or a file object. - -To parse a plist from a file, use the Plist.fromFile(pathOrFile) -classmethod, with a file name or a file object as the only argument. -(Warning: you need pyexpat installed for this to work, ie. it doesn't -work with a vanilla Python 2.2 as shipped with MacOS X.2.) - -Values can be strings, integers, floats, booleans, tuples, lists, -dictionaries, Data or Date objects. String values (including dictionary -keys) may be unicode strings -- they will be written out as UTF-8. - -For convenience, this module exports a class named Dict(), which -allows you to easily construct (nested) dicts using keyword arguments. -But regular dicts work, too. - -To support Boolean values in plists with Python < 2.3, "bool", "True" -and "False" are exported. Use these symbols from this module if you -want to be compatible with Python 2.2.x (strongly recommended). - -The <data> plist type is supported through the Data class. This is a -thin wrapper around a Python string. - -The <date> plist data has (limited) support through the Date class. -(Warning: Dates are only supported if the PyXML package is installed.) - -Generate Plist example: - - pl = Plist( - aString="Doodah", - aList=["A", "B", 12, 32.1, [1, 2, 3]], - aFloat = 0.1, - anInt = 728, - aDict=Dict( - anotherString="<hello & hi there!>", - aUnicodeValue=u'M\xe4ssig, Ma\xdf', - aTrueValue=True, - aFalseValue=False, - ), - someData = Data("<binary gunk>"), - someMoreData = Data("<lots of binary gunk>" * 10), - aDate = Date(time.mktime(time.gmtime())), - ) - # unicode keys are possible, but a little awkward to use: - pl[u'\xc5benraa'] = "That was a unicode key." - pl.write(fileName) - -Parse Plist example: - - pl = Plist.fromFile(pathOrFile) - print pl.aKey - - -""" - -# written by Just van Rossum (just@letterror.com), 2002-11-19 - - -__all__ = ["Plist", "Data", "Date", "Dict", "False", "True", "bool"] - - -INDENT = "\t" - - -class DumbXMLWriter: - - def __init__(self, file): - self.file = file - self.stack = [] - self.indentLevel = 0 - - def beginElement(self, element): - self.stack.append(element) - self.writeln("<%s>" % element) - self.indentLevel += 1 - - def endElement(self, element): - assert self.indentLevel > 0 - assert self.stack.pop() == element - self.indentLevel -= 1 - self.writeln("</%s>" % element) - - def simpleElement(self, element, value=None): - if value: - value = _encode(value) - self.writeln("<%s>%s</%s>" % (element, value, element)) - else: - self.writeln("<%s/>" % element) - - def writeln(self, line): - if line: - self.file.write(self.indentLevel * INDENT + line + "\n") - else: - self.file.write("\n") - - -def _encode(text): - text = text.replace("&", "&") - text = text.replace("<", "<") - return text.encode("utf-8") - - -PLISTHEADER = """\ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> -""" - -class PlistWriter(DumbXMLWriter): - - def __init__(self, file): - file.write(PLISTHEADER) - DumbXMLWriter.__init__(self, file) - - def writeValue(self, value): - if isinstance(value, (str, unicode)): - self.simpleElement("string", value) - elif isinstance(value, bool): - # must switch for bool before int, as bool is a - # subclass of int... - if value: - self.simpleElement("true") - else: - self.simpleElement("false") - elif isinstance(value, int): - self.simpleElement("integer", str(value)) - elif isinstance(value, float): - # should perhaps use repr() for better precision? - self.simpleElement("real", str(value)) - elif isinstance(value, (dict, Dict)): - self.writeDict(value) - elif isinstance(value, Data): - self.writeData(value) - elif isinstance(value, Date): - self.simpleElement("date", value.toString()) - elif isinstance(value, (tuple, list)): - self.writeArray(value) - else: - assert 0, "unsuported type: %s" % type(value) - - def writeData(self, data): - self.beginElement("data") - for line in data.asBase64().split("\n"): - if line: - self.writeln(line) - self.endElement("data") - - def writeDict(self, d): - self.beginElement("dict") - items = d.items() - items.sort() - for key, value in items: - assert isinstance(key, (str, unicode)), "keys must be strings" - self.simpleElement("key", key) - self.writeValue(value) - self.endElement("dict") - - def writeArray(self, array): - self.beginElement("array") - for value in array: - self.writeValue(value) - self.endElement("array") - - -class Dict: - - """Dict wrapper for convenient access of values through attributes.""" - - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - def __cmp__(self, other): - if isinstance(other, self.__class__): - return cmp(self.__dict__, other.__dict__) - elif isinstance(other, dict): - return cmp(self.__dict__, other) - else: - return cmp(id(self), id(other)) - - def __str__(self): - return "%s(**%s)" % (self.__class__.__name__, self.__dict__) - __repr__ = __str__ - - def copy(self): - return self.__class__(**self.__dict__) - - def __getattr__(self, attr): - """Delegate everything else to the dict object.""" - return getattr(self.__dict__, attr) - - -class Plist(Dict): - - """The main Plist object. Basically a dict (the toplevel object - of a plist is a dict) with two additional methods to read from - and write to files. - """ - - def fromFile(cls, pathOrFile): - didOpen = 0 - if not hasattr(pathOrFile, "write"): - pathOrFile = open(pathOrFile) - didOpen = 1 - p = PlistParser() - plist = p.parse(pathOrFile) - if didOpen: - pathOrFile.close() - return plist - fromFile = classmethod(fromFile) - - def write(self, pathOrFile): - if not hasattr(pathOrFile, "write"): - pathOrFile = open(pathOrFile, "w") - didOpen = 1 - else: - didOpen = 0 - - writer = PlistWriter(pathOrFile) - writer.writeln("<plist version=\"1.0\">") - writer.writeDict(self.__dict__) - writer.writeln("</plist>") - - if didOpen: - pathOrFile.close() - - -class Data: - - """Wrapper for binary data.""" - - def __init__(self, data): - self.data = data - - def fromBase64(cls, data): - import base64 - return cls(base64.decodestring(data)) - fromBase64 = classmethod(fromBase64) - - def asBase64(self): - import base64 - return base64.encodestring(self.data) - - def __cmp__(self, other): - if isinstance(other, self.__class__): - return cmp(self.data, other.data) - elif isinstance(other, str): - return cmp(self.data, other) - else: - return cmp(id(self), id(other)) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self.data)) - - -class Date: - - """Primitive date wrapper, uses time floats internally, is agnostic - about time zones. - """ - - def __init__(self, date): - if isinstance(date, str): - from xml.utils.iso8601 import parse - date = parse(date) - self.date = date - - def toString(self): - from xml.utils.iso8601 import tostring - return tostring(self.date) - - def __cmp__(self, other): - if isinstance(other, self.__class__): - return cmp(self.date, other.date) - elif isinstance(other, (int, float)): - return cmp(self.date, other) - else: - return cmp(id(self), id(other)) - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, repr(self.toString())) - - -class PlistParser: - - def __init__(self): - self.stack = [] - self.currentKey = None - self.root = None - - def parse(self, file): - from xml.parsers.expat import ParserCreate - parser = ParserCreate() - parser.StartElementHandler = self.handleBeginElement - parser.EndElementHandler = self.handleEndElement - parser.CharacterDataHandler = self.handleData - parser.ParseFile(file) - return self.root - - def handleBeginElement(self, element, attrs): - self.data = [] - handler = getattr(self, "begin_" + element, None) - if handler is not None: - handler(attrs) - - def handleEndElement(self, element): - handler = getattr(self, "end_" + element, None) - if handler is not None: - handler() - - def handleData(self, data): - self.data.append(data) - - def addObject(self, value): - if self.currentKey is not None: - self.stack[-1][self.currentKey] = value - self.currentKey = None - elif not self.stack: - # this is the root object - assert self.root is value - else: - self.stack[-1].append(value) - - def getData(self): - data = "".join(self.data) - try: - data = data.encode("ascii") - except UnicodeError: - pass - self.data = [] - return data - - # element handlers - - def begin_dict(self, attrs): - if self.root is None: - self.root = d = Plist() - else: - d = Dict() - self.addObject(d) - self.stack.append(d) - def end_dict(self): - self.stack.pop() - - def end_key(self): - self.currentKey = self.getData() - - def begin_array(self, attrs): - a = [] - self.addObject(a) - self.stack.append(a) - def end_array(self): - self.stack.pop() - - def end_true(self): - self.addObject(True) - def end_false(self): - self.addObject(False) - def end_integer(self): - self.addObject(int(self.getData())) - def end_real(self): - self.addObject(float(self.getData())) - def end_string(self): - self.addObject(self.getData()) - def end_data(self): - self.addObject(Data.fromBase64(self.getData())) - def end_date(self): - self.addObject(Date(self.getData())) - - -# cruft to support booleans in Python <= 2.3 -import sys -if sys.version_info[:2] < (2, 3): - # Python 2.2 and earlier: no booleans - # Python 2.2.x: booleans are ints - class bool(int): - """Imitation of the Python 2.3 bool object.""" - def __new__(cls, value): - return int.__new__(cls, not not value) - def __repr__(self): - if self: - return "True" - else: - return "False" - True = bool(1) - False = bool(0) -else: - # Bind the boolean builtins to local names - True = True - False = False - bool = bool - - -if __name__ == "__main__": - from StringIO import StringIO - import time - if len(sys.argv) == 1: - pl = Plist( - aString="Doodah", - aList=["A", "B", 12, 32.1, [1, 2, 3]], - aFloat = 0.1, - anInt = 728, - aDict=Dict( - anotherString="<hello & hi there!>", - aUnicodeValue=u'M\xe4ssig, Ma\xdf', - aTrueValue=True, - aFalseValue=False, - ), - someData = Data("<binary gunk>"), - someMoreData = Data("<lots of binary gunk>" * 10), - aDate = Date(time.mktime(time.gmtime())), - ) - elif len(sys.argv) == 2: - pl = Plist.fromFile(sys.argv[1]) - else: - print "Too many arguments: at most 1 plist file can be given." - sys.exit(1) - - # unicode keys are possible, but a little awkward to use: - pl[u'\xc5benraa'] = "That was a unicode key." - f = StringIO() - pl.write(f) - xml = f.getvalue() - print xml - f.seek(0) - pl2 = Plist.fromFile(f) - assert pl == pl2 - f = StringIO() - pl2.write(f) - assert xml == f.getvalue() - #print repr(pl2) |