FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

"""Fallback pure Python implementation of msgpack""" import struct import sys from datetime import datetime as _DateTime if hasattr(sys, "pypy_version_info"): from __pypy__ import newlist_hint from __pypy__.builders import BytesBuilder _USING_STRINGBUILDER = True class BytesIO: def __init__(self, s=b""): if s: self.builder = BytesBuilder(len(s)) self.builder.append(s) else: self.builder = BytesBuilder() def write(self, s): if isinstance(s, memoryview): s = s.tobytes() elif isinstance(s, bytearray): s = bytes(s) self.builder.append(s) def getvalue(self): return self.builder.build() else: from io import BytesIO _USING_STRINGBUILDER = False def newlist_hint(size): return [] from .exceptions import BufferFull, ExtraData, FormatError, OutOfData, StackError from .ext import ExtType, Timestamp EX_SKIP = 0 EX_CONSTRUCT = 1 EX_READ_ARRAY_HEADER = 2 EX_READ_MAP_HEADER = 3 TYPE_IMMEDIATE = 0 TYPE_ARRAY = 1 TYPE_MAP = 2 TYPE_RAW = 3 TYPE_BIN = 4 TYPE_EXT = 5 DEFAULT_RECURSE_LIMIT = 1024 def _check_type_strict(obj, t, type=type, tuple=tuple): if type(t) is tuple: return type(obj) in t else: return type(obj) is t def _get_data_from_buffer(obj): view = memoryview(obj) if view.itemsize != 1: raise ValueError("cannot unpack from multi-byte object") return view def unpackb(packed, **kwargs): """ Unpack an object from `packed`. Raises ``ExtraData`` when *packed* contains extra bytes. Raises ``ValueError`` when *packed* is incomplete. Raises ``FormatError`` when *packed* is not valid msgpack. Raises ``StackError`` when *packed* contains too nested. Other exceptions can be raised during unpacking. See :class:`Unpacker` for options. """ unpacker = Unpacker(None, max_buffer_size=len(packed), **kwargs) unpacker.feed(packed) try: ret = unpacker._unpack() except OutOfData: raise ValueError("Unpack failed: incomplete input") except RecursionError: raise StackError if unpacker._got_extradata(): raise ExtraData(ret, unpacker._get_extradata()) return ret _NO_FORMAT_USED = "" _MSGPACK_HEADERS = { 0xC4: (1, _NO_FORMAT_USED, TYPE_BIN), 0xC5: (2, ">H", TYPE_BIN), 0xC6: (4, ">I", TYPE_BIN), 0xC7: (2, "Bb", TYPE_EXT), 0xC8: (3, ">Hb", TYPE_EXT), 0xC9: (5, ">Ib", TYPE_EXT), 0xCA: (4, ">f"), 0xCB: (8, ">d"), 0xCC: (1, _NO_FORMAT_USED), 0xCD: (2, ">H"), 0xCE: (4, ">I"), 0xCF: (8, ">Q"), 0xD0: (1, "b"), 0xD1: (2, ">h"), 0xD2: (4, ">i"), 0xD3: (8, ">q"), 0xD4: (1, "b1s", TYPE_EXT), 0xD5: (2, "b2s", TYPE_EXT), 0xD6: (4, "b4s", TYPE_EXT), 0xD7: (8, "b8s", TYPE_EXT), 0xD8: (16, "b16s", TYPE_EXT), 0xD9: (1, _NO_FORMAT_USED, TYPE_RAW), 0xDA: (2, ">H", TYPE_RAW), 0xDB: (4, ">I", TYPE_RAW), 0xDC: (2, ">H", TYPE_ARRAY), 0xDD: (4, ">I", TYPE_ARRAY), 0xDE: (2, ">H", TYPE_MAP), 0xDF: (4, ">I", TYPE_MAP), } class Unpacker: """Streaming unpacker. Arguments: :param file_like: File-like object having `.read(n)` method. If specified, unpacker reads serialized data from it and `.feed()` is not usable. :param int read_size: Used as `file_like.read(read_size)`. Must be equal to or smaller than *max_buffer_size*. :param bool use_list: If true, unpack msgpack array to Python list. Otherwise, unpack to Python tuple. (default: True) :param bool raw: If true, unpack msgpack raw to Python bytes. Otherwise, unpack to Python str by decoding with UTF-8 encoding (default). :param int timestamp: Control how timestamp type is unpacked: 0 - Timestamp 1 - float (Seconds from the EPOCH) 2 - int (Nanoseconds from the EPOCH) 3 - datetime.datetime (UTC). :param bool strict_map_key: If true (default), only str or bytes are accepted for map (dict) keys. :param object_hook: When specified, it should be callable. Unpacker calls it with a dict argument after unpacking msgpack map. (See also simplejson) :param object_pairs_hook: When specified, it should be callable. Unpacker calls it with a list of key-value pairs after unpacking msgpack map. (See also simplejson) :param str unicode_errors: The error handler for decoding unicode. (default: 'strict') This option should be used only when you have msgpack data which contains invalid UTF-8 string. :param int max_buffer_size: Limits size of data waiting unpacked. 0 means 2**32-1. The default value is 100*1024*1024 (100MiB). Raises `BufferFull` exception when it is insufficient. You should set this parameter when unpacking data from untrusted source. :param int max_str_len: Deprecated, use *max_buffer_size* instead. Limits max length of str. (default: max_buffer_size) :param int max_bin_len: Deprecated, use *max_buffer_size* instead. Limits max length of bin. (default: max_buffer_size) :param int max_array_len: Limits max length of array. (default: max_buffer_size) :param int max_map_len: Limits max length of map. (default: max_buffer_size//2) :param int max_ext_len: Deprecated, use *max_buffer_size* instead. Limits max size of ext type. (default: max_buffer_size) Example of streaming deserialize from file-like object:: unpacker = Unpacker(file_like) for o in unpacker: process(o) Example of streaming deserialize from socket:: unpacker = Unpacker() while True: buf = sock.recv(1024**2) if not buf: break unpacker.feed(buf) for o in unpacker: process(o) Raises ``ExtraData`` when *packed* contains extra bytes. Raises ``OutOfData`` when *packed* is incomplete. Raises ``FormatError`` when *packed* is not valid msgpack. Raises ``StackError`` when *packed* contains too nested. Other exceptions can be raised during unpacking. """ def __init__( self, file_like=None, *, read_size=0, use_list=True, raw=False, timestamp=0, strict_map_key=True, object_hook=None, object_pairs_hook=None, list_hook=None, unicode_errors=None, max_buffer_size=100 * 1024 * 1024, ext_hook=ExtType, max_str_len=-1, max_bin_len=-1, max_array_len=-1, max_map_len=-1, max_ext_len=-1, ): if unicode_errors is None: unicode_errors = "strict" if file_like is None: self._feeding = True else: if not callable(file_like.read): raise TypeError("`file_like.read` must be callable") self.file_like = file_like self._feeding = False #: array of bytes fed. self._buffer = bytearray() #: Which position we currently reads self._buff_i = 0 # When Unpacker is used as an iterable, between the calls to next(), # the buffer is not "consumed" completely, for efficiency sake. # Instead, it is done sloppily. To make sure we raise BufferFull at # the correct moments, we have to keep track of how sloppy we were. # Furthermore, when the buffer is incomplete (that is: in the case # we raise an OutOfData) we need to rollback the buffer to the correct # state, which _buf_checkpoint records. self._buf_checkpoint = 0 if not max_buffer_size: max_buffer_size = 2**31 - 1 if max_str_len == -1: max_str_len = max_buffer_size if max_bin_len == -1: max_bin_len = max_buffer_size if max_array_len == -1: max_array_len = max_buffer_size if max_map_len == -1: max_map_len = max_buffer_size // 2 if max_ext_len == -1: max_ext_len = max_buffer_size self._max_buffer_size = max_buffer_size if read_size > self._max_buffer_size: raise ValueError("read_size must be smaller than max_buffer_size") self._read_size = read_size or min(self._max_buffer_size, 16 * 1024) self._raw = bool(raw) self._strict_map_key = bool(strict_map_key) self._unicode_errors = unicode_errors self._use_list = use_list if not (0 0: del self._buffer[: self._buf_checkpoint] self._buff_i -= self._buf_checkpoint self._buf_checkpoint = 0 # Use extend here: INPLACE_ADD += doesn't reliably typecast memoryview in jython self._buffer.extend(view if view.contiguous else view.tobytes()) view.release() def _consume(self): """Gets rid of the used parts of the buffer.""" self._stream_offset += self._buff_i - self._buf_checkpoint self._buf_checkpoint = self._buff_i def _got_extradata(self): return self._buff_i < len(self._buffer) def _get_extradata(self): return self._buffer[self._buff_i :] def read_bytes(self, n): ret = self._read(n, raise_outofdata=False) self._consume() return ret def _read(self, n, raise_outofdata=True): # (int) -> bytearray self._reserve(n, raise_outofdata=raise_outofdata) i = self._buff_i ret = self._buffer[i : i + n] self._buff_i = i + len(ret) return ret def _reserve(self, n, raise_outofdata=True): remain_bytes = len(self._buffer) - self._buff_i - n # Fast path: buffer has n bytes already if remain_bytes >= 0: return if self._feeding: self._buff_i = self._buf_checkpoint raise OutOfData # Strip buffer before checkpoint before reading file. if self._buf_checkpoint > 0: del self._buffer[: self._buf_checkpoint] self._buff_i -= self._buf_checkpoint self._buf_checkpoint = 0 # Read from file remain_bytes = -remain_bytes if remain_bytes + len(self._buffer) > self._max_buffer_size: raise BufferFull while remain_bytes > 0: to_read_bytes = max(self._read_size, remain_bytes) read_data = self.file_like.read(to_read_bytes) if not read_data: break assert isinstance(read_data, bytes) self._buffer += read_data remain_bytes -= len(read_data) if len(self._buffer) < n + self._buff_i and raise_outofdata: self._buff_i = 0 # rollback raise OutOfData def _read_header(self): typ = TYPE_IMMEDIATE n = 0 obj = None self._reserve(1) b = self._buffer[self._buff_i] self._buff_i += 1 if b & 0b10000000 == 0: obj = b elif b & 0b11100000 == 0b11100000: obj = -1 - (b ^ 0xFF) elif b & 0b11100000 == 0b10100000: n = b & 0b00011111 typ = TYPE_RAW if n > self._max_str_len: raise ValueError(f"{n} exceeds max_str_len({self._max_str_len})") obj = self._read(n) elif b & 0b11110000 == 0b10010000: n = b & 0b00001111 typ = TYPE_ARRAY if n > self._max_array_len: raise ValueError(f"{n} exceeds max_array_len({self._max_array_len})") elif b & 0b11110000 == 0b10000000: n = b & 0b00001111 typ = TYPE_MAP if n > self._max_map_len: raise ValueError(f"{n} exceeds max_map_len({self._max_map_len})") elif b == 0xC0: obj = None elif b == 0xC2: obj = False elif b == 0xC3: obj = True elif 0xC4 self._max_bin_len: raise ValueError(f"{n} exceeds max_bin_len({self._max_bin_len})") obj = self._read(n) elif 0xC7

Back | FazBrowse Home | New Git URL