65 elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF): |
83 elif long(-0x8000000000000000) <= x <= long(0x7FFFFFFFFFFFFFFF): |
66 return 8 |
84 return 8 |
67 else: |
85 else: |
68 raise RuntimeError('Cannot represent value: ' + str(x)) |
86 raise RuntimeError('Cannot represent value: ' + str(x)) |
69 |
87 |
|
88 def _buf_pos(buf, pos): |
|
89 ret = buf[pos] |
|
90 # In Python 2, buf is a str array so buf[pos] is a string. In Python 3, buf |
|
91 # is a bytes array and buf[pos] is an integer. |
|
92 if compat.PYTHON3: |
|
93 ret = bytes((ret,)) |
|
94 return ret |
70 |
95 |
71 class _bser_buffer(object): |
96 class _bser_buffer(object): |
72 |
97 |
73 def __init__(self): |
98 def __init__(self, version): |
|
99 self.bser_version = version |
74 self.buf = ctypes.create_string_buffer(8192) |
100 self.buf = ctypes.create_string_buffer(8192) |
75 struct.pack_into(str(len(EMPTY_HEADER)) + 's', self.buf, 0, EMPTY_HEADER) |
101 if self.bser_version == 1: |
76 self.wpos = len(EMPTY_HEADER) |
102 struct.pack_into(tobytes(len(EMPTY_HEADER)) + b's', self.buf, 0, |
|
103 EMPTY_HEADER) |
|
104 self.wpos = len(EMPTY_HEADER) |
|
105 else: |
|
106 assert self.bser_version == 2 |
|
107 struct.pack_into(tobytes(len(EMPTY_HEADER_V2)) + b's', self.buf, 0, |
|
108 EMPTY_HEADER_V2) |
|
109 self.wpos = len(EMPTY_HEADER_V2) |
77 |
110 |
78 def ensure_size(self, size): |
111 def ensure_size(self, size): |
79 while ctypes.sizeof(self.buf) - self.wpos < size: |
112 while ctypes.sizeof(self.buf) - self.wpos < size: |
80 ctypes.resize(self.buf, ctypes.sizeof(self.buf) * 2) |
113 ctypes.resize(self.buf, ctypes.sizeof(self.buf) * 2) |
81 |
114 |
82 def append_long(self, val): |
115 def append_long(self, val): |
83 size = _int_size(val) |
116 size = _int_size(val) |
84 to_write = size + 1 |
117 to_write = size + 1 |
85 self.ensure_size(to_write) |
118 self.ensure_size(to_write) |
86 if size == 1: |
119 if size == 1: |
87 struct.pack_into('=cb', self.buf, self.wpos, BSER_INT8, val) |
120 struct.pack_into(b'=cb', self.buf, self.wpos, BSER_INT8, val) |
88 elif size == 2: |
121 elif size == 2: |
89 struct.pack_into('=ch', self.buf, self.wpos, BSER_INT16, val) |
122 struct.pack_into(b'=ch', self.buf, self.wpos, BSER_INT16, val) |
90 elif size == 4: |
123 elif size == 4: |
91 struct.pack_into('=ci', self.buf, self.wpos, BSER_INT32, val) |
124 struct.pack_into(b'=ci', self.buf, self.wpos, BSER_INT32, val) |
92 elif size == 8: |
125 elif size == 8: |
93 struct.pack_into('=cq', self.buf, self.wpos, BSER_INT64, val) |
126 struct.pack_into(b'=cq', self.buf, self.wpos, BSER_INT64, val) |
94 else: |
127 else: |
95 raise RuntimeError('Cannot represent this long value') |
128 raise RuntimeError('Cannot represent this long value') |
96 self.wpos += to_write |
129 self.wpos += to_write |
97 |
130 |
98 |
131 |
122 self.ensure_size(needed) |
159 self.ensure_size(needed) |
123 if val: |
160 if val: |
124 to_encode = BSER_TRUE |
161 to_encode = BSER_TRUE |
125 else: |
162 else: |
126 to_encode = BSER_FALSE |
163 to_encode = BSER_FALSE |
127 struct.pack_into('=c', self.buf, self.wpos, to_encode) |
164 struct.pack_into(b'=c', self.buf, self.wpos, to_encode) |
128 self.wpos += needed |
165 self.wpos += needed |
129 elif val is None: |
166 elif val is None: |
130 needed = 1 |
167 needed = 1 |
131 self.ensure_size(needed) |
168 self.ensure_size(needed) |
132 struct.pack_into('=c', self.buf, self.wpos, BSER_NULL) |
169 struct.pack_into(b'=c', self.buf, self.wpos, BSER_NULL) |
133 self.wpos += needed |
170 self.wpos += needed |
134 elif isinstance(val, (int, long)): |
171 elif isinstance(val, (int, long)): |
135 self.append_long(val) |
172 self.append_long(val) |
136 elif isinstance(val, (str, unicode)): |
173 elif isinstance(val, STRING_TYPES): |
137 self.append_string(val) |
174 self.append_string(val) |
138 elif isinstance(val, float): |
175 elif isinstance(val, float): |
139 needed = 9 |
176 needed = 9 |
140 self.ensure_size(needed) |
177 self.ensure_size(needed) |
141 struct.pack_into('=cd', self.buf, self.wpos, BSER_REAL, val) |
178 struct.pack_into(b'=cd', self.buf, self.wpos, BSER_REAL, val) |
142 self.wpos += needed |
179 self.wpos += needed |
143 elif isinstance(val, collections.Mapping) and isinstance(val, collections.Sized): |
180 elif isinstance(val, collections.Mapping) and \ |
|
181 isinstance(val, collections.Sized): |
144 val_len = len(val) |
182 val_len = len(val) |
145 size = _int_size(val_len) |
183 size = _int_size(val_len) |
146 needed = 2 + size |
184 needed = 2 + size |
147 self.ensure_size(needed) |
185 self.ensure_size(needed) |
148 if size == 1: |
186 if size == 1: |
149 struct.pack_into('=ccb', self.buf, self.wpos, BSER_OBJECT, BSER_INT8, val_len) |
187 struct.pack_into(b'=ccb', self.buf, self.wpos, BSER_OBJECT, |
|
188 BSER_INT8, val_len) |
150 elif size == 2: |
189 elif size == 2: |
151 struct.pack_into('=cch', self.buf, self.wpos, BSER_OBJECT, BSER_INT16, val_len) |
190 struct.pack_into(b'=cch', self.buf, self.wpos, BSER_OBJECT, |
|
191 BSER_INT16, val_len) |
152 elif size == 4: |
192 elif size == 4: |
153 struct.pack_into('=cci', self.buf, self.wpos, BSER_OBJECT, BSER_INT32, val_len) |
193 struct.pack_into(b'=cci', self.buf, self.wpos, BSER_OBJECT, |
|
194 BSER_INT32, val_len) |
154 elif size == 8: |
195 elif size == 8: |
155 struct.pack_into('=ccq', self.buf, self.wpos, BSER_OBJECT, BSER_INT64, val_len) |
196 struct.pack_into(b'=ccq', self.buf, self.wpos, BSER_OBJECT, |
|
197 BSER_INT64, val_len) |
156 else: |
198 else: |
157 raise RuntimeError('Cannot represent this mapping value') |
199 raise RuntimeError('Cannot represent this mapping value') |
158 self.wpos += needed |
200 self.wpos += needed |
159 for k, v in val.iteritems(): |
201 if compat.PYTHON3: |
|
202 iteritems = val.items() |
|
203 else: |
|
204 iteritems = val.iteritems() |
|
205 for k, v in iteritems: |
160 self.append_string(k) |
206 self.append_string(k) |
161 self.append_recursive(v) |
207 self.append_recursive(v) |
162 elif isinstance(val, collections.Iterable) and isinstance(val, collections.Sized): |
208 elif isinstance(val, collections.Iterable) and \ |
|
209 isinstance(val, collections.Sized): |
163 val_len = len(val) |
210 val_len = len(val) |
164 size = _int_size(val_len) |
211 size = _int_size(val_len) |
165 needed = 2 + size |
212 needed = 2 + size |
166 self.ensure_size(needed) |
213 self.ensure_size(needed) |
167 if size == 1: |
214 if size == 1: |
168 struct.pack_into('=ccb', self.buf, self.wpos, BSER_ARRAY, BSER_INT8, val_len) |
215 struct.pack_into(b'=ccb', self.buf, self.wpos, BSER_ARRAY, |
|
216 BSER_INT8, val_len) |
169 elif size == 2: |
217 elif size == 2: |
170 struct.pack_into('=cch', self.buf, self.wpos, BSER_ARRAY, BSER_INT16, val_len) |
218 struct.pack_into(b'=cch', self.buf, self.wpos, BSER_ARRAY, |
|
219 BSER_INT16, val_len) |
171 elif size == 4: |
220 elif size == 4: |
172 struct.pack_into('=cci', self.buf, self.wpos, BSER_ARRAY, BSER_INT32, val_len) |
221 struct.pack_into(b'=cci', self.buf, self.wpos, BSER_ARRAY, |
|
222 BSER_INT32, val_len) |
173 elif size == 8: |
223 elif size == 8: |
174 struct.pack_into('=ccq', self.buf, self.wpos, BSER_ARRAY, BSER_INT64, val_len) |
224 struct.pack_into(b'=ccq', self.buf, self.wpos, BSER_ARRAY, |
|
225 BSER_INT64, val_len) |
175 else: |
226 else: |
176 raise RuntimeError('Cannot represent this sequence value') |
227 raise RuntimeError('Cannot represent this sequence value') |
177 self.wpos += needed |
228 self.wpos += needed |
178 for v in val: |
229 for v in val: |
179 self.append_recursive(v) |
230 self.append_recursive(v) |
180 else: |
231 else: |
181 raise RuntimeError('Cannot represent unknown value type') |
232 raise RuntimeError('Cannot represent unknown value type') |
182 |
233 |
183 |
234 |
184 def dumps(obj): |
235 def dumps(obj, version=1, capabilities=0): |
185 bser_buf = _bser_buffer() |
236 bser_buf = _bser_buffer(version=version) |
186 bser_buf.append_recursive(obj) |
237 bser_buf.append_recursive(obj) |
187 # Now fill in the overall length |
238 # Now fill in the overall length |
188 obj_len = bser_buf.wpos - len(EMPTY_HEADER) |
239 if version == 1: |
189 struct.pack_into('=i', bser_buf.buf, 3, obj_len) |
240 obj_len = bser_buf.wpos - len(EMPTY_HEADER) |
|
241 struct.pack_into(b'=i', bser_buf.buf, 3, obj_len) |
|
242 else: |
|
243 obj_len = bser_buf.wpos - len(EMPTY_HEADER_V2) |
|
244 struct.pack_into(b'=i', bser_buf.buf, 2, capabilities) |
|
245 struct.pack_into(b'=i', bser_buf.buf, 7, obj_len) |
190 return bser_buf.buf.raw[:bser_buf.wpos] |
246 return bser_buf.buf.raw[:bser_buf.wpos] |
191 |
|
192 |
|
193 def _bunser_int(buf, pos): |
|
194 try: |
|
195 int_type = buf[pos] |
|
196 except IndexError: |
|
197 raise ValueError('Invalid bser int encoding, pos out of range') |
|
198 if int_type == BSER_INT8: |
|
199 needed = 2 |
|
200 fmt = '=b' |
|
201 elif int_type == BSER_INT16: |
|
202 needed = 3 |
|
203 fmt = '=h' |
|
204 elif int_type == BSER_INT32: |
|
205 needed = 5 |
|
206 fmt = '=i' |
|
207 elif int_type == BSER_INT64: |
|
208 needed = 9 |
|
209 fmt = '=q' |
|
210 else: |
|
211 raise ValueError('Invalid bser int encoding 0x%02x' % int(int_type)) |
|
212 int_val = struct.unpack_from(fmt, buf, pos + 1)[0] |
|
213 return (int_val, pos + needed) |
|
214 |
|
215 |
|
216 def _bunser_string(buf, pos): |
|
217 str_len, pos = _bunser_int(buf, pos + 1) |
|
218 str_val = struct.unpack_from(str(str_len) + 's', buf, pos)[0] |
|
219 return (str_val, pos + str_len) |
|
220 |
|
221 |
|
222 def _bunser_array(buf, pos, mutable=True): |
|
223 arr_len, pos = _bunser_int(buf, pos + 1) |
|
224 arr = [] |
|
225 for i in range(arr_len): |
|
226 arr_item, pos = _bser_loads_recursive(buf, pos, mutable) |
|
227 arr.append(arr_item) |
|
228 |
|
229 if not mutable: |
|
230 arr = tuple(arr) |
|
231 |
|
232 return arr, pos |
|
233 |
|
234 |
247 |
235 # This is a quack-alike with the bserObjectType in bser.c |
248 # This is a quack-alike with the bserObjectType in bser.c |
236 # It provides by getattr accessors and getitem for both index |
249 # It provides by getattr accessors and getitem for both index |
237 # and name. |
250 # and name. |
238 class _BunserDict(object): |
251 class _BunserDict(object): |
258 raise KeyError('_BunserDict has no key %s' % key) |
271 raise KeyError('_BunserDict has no key %s' % key) |
259 |
272 |
260 def __len__(self): |
273 def __len__(self): |
261 return len(self._keys) |
274 return len(self._keys) |
262 |
275 |
263 def _bunser_object(buf, pos, mutable=True): |
276 class Bunser(object): |
264 obj_len, pos = _bunser_int(buf, pos + 1) |
277 def __init__(self, mutable=True, value_encoding=None, value_errors=None): |
265 if mutable: |
278 self.mutable = mutable |
266 obj = {} |
279 self.value_encoding = value_encoding |
|
280 |
|
281 if value_encoding is None: |
|
282 self.value_errors = None |
|
283 elif value_errors is None: |
|
284 self.value_errors = 'strict' |
|
285 else: |
|
286 self.value_errors = value_errors |
|
287 |
|
288 @staticmethod |
|
289 def unser_int(buf, pos): |
|
290 try: |
|
291 int_type = _buf_pos(buf, pos) |
|
292 except IndexError: |
|
293 raise ValueError('Invalid bser int encoding, pos out of range') |
|
294 if int_type == BSER_INT8: |
|
295 needed = 2 |
|
296 fmt = b'=b' |
|
297 elif int_type == BSER_INT16: |
|
298 needed = 3 |
|
299 fmt = b'=h' |
|
300 elif int_type == BSER_INT32: |
|
301 needed = 5 |
|
302 fmt = b'=i' |
|
303 elif int_type == BSER_INT64: |
|
304 needed = 9 |
|
305 fmt = b'=q' |
|
306 else: |
|
307 raise ValueError('Invalid bser int encoding 0x%s' % |
|
308 binascii.hexlify(int_type).decode('ascii')) |
|
309 int_val = struct.unpack_from(fmt, buf, pos + 1)[0] |
|
310 return (int_val, pos + needed) |
|
311 |
|
312 def unser_utf8_string(self, buf, pos): |
|
313 str_len, pos = self.unser_int(buf, pos + 1) |
|
314 str_val = struct.unpack_from(tobytes(str_len) + b's', buf, pos)[0] |
|
315 return (str_val.decode('utf-8'), pos + str_len) |
|
316 |
|
317 def unser_bytestring(self, buf, pos): |
|
318 str_len, pos = self.unser_int(buf, pos + 1) |
|
319 str_val = struct.unpack_from(tobytes(str_len) + b's', buf, pos)[0] |
|
320 if self.value_encoding is not None: |
|
321 str_val = str_val.decode(self.value_encoding, self.value_errors) |
|
322 # str_len stays the same because that's the length in bytes |
|
323 return (str_val, pos + str_len) |
|
324 |
|
325 def unser_array(self, buf, pos): |
|
326 arr_len, pos = self.unser_int(buf, pos + 1) |
|
327 arr = [] |
|
328 for i in range(arr_len): |
|
329 arr_item, pos = self.loads_recursive(buf, pos) |
|
330 arr.append(arr_item) |
|
331 |
|
332 if not self.mutable: |
|
333 arr = tuple(arr) |
|
334 |
|
335 return arr, pos |
|
336 |
|
337 def unser_object(self, buf, pos): |
|
338 obj_len, pos = self.unser_int(buf, pos + 1) |
|
339 if self.mutable: |
|
340 obj = {} |
|
341 else: |
|
342 keys = [] |
|
343 vals = [] |
|
344 |
|
345 for i in range(obj_len): |
|
346 key, pos = self.unser_utf8_string(buf, pos) |
|
347 val, pos = self.loads_recursive(buf, pos) |
|
348 if self.mutable: |
|
349 obj[key] = val |
|
350 else: |
|
351 keys.append(key) |
|
352 vals.append(val) |
|
353 |
|
354 if not self.mutable: |
|
355 obj = _BunserDict(keys, vals) |
|
356 |
|
357 return obj, pos |
|
358 |
|
359 def unser_template(self, buf, pos): |
|
360 val_type = _buf_pos(buf, pos + 1) |
|
361 if val_type != BSER_ARRAY: |
|
362 raise RuntimeError('Expect ARRAY to follow TEMPLATE') |
|
363 # force UTF-8 on keys |
|
364 keys_bunser = Bunser(mutable=self.mutable, value_encoding='utf-8') |
|
365 keys, pos = keys_bunser.unser_array(buf, pos + 1) |
|
366 nitems, pos = self.unser_int(buf, pos) |
|
367 arr = [] |
|
368 for i in range(nitems): |
|
369 if self.mutable: |
|
370 obj = {} |
|
371 else: |
|
372 vals = [] |
|
373 |
|
374 for keyidx in range(len(keys)): |
|
375 if _buf_pos(buf, pos) == BSER_SKIP: |
|
376 pos += 1 |
|
377 ele = None |
|
378 else: |
|
379 ele, pos = self.loads_recursive(buf, pos) |
|
380 |
|
381 if self.mutable: |
|
382 key = keys[keyidx] |
|
383 obj[key] = ele |
|
384 else: |
|
385 vals.append(ele) |
|
386 |
|
387 if not self.mutable: |
|
388 obj = _BunserDict(keys, vals) |
|
389 |
|
390 arr.append(obj) |
|
391 return arr, pos |
|
392 |
|
393 def loads_recursive(self, buf, pos): |
|
394 val_type = _buf_pos(buf, pos) |
|
395 if (val_type == BSER_INT8 or val_type == BSER_INT16 or |
|
396 val_type == BSER_INT32 or val_type == BSER_INT64): |
|
397 return self.unser_int(buf, pos) |
|
398 elif val_type == BSER_REAL: |
|
399 val = struct.unpack_from(b'=d', buf, pos + 1)[0] |
|
400 return (val, pos + 9) |
|
401 elif val_type == BSER_TRUE: |
|
402 return (True, pos + 1) |
|
403 elif val_type == BSER_FALSE: |
|
404 return (False, pos + 1) |
|
405 elif val_type == BSER_NULL: |
|
406 return (None, pos + 1) |
|
407 elif val_type == BSER_BYTESTRING: |
|
408 return self.unser_bytestring(buf, pos) |
|
409 elif val_type == BSER_UTF8STRING: |
|
410 return self.unser_utf8_string(buf, pos) |
|
411 elif val_type == BSER_ARRAY: |
|
412 return self.unser_array(buf, pos) |
|
413 elif val_type == BSER_OBJECT: |
|
414 return self.unser_object(buf, pos) |
|
415 elif val_type == BSER_TEMPLATE: |
|
416 return self.unser_template(buf, pos) |
|
417 else: |
|
418 raise ValueError('unhandled bser opcode 0x%s' % |
|
419 binascii.hexlify(val_type).decode('ascii')) |
|
420 |
|
421 |
|
422 def _pdu_info_helper(buf): |
|
423 bser_version = -1 |
|
424 if buf[0:2] == EMPTY_HEADER[0:2]: |
|
425 bser_version = 1 |
|
426 bser_capabilities = 0 |
|
427 expected_len, pos2 = Bunser.unser_int(buf, 2) |
|
428 elif buf[0:2] == EMPTY_HEADER_V2[0:2]: |
|
429 if len(buf) < 8: |
|
430 raise ValueError('Invalid BSER header') |
|
431 bser_version = 2 |
|
432 bser_capabilities = struct.unpack_from("I", buf, 2)[0] |
|
433 expected_len, pos2 = Bunser.unser_int(buf, 6) |
267 else: |
434 else: |
268 keys = [] |
435 raise ValueError('Invalid BSER header') |
269 vals = [] |
436 |
270 |
437 return bser_version, bser_capabilities, expected_len, pos2 |
271 for i in range(obj_len): |
438 |
272 key, pos = _bunser_string(buf, pos) |
439 |
273 val, pos = _bser_loads_recursive(buf, pos, mutable) |
440 def pdu_info(buf): |
274 if mutable: |
441 info = _pdu_info_helper(buf) |
275 obj[key] = val |
442 return info[0], info[1], info[2] + info[3] |
276 else: |
|
277 keys.append(key) |
|
278 vals.append(val) |
|
279 |
|
280 if not mutable: |
|
281 obj = _BunserDict(keys, vals) |
|
282 |
|
283 return obj, pos |
|
284 |
|
285 |
|
286 def _bunser_template(buf, pos, mutable=True): |
|
287 if buf[pos + 1] != BSER_ARRAY: |
|
288 raise RuntimeError('Expect ARRAY to follow TEMPLATE') |
|
289 keys, pos = _bunser_array(buf, pos + 1) |
|
290 nitems, pos = _bunser_int(buf, pos) |
|
291 arr = [] |
|
292 for i in range(nitems): |
|
293 if mutable: |
|
294 obj = {} |
|
295 else: |
|
296 vals = [] |
|
297 |
|
298 for keyidx in range(len(keys)): |
|
299 if buf[pos] == BSER_SKIP: |
|
300 pos += 1 |
|
301 ele = None |
|
302 else: |
|
303 ele, pos = _bser_loads_recursive(buf, pos, mutable) |
|
304 |
|
305 if mutable: |
|
306 key = keys[keyidx] |
|
307 obj[key] = ele |
|
308 else: |
|
309 vals.append(ele) |
|
310 |
|
311 if not mutable: |
|
312 obj = _BunserDict(keys, vals) |
|
313 |
|
314 arr.append(obj) |
|
315 return arr, pos |
|
316 |
|
317 |
|
318 def _bser_loads_recursive(buf, pos, mutable=True): |
|
319 val_type = buf[pos] |
|
320 if (val_type == BSER_INT8 or val_type == BSER_INT16 or |
|
321 val_type == BSER_INT32 or val_type == BSER_INT64): |
|
322 return _bunser_int(buf, pos) |
|
323 elif val_type == BSER_REAL: |
|
324 val = struct.unpack_from('=d', buf, pos + 1)[0] |
|
325 return (val, pos + 9) |
|
326 elif val_type == BSER_TRUE: |
|
327 return (True, pos + 1) |
|
328 elif val_type == BSER_FALSE: |
|
329 return (False, pos + 1) |
|
330 elif val_type == BSER_NULL: |
|
331 return (None, pos + 1) |
|
332 elif val_type == BSER_STRING: |
|
333 return _bunser_string(buf, pos) |
|
334 elif val_type == BSER_ARRAY: |
|
335 return _bunser_array(buf, pos, mutable) |
|
336 elif val_type == BSER_OBJECT: |
|
337 return _bunser_object(buf, pos, mutable) |
|
338 elif val_type == BSER_TEMPLATE: |
|
339 return _bunser_template(buf, pos, mutable) |
|
340 else: |
|
341 raise RuntimeError('unhandled bser opcode 0x%02x' % (val_type,)) |
|
342 |
443 |
343 |
444 |
344 def pdu_len(buf): |
445 def pdu_len(buf): |
345 if buf[0:2] != EMPTY_HEADER[0:2]: |
446 info = _pdu_info_helper(buf) |
346 raise RuntimeError('Invalid BSER header') |
447 return info[2] + info[3] |
347 expected_len, pos = _bunser_int(buf, 2) |
448 |
348 return expected_len + pos |
449 |
349 |
450 def loads(buf, mutable=True, value_encoding=None, value_errors=None): |
350 |
451 """Deserialize a BSER-encoded blob. |
351 def loads(buf, mutable=True): |
452 |
352 if buf[0:2] != EMPTY_HEADER[0:2]: |
453 @param buf: The buffer to deserialize. |
353 raise RuntimeError('Invalid BSER header') |
454 @type buf: bytes |
354 expected_len, pos = _bunser_int(buf, 2) |
455 |
|
456 @param mutable: Whether to return mutable results. |
|
457 @type mutable: bool |
|
458 |
|
459 @param value_encoding: Optional codec to use to decode values. If |
|
460 unspecified or None, return values as bytestrings. |
|
461 @type value_encoding: str |
|
462 |
|
463 @param value_errors: Optional error handler for codec. 'strict' by default. |
|
464 The other most common argument is 'surrogateescape' on |
|
465 Python 3. If value_encoding is None, this is ignored. |
|
466 @type value_errors: str |
|
467 """ |
|
468 |
|
469 info = _pdu_info_helper(buf) |
|
470 expected_len = info[2] |
|
471 pos = info[3] |
|
472 |
355 if len(buf) != expected_len + pos: |
473 if len(buf) != expected_len + pos: |
356 raise RuntimeError('bser data len != header len') |
474 raise ValueError('bser data len != header len') |
357 return _bser_loads_recursive(buf, pos, mutable)[0] |
475 |
358 |
476 bunser = Bunser(mutable=mutable, value_encoding=value_encoding, |
359 # no-check-code -- this is a 3rd party library |
477 value_errors=value_errors) |
|
478 |
|
479 return bunser.loads_recursive(buf, pos)[0] |
|
480 |
|
481 |
|
482 def load(fp, mutable=True, value_encoding=None, value_errors=None): |
|
483 from . import load |
|
484 return load.load(fp, mutable, value_encoding, value_errors) |