diff options
Diffstat (limited to 'Lib/plat-mac/plistlib.py')
-rw-r--r-- | Lib/plat-mac/plistlib.py | 648 |
1 files changed, 324 insertions, 324 deletions
diff --git a/Lib/plat-mac/plistlib.py b/Lib/plat-mac/plistlib.py index 9c914d2..40e2675 100644 --- a/Lib/plat-mac/plistlib.py +++ b/Lib/plat-mac/plistlib.py @@ -33,29 +33,29 @@ The <date> plist data has (limited) support through the Date class. 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) + 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 + pl = Plist.fromFile(pathOrFile) + print pl.aKey """ @@ -71,40 +71,40 @@ INDENT = "\t" class DumbXMLWriter: - def __init__(self, file): - self.file = file - self.stack = [] - self.indentLevel = 0 + 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 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 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 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 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") + text = text.replace("&", "&") + text = text.replace("<", "<") + return text.encode("utf-8") PLISTHEADER = """\ @@ -114,323 +114,323 @@ PLISTHEADER = """\ 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") + 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.""" + """Dict wrapper for convenient access of values through attributes.""" - def __init__(self, **kwargs): - self.__dict__.update(kwargs) + 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 __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 __str__(self): + return "%s(**%s)" % (self.__class__.__name__, self.__dict__) + __repr__ = __str__ - def copy(self): - return self.__class__(**self.__dict__) + def copy(self): + return self.__class__(**self.__dict__) - def __getattr__(self, attr): - """Delegate everything else to the dict object.""" - return getattr(self.__dict__, attr) + 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() + """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.""" + """Wrapper for binary data.""" - def __init__(self, data): - self.data = data + def __init__(self, data): + self.data = data - def fromBase64(cls, data): - import base64 - return cls(base64.decodestring(data)) - fromBase64 = classmethod(fromBase64) + 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 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 __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)) + 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. - """ + """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 __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 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 __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())) + 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())) + 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) + # 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 + # 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) + 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) |