blob: 49bd5563c9406c2c132924611d4b753d860d60fa [file] [log] [blame]
Just van Rossum0ec27442002-11-19 22:01:02 +00001"""plistlib.py -- a tool to generate and parse MacOSX .plist files.
2
Just van Rossum4c3d0542004-10-02 08:40:47 +00003The PropertList (.plist) file format is a simple XML pickle supporting
4basic object types, like dictionaries, lists, numbers and strings.
5Usually the top level object is a dictionary.
Just van Rossum0ec27442002-11-19 22:01:02 +00006
Just van Rossum4c3d0542004-10-02 08:40:47 +00007To write out a plist file, use the writePlist(rootObject, pathOrFile)
8function. 'rootObject' is the top level object, 'pathOrFile' is a
9filename or a (writable) file object.
Just van Rossum0ec27442002-11-19 22:01:02 +000010
Just van Rossumc6fdd1b2004-10-26 06:50:50 +000011To parse a plist from a file, use the readPlist(pathOrFile) function,
12with a file name or a (readable) file object as the only argument. It
13returns the top level object (again, usually a dictionary).
14
15To work with plist data in strings, you can use readPlistFromString()
16and writePlistToString().
Just van Rossum0ec27442002-11-19 22:01:02 +000017
18Values can be strings, integers, floats, booleans, tuples, lists,
Just van Rossum7c944872004-10-26 07:20:26 +000019dictionaries, Data or datetime.datetime objects. String values (including
20dictionary keys) may be unicode strings -- they will be written out as
21UTF-8.
Just van Rossum0ec27442002-11-19 22:01:02 +000022
Just van Rossum0ec27442002-11-19 22:01:02 +000023The <data> plist type is supported through the Data class. This is a
24thin wrapper around a Python string.
25
Just van Rossum0ec27442002-11-19 22:01:02 +000026Generate Plist example:
27
Just van Rossum368c0b22004-10-26 07:38:16 +000028 pl = dict(
Jack Jansen0ae32202003-04-09 13:25:43 +000029 aString="Doodah",
30 aList=["A", "B", 12, 32.1, [1, 2, 3]],
31 aFloat = 0.1,
32 anInt = 728,
Just van Rossum368c0b22004-10-26 07:38:16 +000033 aDict=dict(
Jack Jansen0ae32202003-04-09 13:25:43 +000034 anotherString="<hello & hi there!>",
35 aUnicodeValue=u'M\xe4ssig, Ma\xdf',
36 aTrueValue=True,
37 aFalseValue=False,
38 ),
39 someData = Data("<binary gunk>"),
40 someMoreData = Data("<lots of binary gunk>" * 10),
Just van Rossum7c944872004-10-26 07:20:26 +000041 aDate = datetime.datetime.fromtimestamp(time.mktime(time.gmtime())),
Jack Jansen0ae32202003-04-09 13:25:43 +000042 )
43 # unicode keys are possible, but a little awkward to use:
44 pl[u'\xc5benraa'] = "That was a unicode key."
Just van Rossum4c3d0542004-10-02 08:40:47 +000045 writePlist(pl, fileName)
Just van Rossum0ec27442002-11-19 22:01:02 +000046
47Parse Plist example:
48
Just van Rossum4c3d0542004-10-02 08:40:47 +000049 pl = readPlist(pathOrFile)
Just van Rossum368c0b22004-10-26 07:38:16 +000050 print pl["aKey"]
Just van Rossum0ec27442002-11-19 22:01:02 +000051"""
52
Just van Rossum4c3d0542004-10-02 08:40:47 +000053
Just van Rossum95387a12004-10-25 15:10:42 +000054__all__ = [
Just van Rossumc6fdd1b2004-10-26 06:50:50 +000055 "readPlist", "writePlist", "readPlistFromString", "writePlistToString",
Just van Rossum95387a12004-10-25 15:10:42 +000056 "readPlistFromResource", "writePlistToResource",
Just van Rossum7c944872004-10-26 07:20:26 +000057 "Plist", "Data", "Dict"
Just van Rossum95387a12004-10-25 15:10:42 +000058]
Just van Rossum368c0b22004-10-26 07:38:16 +000059# Note: the Plist and Dict classes have been deprecated.
Just van Rossum0ec27442002-11-19 22:01:02 +000060
Just van Rossum1f74ef02004-10-26 10:30:55 +000061import binascii
Just van Rossumc6fdd1b2004-10-26 06:50:50 +000062import datetime
63from cStringIO import StringIO
Just van Rossum26e811a2004-11-12 08:02:35 +000064import re
Just van Rossum95387a12004-10-25 15:10:42 +000065
Just van Rossum0ec27442002-11-19 22:01:02 +000066
Just van Rossum4c3d0542004-10-02 08:40:47 +000067def readPlist(pathOrFile):
68 """Read a .plist file. 'pathOrFile' may either be a file name or a
69 (readable) file object. Return the unpacked root object (which
70 usually is a dictionary).
71 """
72 didOpen = 0
73 if isinstance(pathOrFile, (str, unicode)):
74 pathOrFile = open(pathOrFile)
75 didOpen = 1
76 p = PlistParser()
77 rootObject = p.parse(pathOrFile)
78 if didOpen:
79 pathOrFile.close()
80 return rootObject
Just van Rossum0ec27442002-11-19 22:01:02 +000081
82
Just van Rossum4c3d0542004-10-02 08:40:47 +000083def writePlist(rootObject, pathOrFile):
84 """Write 'rootObject' to a .plist file. 'pathOrFile' may either be a
85 file name or a (writable) file object.
86 """
87 didOpen = 0
88 if isinstance(pathOrFile, (str, unicode)):
89 pathOrFile = open(pathOrFile, "w")
90 didOpen = 1
91 writer = PlistWriter(pathOrFile)
92 writer.writeln("<plist version=\"1.0\">")
93 writer.writeValue(rootObject)
94 writer.writeln("</plist>")
95 if didOpen:
96 pathOrFile.close()
Just van Rossum0ec27442002-11-19 22:01:02 +000097
98
Just van Rossumc6fdd1b2004-10-26 06:50:50 +000099def readPlistFromString(data):
100 """Read a plist data from a string. Return the root object.
101 """
102 return readPlist(StringIO(data))
103
104
105def writePlistToString(rootObject):
106 """Return 'rootObject' as a plist-formatted string.
107 """
108 f = StringIO()
109 writePlist(rootObject, f)
110 return f.getvalue()
111
112
Just van Rossum95387a12004-10-25 15:10:42 +0000113def readPlistFromResource(path, restype='plst', resid=0):
114 """Read plst resource from the resource fork of path.
115 """
116 from Carbon.File import FSRef, FSGetResourceForkName
117 from Carbon.Files import fsRdPerm
118 from Carbon import Res
Just van Rossum95387a12004-10-25 15:10:42 +0000119 fsRef = FSRef(path)
120 resNum = Res.FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdPerm)
121 Res.UseResFile(resNum)
Just van Rossumc6fdd1b2004-10-26 06:50:50 +0000122 plistData = Res.Get1Resource(restype, resid).data
Just van Rossum95387a12004-10-25 15:10:42 +0000123 Res.CloseResFile(resNum)
Just van Rossumc6fdd1b2004-10-26 06:50:50 +0000124 return readPlistFromString(plistData)
Just van Rossum95387a12004-10-25 15:10:42 +0000125
126
127def writePlistToResource(rootObject, path, restype='plst', resid=0):
128 """Write 'rootObject' as a plst resource to the resource fork of path.
129 """
130 from Carbon.File import FSRef, FSGetResourceForkName
131 from Carbon.Files import fsRdWrPerm
132 from Carbon import Res
Just van Rossumc6fdd1b2004-10-26 06:50:50 +0000133 plistData = writePlistToString(rootObject)
Just van Rossum95387a12004-10-25 15:10:42 +0000134 fsRef = FSRef(path)
135 resNum = Res.FSOpenResourceFile(fsRef, FSGetResourceForkName(), fsRdWrPerm)
136 Res.UseResFile(resNum)
137 try:
138 Res.Get1Resource(restype, resid).RemoveResource()
139 except Res.Error:
140 pass
141 res = Res.Resource(plistData)
142 res.AddResource(restype, resid, '')
143 res.WriteResource()
144 Res.CloseResFile(resNum)
145
146
Just van Rossum0ec27442002-11-19 22:01:02 +0000147class DumbXMLWriter:
148
Just van Rossum4c3d0542004-10-02 08:40:47 +0000149 def __init__(self, file, indentLevel=0, indent="\t"):
Jack Jansen0ae32202003-04-09 13:25:43 +0000150 self.file = file
151 self.stack = []
Just van Rossum4c3d0542004-10-02 08:40:47 +0000152 self.indentLevel = indentLevel
153 self.indent = indent
Just van Rossum0ec27442002-11-19 22:01:02 +0000154
Jack Jansen0ae32202003-04-09 13:25:43 +0000155 def beginElement(self, element):
156 self.stack.append(element)
157 self.writeln("<%s>" % element)
158 self.indentLevel += 1
Just van Rossum0ec27442002-11-19 22:01:02 +0000159
Jack Jansen0ae32202003-04-09 13:25:43 +0000160 def endElement(self, element):
161 assert self.indentLevel > 0
162 assert self.stack.pop() == element
163 self.indentLevel -= 1
164 self.writeln("</%s>" % element)
Just van Rossum0ec27442002-11-19 22:01:02 +0000165
Jack Jansen0ae32202003-04-09 13:25:43 +0000166 def simpleElement(self, element, value=None):
Just van Rossum87316ec2003-07-10 14:26:06 +0000167 if value is not None:
Just van Rossum4c3d0542004-10-02 08:40:47 +0000168 value = _escapeAndEncode(value)
Jack Jansen0ae32202003-04-09 13:25:43 +0000169 self.writeln("<%s>%s</%s>" % (element, value, element))
170 else:
171 self.writeln("<%s/>" % element)
Just van Rossum0ec27442002-11-19 22:01:02 +0000172
Jack Jansen0ae32202003-04-09 13:25:43 +0000173 def writeln(self, line):
174 if line:
Just van Rossum4c3d0542004-10-02 08:40:47 +0000175 self.file.write(self.indentLevel * self.indent + line + "\n")
Jack Jansen0ae32202003-04-09 13:25:43 +0000176 else:
177 self.file.write("\n")
Just van Rossum0ec27442002-11-19 22:01:02 +0000178
179
Just van Rossum95387a12004-10-25 15:10:42 +0000180# Contents should conform to a subset of ISO 8601
181# (in particular, YYYY '-' MM '-' DD 'T' HH ':' MM ':' SS 'Z'. Smaller units may be omitted with
182# a loss of precision)
183_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")
184
Just van Rossum7c944872004-10-26 07:20:26 +0000185def _dateFromString(s):
186 order = ('year', 'month', 'day', 'hour', 'minute', 'second')
187 gd = _dateParser.match(s).groupdict()
188 lst = []
189 for key in order:
190 val = gd[key]
191 if val is None:
192 break
193 lst.append(int(val))
194 return datetime.datetime(*lst)
195
196def _dateToString(d):
197 return '%04d-%02d-%02dT%02d:%02d:%02dZ' % (
198 d.year, d.month, d.day,
199 d.hour, d.minute, d.second
200 )
201
Just van Rossum26e811a2004-11-12 08:02:35 +0000202
Just van Rossum2dae7642004-11-12 09:36:12 +0000203# Regex to find any control chars, except for \t \n and \r
204_controlCharPat = re.compile(
Just van Rossumb84330d2004-11-12 08:14:49 +0000205 r"[\x00\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f"
206 r"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f]")
Just van Rossum26e811a2004-11-12 08:02:35 +0000207
Just van Rossum4c3d0542004-10-02 08:40:47 +0000208def _escapeAndEncode(text):
Just van Rossum2dae7642004-11-12 09:36:12 +0000209 m = _controlCharPat.search(text)
210 if m is not None:
211 raise ValueError("strings can't contains control characters; "
212 "use plistlib.Data instead")
Just van Rossum4c3d0542004-10-02 08:40:47 +0000213 text = text.replace("\r\n", "\n") # convert DOS line endings
214 text = text.replace("\r", "\n") # convert Mac line endings
215 text = text.replace("&", "&amp;") # escape '&'
216 text = text.replace("<", "&lt;") # escape '<'
Just van Rossum8b8dece2004-10-26 10:11:00 +0000217 text = text.replace(">", "&gt;") # escape '>'
Just van Rossum4c3d0542004-10-02 08:40:47 +0000218 return text.encode("utf-8") # encode as UTF-8
Just van Rossum0ec27442002-11-19 22:01:02 +0000219
220
221PLISTHEADER = """\
222<?xml version="1.0" encoding="UTF-8"?>
223<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
224"""
225
226class PlistWriter(DumbXMLWriter):
227
Just van Rossum4c3d0542004-10-02 08:40:47 +0000228 def __init__(self, file, indentLevel=0, indent="\t", writeHeader=1):
229 if writeHeader:
230 file.write(PLISTHEADER)
231 DumbXMLWriter.__init__(self, file, indentLevel, indent)
Just van Rossum0ec27442002-11-19 22:01:02 +0000232
Jack Jansen0ae32202003-04-09 13:25:43 +0000233 def writeValue(self, value):
234 if isinstance(value, (str, unicode)):
235 self.simpleElement("string", value)
236 elif isinstance(value, bool):
237 # must switch for bool before int, as bool is a
238 # subclass of int...
239 if value:
240 self.simpleElement("true")
241 else:
242 self.simpleElement("false")
243 elif isinstance(value, int):
244 self.simpleElement("integer", str(value))
245 elif isinstance(value, float):
Just van Rossum95387a12004-10-25 15:10:42 +0000246 self.simpleElement("real", repr(value))
Just van Rossum4c3d0542004-10-02 08:40:47 +0000247 elif isinstance(value, dict):
Jack Jansen0ae32202003-04-09 13:25:43 +0000248 self.writeDict(value)
249 elif isinstance(value, Data):
250 self.writeData(value)
Just van Rossum7c944872004-10-26 07:20:26 +0000251 elif isinstance(value, datetime.datetime):
252 self.simpleElement("date", _dateToString(value))
Jack Jansen0ae32202003-04-09 13:25:43 +0000253 elif isinstance(value, (tuple, list)):
254 self.writeArray(value)
255 else:
Just van Rossum94af32e2003-07-01 20:15:38 +0000256 raise TypeError("unsuported type: %s" % type(value))
Just van Rossum0ec27442002-11-19 22:01:02 +0000257
Jack Jansen0ae32202003-04-09 13:25:43 +0000258 def writeData(self, data):
259 self.beginElement("data")
Just van Rossum1f74ef02004-10-26 10:30:55 +0000260 self.indentLevel -= 1
261 maxlinelength = 76 - len(self.indent.replace("\t", " " * 8) *
262 self.indentLevel)
263 for line in data.asBase64(maxlinelength).split("\n"):
Jack Jansen0ae32202003-04-09 13:25:43 +0000264 if line:
265 self.writeln(line)
Just van Rossum1f74ef02004-10-26 10:30:55 +0000266 self.indentLevel += 1
Jack Jansen0ae32202003-04-09 13:25:43 +0000267 self.endElement("data")
Just van Rossum0ec27442002-11-19 22:01:02 +0000268
Jack Jansen0ae32202003-04-09 13:25:43 +0000269 def writeDict(self, d):
270 self.beginElement("dict")
271 items = d.items()
272 items.sort()
273 for key, value in items:
Just van Rossum94af32e2003-07-01 20:15:38 +0000274 if not isinstance(key, (str, unicode)):
275 raise TypeError("keys must be strings")
Jack Jansen0ae32202003-04-09 13:25:43 +0000276 self.simpleElement("key", key)
277 self.writeValue(value)
278 self.endElement("dict")
Just van Rossum0ec27442002-11-19 22:01:02 +0000279
Jack Jansen0ae32202003-04-09 13:25:43 +0000280 def writeArray(self, array):
281 self.beginElement("array")
282 for value in array:
283 self.writeValue(value)
284 self.endElement("array")
Just van Rossum0ec27442002-11-19 22:01:02 +0000285
286
Just van Rossum368c0b22004-10-26 07:38:16 +0000287class _InternalDict(dict):
Just van Rossum0ec27442002-11-19 22:01:02 +0000288
Just van Rossum368c0b22004-10-26 07:38:16 +0000289 # This class is needed while Dict is scheduled for deprecation:
290 # we only need to warn when a *user* instantiates Dict or when
291 # the "attribute notation for dict keys" is used.
Just van Rossum4c3d0542004-10-02 08:40:47 +0000292
Jack Jansen0ae32202003-04-09 13:25:43 +0000293 def __getattr__(self, attr):
Just van Rossum4c3d0542004-10-02 08:40:47 +0000294 try:
295 value = self[attr]
296 except KeyError:
297 raise AttributeError, attr
Just van Rossum368c0b22004-10-26 07:38:16 +0000298 from warnings import warn
299 warn("Attribute access from plist dicts is deprecated, use d[key] "
300 "notation instead", PendingDeprecationWarning)
Just van Rossum4c3d0542004-10-02 08:40:47 +0000301 return value
302
303 def __setattr__(self, attr, value):
Just van Rossum368c0b22004-10-26 07:38:16 +0000304 from warnings import warn
305 warn("Attribute access from plist dicts is deprecated, use d[key] "
306 "notation instead", PendingDeprecationWarning)
Just van Rossum4c3d0542004-10-02 08:40:47 +0000307 self[attr] = value
308
309 def __delattr__(self, attr):
310 try:
311 del self[attr]
312 except KeyError:
313 raise AttributeError, attr
Just van Rossum368c0b22004-10-26 07:38:16 +0000314 from warnings import warn
315 warn("Attribute access from plist dicts is deprecated, use d[key] "
316 "notation instead", PendingDeprecationWarning)
317
318class Dict(_InternalDict):
319
320 def __init__(self, **kwargs):
321 from warnings import warn
322 warn("The plistlib.Dict class is deprecated, use builtin dict instead",
323 PendingDeprecationWarning)
324 super(Dict, self).__init__(**kwargs)
Just van Rossum0ec27442002-11-19 22:01:02 +0000325
326
Just van Rossum368c0b22004-10-26 07:38:16 +0000327class Plist(_InternalDict):
Just van Rossum0ec27442002-11-19 22:01:02 +0000328
Just van Rossum1f74ef02004-10-26 10:30:55 +0000329 """This class has been deprecated. Use readPlist() and writePlist()
Just van Rossum368c0b22004-10-26 07:38:16 +0000330 functions instead, together with regular dict objects.
Jack Jansen0ae32202003-04-09 13:25:43 +0000331 """
Just van Rossum0ec27442002-11-19 22:01:02 +0000332
Just van Rossum86ca9022004-10-25 16:09:10 +0000333 def __init__(self, **kwargs):
334 from warnings import warn
335 warn("The Plist class is deprecated, use the readPlist() and "
336 "writePlist() functions instead", PendingDeprecationWarning)
337 super(Plist, self).__init__(**kwargs)
338
Jack Jansen0ae32202003-04-09 13:25:43 +0000339 def fromFile(cls, pathOrFile):
Just van Rossum86ca9022004-10-25 16:09:10 +0000340 """Deprecated. Use the readPlist() function instead."""
Just van Rossum4c3d0542004-10-02 08:40:47 +0000341 rootObject = readPlist(pathOrFile)
342 plist = cls()
343 plist.update(rootObject)
Jack Jansen0ae32202003-04-09 13:25:43 +0000344 return plist
345 fromFile = classmethod(fromFile)
Just van Rossum0ec27442002-11-19 22:01:02 +0000346
Jack Jansen0ae32202003-04-09 13:25:43 +0000347 def write(self, pathOrFile):
Just van Rossum86ca9022004-10-25 16:09:10 +0000348 """Deprecated. Use the writePlist() function instead."""
Just van Rossum4c3d0542004-10-02 08:40:47 +0000349 writePlist(self, pathOrFile)
Just van Rossum0ec27442002-11-19 22:01:02 +0000350
351
Just van Rossum1f74ef02004-10-26 10:30:55 +0000352def _encodeBase64(s, maxlinelength=76):
353 # copied from base64.encodestring(), with added maxlinelength argument
354 maxbinsize = (maxlinelength//4)*3
355 pieces = []
356 for i in range(0, len(s), maxbinsize):
357 chunk = s[i : i + maxbinsize]
358 pieces.append(binascii.b2a_base64(chunk))
359 return "".join(pieces)
360
Just van Rossum0ec27442002-11-19 22:01:02 +0000361class Data:
362
Jack Jansen0ae32202003-04-09 13:25:43 +0000363 """Wrapper for binary data."""
Just van Rossum0ec27442002-11-19 22:01:02 +0000364
Jack Jansen0ae32202003-04-09 13:25:43 +0000365 def __init__(self, data):
366 self.data = data
Just van Rossum0ec27442002-11-19 22:01:02 +0000367
Jack Jansen0ae32202003-04-09 13:25:43 +0000368 def fromBase64(cls, data):
Just van Rossum1f74ef02004-10-26 10:30:55 +0000369 # base64.decodestring just calls binascii.a2b_base64;
370 # it seems overkill to use both base64 and binascii.
371 return cls(binascii.a2b_base64(data))
Jack Jansen0ae32202003-04-09 13:25:43 +0000372 fromBase64 = classmethod(fromBase64)
Just van Rossum0ec27442002-11-19 22:01:02 +0000373
Just van Rossum1f74ef02004-10-26 10:30:55 +0000374 def asBase64(self, maxlinelength=76):
375 return _encodeBase64(self.data, maxlinelength)
Just van Rossum0ec27442002-11-19 22:01:02 +0000376
Jack Jansen0ae32202003-04-09 13:25:43 +0000377 def __cmp__(self, other):
378 if isinstance(other, self.__class__):
379 return cmp(self.data, other.data)
380 elif isinstance(other, str):
381 return cmp(self.data, other)
382 else:
383 return cmp(id(self), id(other))
Just van Rossum0ec27442002-11-19 22:01:02 +0000384
Jack Jansen0ae32202003-04-09 13:25:43 +0000385 def __repr__(self):
386 return "%s(%s)" % (self.__class__.__name__, repr(self.data))
Just van Rossum0ec27442002-11-19 22:01:02 +0000387
388
Just van Rossum0ec27442002-11-19 22:01:02 +0000389class PlistParser:
390
Jack Jansen0ae32202003-04-09 13:25:43 +0000391 def __init__(self):
392 self.stack = []
393 self.currentKey = None
394 self.root = None
Just van Rossum0ec27442002-11-19 22:01:02 +0000395
Just van Rossum95387a12004-10-25 15:10:42 +0000396 def parse(self, fileobj):
Jack Jansen0ae32202003-04-09 13:25:43 +0000397 from xml.parsers.expat import ParserCreate
398 parser = ParserCreate()
399 parser.StartElementHandler = self.handleBeginElement
400 parser.EndElementHandler = self.handleEndElement
401 parser.CharacterDataHandler = self.handleData
Just van Rossum95387a12004-10-25 15:10:42 +0000402 parser.ParseFile(fileobj)
Jack Jansen0ae32202003-04-09 13:25:43 +0000403 return self.root
Just van Rossum0ec27442002-11-19 22:01:02 +0000404
Jack Jansen0ae32202003-04-09 13:25:43 +0000405 def handleBeginElement(self, element, attrs):
406 self.data = []
407 handler = getattr(self, "begin_" + element, None)
408 if handler is not None:
409 handler(attrs)
Just van Rossum0ec27442002-11-19 22:01:02 +0000410
Jack Jansen0ae32202003-04-09 13:25:43 +0000411 def handleEndElement(self, element):
412 handler = getattr(self, "end_" + element, None)
413 if handler is not None:
414 handler()
Just van Rossum0ec27442002-11-19 22:01:02 +0000415
Jack Jansen0ae32202003-04-09 13:25:43 +0000416 def handleData(self, data):
417 self.data.append(data)
Just van Rossum0ec27442002-11-19 22:01:02 +0000418
Jack Jansen0ae32202003-04-09 13:25:43 +0000419 def addObject(self, value):
420 if self.currentKey is not None:
421 self.stack[-1][self.currentKey] = value
422 self.currentKey = None
423 elif not self.stack:
424 # this is the root object
Just van Rossum4c3d0542004-10-02 08:40:47 +0000425 self.root = value
Jack Jansen0ae32202003-04-09 13:25:43 +0000426 else:
427 self.stack[-1].append(value)
Just van Rossum0ec27442002-11-19 22:01:02 +0000428
Jack Jansen0ae32202003-04-09 13:25:43 +0000429 def getData(self):
430 data = "".join(self.data)
431 try:
432 data = data.encode("ascii")
433 except UnicodeError:
434 pass
435 self.data = []
436 return data
Just van Rossum0ec27442002-11-19 22:01:02 +0000437
Jack Jansen0ae32202003-04-09 13:25:43 +0000438 # element handlers
Just van Rossum0ec27442002-11-19 22:01:02 +0000439
Jack Jansen0ae32202003-04-09 13:25:43 +0000440 def begin_dict(self, attrs):
Just van Rossum368c0b22004-10-26 07:38:16 +0000441 d = _InternalDict()
Jack Jansen0ae32202003-04-09 13:25:43 +0000442 self.addObject(d)
443 self.stack.append(d)
444 def end_dict(self):
445 self.stack.pop()
Just van Rossum0ec27442002-11-19 22:01:02 +0000446
Jack Jansen0ae32202003-04-09 13:25:43 +0000447 def end_key(self):
448 self.currentKey = self.getData()
Just van Rossum0ec27442002-11-19 22:01:02 +0000449
Jack Jansen0ae32202003-04-09 13:25:43 +0000450 def begin_array(self, attrs):
451 a = []
452 self.addObject(a)
453 self.stack.append(a)
454 def end_array(self):
455 self.stack.pop()
Just van Rossum0ec27442002-11-19 22:01:02 +0000456
Jack Jansen0ae32202003-04-09 13:25:43 +0000457 def end_true(self):
458 self.addObject(True)
459 def end_false(self):
460 self.addObject(False)
461 def end_integer(self):
462 self.addObject(int(self.getData()))
463 def end_real(self):
464 self.addObject(float(self.getData()))
465 def end_string(self):
466 self.addObject(self.getData())
467 def end_data(self):
468 self.addObject(Data.fromBase64(self.getData()))
469 def end_date(self):
Just van Rossum7c944872004-10-26 07:20:26 +0000470 self.addObject(_dateFromString(self.getData()))