3 from cStringIO import StringIO
5 from StringIO import StringIO
9 __all__ = ('UnknownElement', 'Element', 'Document', 'INT', 'UINT', 'FLOAT', 'STRING', 'UNICODE', 'DATE', 'BINARY', 'CONTAINER')
12 INT, UINT, FLOAT, STRING, UNICODE, DATE, BINARY, CONTAINER = range(0, 8)
16 INT: read_signed_integer,
17 UINT: read_unsigned_integer,
20 UNICODE: read_unicode_string,
22 BINARY: lambda stream, size: bytearray(stream.read(size))
27 class Substream(object):
28 def __init__(self, stream, offset, size):
34 current_offset = self.tell()
35 if current_offset == 0:
36 self.stream.seek(self.offset)
38 return self.stream.read(self.size)
40 return self.stream.read(size)
42 if current_offset > self.size:
45 max_size = (self.size - current_offset)
47 return self.stream.read(size)
49 return self.stream.read(max_size)
51 def seek(self, offset, whence=os.SEEK_SET):
52 if whence == os.SEEK_SET:
53 desired_offset = self.offset + offset
54 elif whence == os.SEEK_CUR:
55 desired_offset = self.stream.tell() + offset
56 elif whence == os.SEEK_END:
57 desired_offset = self.offset + self.size + offset
59 if not self.offset <= desired_offset:
62 self.stream.seek(desired_offset, os.SEEK_SET)
65 stream_offset = self.stream.tell()
66 if stream_offset <= self.offset:
69 return stream_offset - self.offset
71 def substream(self, offset, size):
72 if offset + size <= self.size:
73 return self.stream.substream(self.offset + offset, size)
77 def __getitem__(self, key):
78 if isinstance(key, (int, long)):
81 elif isinstance(key, slice):
82 if key.start is None or key.stop is None or key.step is not None:
84 return self.substream(key.start, (key.stop - key.start))
88 def __init__(self, file_like):
90 self.file.seek(0, os.SEEK_END)
91 self.size = self.file.tell()
92 self.file.seek(0, os.SEEK_SET)
96 return self.file.read(size)
98 def seek(self, offset, whence=os.SEEK_SET):
99 return self.file.seek(offset, whence)
102 return self.file.tell()
104 def substream(self, offset, size):
105 if offset + size <= self.size:
106 if (offset, size) not in self.substreams:
107 self.substreams[(offset, size)] = self.Substream(self, offset, size)
108 return self.substreams[(offset, size)]
112 def __getitem__(self, key):
113 if isinstance(key, (int, long)):
116 elif isinstance(key, slice):
117 if key.start is None or key.stop is None or key.step is not None:
119 return self.substream(key.start, (key.stop - key.start))
124 class Element(object):
125 __metaclass__ = abc.ABCMeta
127 id = abc.abstractproperty()
128 name = abc.abstractproperty()
129 type = abc.abstractproperty()
135 def __init__(self, document, stream):
136 self.document = document
141 if not hasattr(self, 'cached_value'):
142 if self.type in READERS:
143 self.cached_value = READERS[self.type](self.body_stream, self.body_size)
144 elif self.type == CONTAINER:
145 self.cached_value = read_elements(self.body_stream, self.document, self.children)
147 self.cached_value = None
148 return self.cached_value
152 if not hasattr(self, 'cached_id_size'):
154 _, self.cached_id_size = read_element_id(self.stream)
155 return self.cached_id_size
159 if not hasattr(self, 'cached_size_size'):
160 self.stream.seek(self.id_size)
161 _, self.cached_size_size = read_element_size(self.stream)
162 return self.cached_size_size
166 return self.id_size + self.size_size
170 return self.size - self.head_size
173 def body_stream(self):
174 return self.stream.substream(self.head_size, self.body_size)
178 return self.stream.size
181 class UnknownElement(Element):
186 def __init__(self, document, stream, id):
188 super(UnknownElement, self).__init__(document, stream)
191 def read_elements(stream, document, children):
195 element_offset = stream.size - size
196 stream.seek(element_offset)
197 element_id, element_id_size = read_element_id(stream)
198 element_size, element_size_size = read_element_size(stream)
199 element_stream_size = element_id_size + element_size_size + element_size
200 element_stream = stream.substream(element_offset, element_stream_size)
201 size -= element_stream_size
204 for child in (children + document.globals):
205 if child.id == element_id:
206 element_class = child
209 if element_class is None:
210 element = UnknownElement(document, element_stream, element_id)
212 element = element_class(document, element_stream)
214 elements.append(element)
218 class Document(object):
219 __metaclass__ = abc.ABCMeta
221 type = abc.abstractproperty()
222 version = abc.abstractproperty()
226 def __init__(self, file_like):
227 self.stream = Stream(file_like)
232 if self._roots is None:
233 self._roots = read_elements(self.stream, self, self.children)