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 INT: encode_signed_integer,
28 UINT: encode_unsigned_integer,
30 STRING: encode_string,
31 UNICODE: encode_unicode_string,
33 BINARY: lambda binary, length: binary
38 INT: lambda value: True if isinstance(value, (int, long)) else False,
39 UINT: lambda value: True if isinstance(value, (int, long)) and value == abs(value) else False,
40 FLOAT: lambda value: True if isinstance(value, float) else False,
41 STRING: lambda value: True if isinstance(value, str) else False,
42 UNICODE: lambda value: True if isinstance(value, basestring) else False,
43 DATE: lambda value: True if isinstance(value, datetime.datetime) else False,
44 BINARY: lambda value: True if isinstance(value, (str, bytes, bytearray)) else False
48 class BaseElement(object):
49 __metaclass__ = abc.ABCMeta
51 id = abc.abstractproperty()
52 name = abc.abstractproperty()
53 type = abc.abstractproperty()
60 class UnknownElement(BaseElement):
65 def __init__(self, id, encoding):
67 self.encoding = encoding
70 def read_elements(stream, size, document, children):
72 while (size if size is not None else True):
74 element_id, element_id_size = read_element_id(stream)
75 element_size, element_size_size = read_element_size(stream)
76 element_encoding = (element_size, bytearray(stream.read(element_size)))
81 for child in (children + document.globals):
82 if child.id == element_id:
85 if element_class is None:
86 element = UnknownElement(element_id, element_encoding)
88 element = element_class(document, encoding=element_encoding)
89 elements.append(element)
91 size -= element_id_size + element_size_size + element_size
95 class Element(BaseElement):
97 def check_value(cls, value):
98 if cls.type in VALIDATORS:
99 return VALIDATORS[cls.type](value)
100 elif cls.type == CONTAINER:
101 if isinstance(value, (list, tuple)):
103 if not isinstance(value, Element):
106 elif isinstance(value, Element):
111 raise NotImplementedError('Unsupported element type.')
113 def __init__(self, document, value=None, encoding=None):
114 self.document = document
116 self._encoding = encoding
120 if self._value is None and self._encoding is not None:
121 if self.type in READERS:
122 self._value = READERS[self.type](StringIO(self._encoding[1]), self._encoding[0])
123 elif self.type == CONTAINER:
124 self._value = read_elements(StringIO(self._encoding[1]), self._encoding[0], self.document, self.children)
128 def set_value(self, value):
129 if not self.check_value(value):
130 raise ValueError('Unsupported element value.')
132 self._encoding = None
136 if self._encoding is None:
139 if self._value is not None:
140 if self.type in ENCODERS:
141 data = ENCODERS[self.type](self._value)
143 elif self.type == CONTAINER:
144 for element in self._value:
146 data.extend(element.encoding[1])
147 self._encoding = (size, data)
148 return self._encoding
152 return len(encode_element_id(self.id))
156 return len(encode_element_size(self.body_size))
160 return self.id_size + self.size_size
164 return self.encoding[0]
168 return self.head_size + self.body_size
171 class Document(object):
172 __metaclass__ = abc.ABCMeta
174 type = abc.abstractproperty()
175 version = abc.abstractproperty()
179 def __init__(self, stream):
185 if self._roots is None:
186 self._roots = read_elements(self.stream, None, self, self.children)