1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 from cStringIO import StringIO
25
26 from common import BERException, deflate_long, inflate_long
27 from common import UNIVERSAL, APPLICATION, CONTEXT, PRIVATE
28 from tag import Tag
29
30
31 UNIVERSAL_BOOL = 1
32 UNIVERSAL_INT = 2
33 UNIVERSAL_BYTES = 4
34 UNIVERSAL_NULL = 5
35 UNIVERSAL_UTF8 = 12
36 UNIVERSAL_LIST = 16
37
38 EOF_TYPE = Tag(UNIVERSAL, 0, 0)
39 NULL_TYPE = Tag(UNIVERSAL, UNIVERSAL_NULL)
40 BOOL_TYPE = Tag(UNIVERSAL, UNIVERSAL_BOOL)
41 INT_TYPE = Tag(UNIVERSAL, UNIVERSAL_INT)
42 BYTES_TYPE = Tag(UNIVERSAL, UNIVERSAL_BYTES)
43 UTF8_TYPE = Tag(UNIVERSAL, UNIVERSAL_UTF8)
44 LIST_TYPE = Tag(UNIVERSAL, UNIVERSAL_LIST, container=True)
45
46
49 self._fd = fd
50 self.count = 0
51
53 out = self._fd.read(n)
54 self.count += len(out)
55 return out
56
58 return getattr(self._fd, name)
59
60
62 """
63 FIXME docs
64 """
65
66 _encoder_table = {}
67 _zencoder_table = {}
68 _decoder_table = {}
69
71 self._fd = fd
72 self._bytes_read = 0
73 self._size = size
74 self._hit_eof = False
75 self._advance_tag = None
76
85
87 """
88 Return C{True} if there is still more data left in this stream, and
89 a future call to L{next} should succeed.
90
91 @return: C{True} if the stream has more data to read
92 """
93 if self._size is not None:
94 return self._bytes_read < self._size
95 if self._hit_eof:
96 return False
97
98
99 if self._advance_tag is not None:
100
101 return not self._hit_eof
102 self._advance_tag = self._next_tag()
103 if self._advance_tag == EOF_TYPE:
104 self._hit_eof = True
105 return False
106 return True
107
109 """
110 Return the next item from this stream. Objects are decoded using the
111 codecs registered via the L{decoder} operator, though simple types
112 (None, bool, int, long, str, unicode, list, and tuple) have default
113 decoders.
114
115 @return: the next object from the stream
116 @rtype: object
117 @raise BERException: if you're already at the end of the stream
118 """
119
120 if not self.has_next():
121
122 raise BERException('End of stream')
123
124 if self._advance_tag is not None:
125
126 tag = self._advance_tag
127 self._advance_tag = None
128 else:
129 tag = self._next_tag()
130
131 decoder = self._decoder_table.get(tag, None)
132 if decoder is None:
133 raise BERException('Can\'t decode object of type %r' % (tag,))
134
135
136 count_fd = CountingFile(self._fd)
137 obj = decoder(count_fd, tag)
138 if tag.size is not None:
139 if count_fd.count > tag.size:
140 raise BERException('Overrun in decoder for type %r' % (tag,))
141 if count_fd.count < tag.size:
142 raise BERException('Underrun in decoder for type %r' % (tag,))
143 self._bytes_read += tag.size
144 else:
145
146 self._bytes_read += count_fd.count
147 return obj
148
149 - def add(self, item, compress=False):
150 """
151 Write an object into the stream. Simple types (None, bool, int, long,
152 str, unicode, list, and tuple) are handled by default encoders. Other
153 encoders may be added with the L{encoder} decorator.
154
155 @param item: object to add
156 @type item: object
157 """
158 encoder = BERStream._get_encoder(item, compress)
159 if encoder is None:
160 raise BERException('Can\'t encode object of type %r' % (type(item),))
161 encoder(self._fd, item)
162
165
166 @staticmethod
180
181 @staticmethod
185
186
187
189 self._types = types
190
195
197
198
200 self._types = types
201
206
207
209
210
212 self._type = ttype
213
217
218
220 """
221 Encode a list of items into a container with the given tag and write it
222 to a stream. The list is written using indefinite-length encoding, so
223 no extra copying occurs.
224
225 @param fd: the file object to write into
226 @type fd: file
227 @param tag: the tag to use for this list
228 @type tag: L{Tag}
229 @param items: a list of items to put into the container
230 @type items: list or iterable
231 """
232 Tag.from_tag(tag, None).write(fd)
233 b = BERStream(fd)
234 for x in items:
235 b.add(x)
236 b._add_eof()
237
238
240 """
241 Decode a container into a list of items.
242
243 @param fd: the file object to read from
244 @type fd: file
245 @param tag: the tag from the container
246 @type tag: L{Tag}
247 @return: a list of decoded objects
248 @rtype: list
249 """
250 b = BERStream(fd, tag.size)
251 out = []
252 while b.has_next():
253 out.append(b.next())
254 return out
255
256
257 @encoder(type(None))
260
261 @decoder(NULL_TYPE)
263 return None
264
265 @encoder(bool)
272
273
274 @decoder(BOOL_TYPE)
276 if tag.size != 1:
277 raise BERException('unexpected size of boolean (%d)' % (tag.size,))
278 data = fd.read(1)
279 if len(data) < 1:
280 raise BERException('abrupt end of stream')
281 if ord(data) == 0:
282 return False
283 return True
284
285 @encoder(int, long)
290
291 @decoder(INT_TYPE)
294
295 @encoder(str)
299
300 @decoder(BYTES_TYPE)
303
304 @encoder(unicode)
309
310 @decoder(UTF8_TYPE)
313
314 @encoder(list, tuple)
317
318 @decoder(LIST_TYPE)
321