summaryrefslogtreecommitdiff
path: root/msgpack
diff options
context:
space:
mode:
authorThomas Goirand <zigo@debian.org>2020-03-14 23:56:08 +0100
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2020-03-15 04:39:34 +0000
commitc46a0bb82a72278c77a70ec614b93b799baa5a87 (patch)
tree34c05528857bef5ebe6daafd3de7f3553dc20f10 /msgpack
parent9c7bd06a309ab70d0c437770dabbabddcb498aae (diff)
Imported using git-ubuntu import.
Notes
Notes: * New upstream release. * Fix pkgos-dh_auto_install to install only for py3. * Removed remaining python3 build-depends (Closes: #937932).
Diffstat (limited to 'msgpack')
-rw-r--r--msgpack/__init__.py11
-rw-r--r--msgpack/_cmsgpack.pyx4
-rw-r--r--msgpack/_packer.pyx63
-rw-r--r--msgpack/_unpacker.pyx216
-rw-r--r--msgpack/_version.py2
-rw-r--r--msgpack/buff_converter.h28
-rw-r--r--msgpack/exceptions.py45
-rw-r--r--msgpack/fallback.py324
-rw-r--r--msgpack/pack_template.h13
-rw-r--r--msgpack/unpack.h5
-rw-r--r--msgpack/unpack_template.h43
11 files changed, 427 insertions, 327 deletions
diff --git a/msgpack/__init__.py b/msgpack/__init__.py
index 3955a41..4ad9c1a 100644
--- a/msgpack/__init__.py
+++ b/msgpack/__init__.py
@@ -1,6 +1,6 @@
# coding: utf-8
-from msgpack._version import version
-from msgpack.exceptions import *
+from ._version import version
+from .exceptions import *
from collections import namedtuple
@@ -19,13 +19,12 @@ class ExtType(namedtuple('ExtType', 'code data')):
import os
if os.environ.get('MSGPACK_PUREPYTHON'):
- from msgpack.fallback import Packer, unpackb, Unpacker
+ from .fallback import Packer, unpackb, Unpacker
else:
try:
- from msgpack._packer import Packer
- from msgpack._unpacker import unpackb, Unpacker
+ from ._cmsgpack import Packer, unpackb, Unpacker
except ImportError:
- from msgpack.fallback import Packer, unpackb, Unpacker
+ from .fallback import Packer, unpackb, Unpacker
def pack(o, stream, **kwargs):
diff --git a/msgpack/_cmsgpack.pyx b/msgpack/_cmsgpack.pyx
new file mode 100644
index 0000000..8ebdbf5
--- /dev/null
+++ b/msgpack/_cmsgpack.pyx
@@ -0,0 +1,4 @@
+# coding: utf-8
+#cython: embedsignature=True, c_string_encoding=ascii, language_level=3
+include "_packer.pyx"
+include "_unpacker.pyx"
diff --git a/msgpack/_packer.pyx b/msgpack/_packer.pyx
index 225f24a..2f4d120 100644
--- a/msgpack/_packer.pyx
+++ b/msgpack/_packer.pyx
@@ -1,19 +1,16 @@
# coding: utf-8
-#cython: embedsignature=True, c_string_encoding=ascii
from cpython cimport *
-from cpython.version cimport PY_MAJOR_VERSION
-from cpython.exc cimport PyErr_WarnEx
+from cpython.bytearray cimport PyByteArray_Check, PyByteArray_CheckExact
-from msgpack.exceptions import PackValueError, PackOverflowError
-from msgpack import ExtType
+cdef ExtType
+
+from . import ExtType
cdef extern from "Python.h":
int PyMemoryView_Check(object obj)
- int PyByteArray_Check(object obj)
- int PyByteArray_CheckExact(object obj)
char* PyUnicode_AsUTF8AndSize(object obj, Py_ssize_t *l) except NULL
@@ -41,6 +38,9 @@ cdef extern from "pack.h":
int msgpack_pack_ext(msgpack_packer* pk, char typecode, size_t l)
int msgpack_pack_unicode(msgpack_packer* pk, object o, long long limit)
+cdef extern from "buff_converter.h":
+ object buff_to_buff(char *, Py_ssize_t)
+
cdef int DEFAULT_RECURSE_LIMIT=511
cdef long long ITEM_LIMIT = (2**32)-1
@@ -118,7 +118,7 @@ cdef class Packer(object):
bint use_single_float=False, bint autoreset=True, bint use_bin_type=False,
bint strict_types=False):
if encoding is not None:
- PyErr_WarnEx(PendingDeprecationWarning, "encoding is deprecated.", 1)
+ PyErr_WarnEx(DeprecationWarning, "encoding is deprecated.", 1)
self.use_float = use_single_float
self.strict_types = strict_types
self.autoreset = autoreset
@@ -162,7 +162,7 @@ cdef class Packer(object):
cdef Py_buffer view
if nest_limit < 0:
- raise PackValueError("recursion limit exceeded.")
+ raise ValueError("recursion limit exceeded.")
while True:
if o is None:
@@ -188,7 +188,7 @@ cdef class Packer(object):
default_used = True
continue
else:
- raise PackOverflowError("Integer value out of range")
+ raise OverflowError("Integer value out of range")
elif PyInt_CheckExact(o) if strict_types else PyInt_Check(o):
longval = o
ret = msgpack_pack_long(&self.pk, longval)
@@ -200,9 +200,9 @@ cdef class Packer(object):
dval = o
ret = msgpack_pack_double(&self.pk, dval)
elif PyBytesLike_CheckExact(o) if strict_types else PyBytesLike_Check(o):
- L = len(o)
+ L = Py_SIZE(o)
if L > ITEM_LIMIT:
- raise PackValueError("%s is too large" % type(o).__name__)
+ PyErr_Format(ValueError, b"%.200s object is too large", Py_TYPE(o).tp_name)
rawval = o
ret = msgpack_pack_bin(&self.pk, L)
if ret == 0:
@@ -211,12 +211,12 @@ cdef class Packer(object):
if self.encoding == NULL and self.unicode_errors == NULL:
ret = msgpack_pack_unicode(&self.pk, o, ITEM_LIMIT);
if ret == -2:
- raise PackValueError("unicode string is too large")
+ raise ValueError("unicode string is too large")
else:
o = PyUnicode_AsEncodedString(o, self.encoding, self.unicode_errors)
- L = len(o)
+ L = Py_SIZE(o)
if L > ITEM_LIMIT:
- raise PackValueError("unicode string is too large")
+ raise ValueError("unicode string is too large")
ret = msgpack_pack_raw(&self.pk, L)
if ret == 0:
rawval = o
@@ -225,10 +225,10 @@ cdef class Packer(object):
d = <dict>o
L = len(d)
if L > ITEM_LIMIT:
- raise PackValueError("dict is too large")
+ raise ValueError("dict is too large")
ret = msgpack_pack_map(&self.pk, L)
if ret == 0:
- for k, v in d.iteritems():
+ for k, v in d.items():
ret = self._pack(k, nest_limit-1)
if ret != 0: break
ret = self._pack(v, nest_limit-1)
@@ -236,7 +236,7 @@ cdef class Packer(object):
elif not strict_types and PyDict_Check(o):
L = len(o)
if L > ITEM_LIMIT:
- raise PackValueError("dict is too large")
+ raise ValueError("dict is too large")
ret = msgpack_pack_map(&self.pk, L)
if ret == 0:
for k, v in o.items():
@@ -250,13 +250,13 @@ cdef class Packer(object):
rawval = o.data
L = len(o.data)
if L > ITEM_LIMIT:
- raise PackValueError("EXT data is too large")
+ raise ValueError("EXT data is too large")
ret = msgpack_pack_ext(&self.pk, longval, L)
ret = msgpack_pack_raw_body(&self.pk, rawval, L)
elif PyList_CheckExact(o) if strict_types else (PyTuple_Check(o) or PyList_Check(o)):
- L = len(o)
+ L = Py_SIZE(o)
if L > ITEM_LIMIT:
- raise PackValueError("list is too large")
+ raise ValueError("list is too large")
ret = msgpack_pack_array(&self.pk, L)
if ret == 0:
for v in o:
@@ -264,11 +264,11 @@ cdef class Packer(object):
if ret != 0: break
elif PyMemoryView_Check(o):
if PyObject_GetBuffer(o, &view, PyBUF_SIMPLE) != 0:
- raise PackValueError("could not get buffer for memoryview")
+ raise ValueError("could not get buffer for memoryview")
L = view.len
if L > ITEM_LIMIT:
PyBuffer_Release(&view);
- raise PackValueError("memoryview is too large")
+ raise ValueError("memoryview is too large")
ret = msgpack_pack_bin(&self.pk, L)
if ret == 0:
ret = msgpack_pack_raw_body(&self.pk, <char*>view.buf, L)
@@ -278,7 +278,7 @@ cdef class Packer(object):
default_used = 1
continue
else:
- raise TypeError("can't serialize %r" % (o,))
+ PyErr_Format(TypeError, b"can not serialize '%.200s' object", Py_TYPE(o).tp_name)
return ret
cpdef pack(self, object obj):
@@ -301,7 +301,7 @@ cdef class Packer(object):
def pack_array_header(self, long long size):
if size > ITEM_LIMIT:
- raise PackValueError
+ raise ValueError
cdef int ret = msgpack_pack_array(&self.pk, size)
if ret == -1:
raise MemoryError
@@ -314,7 +314,7 @@ cdef class Packer(object):
def pack_map_header(self, long long size):
if size > ITEM_LIMIT:
- raise PackValueError
+ raise ValueError
cdef int ret = msgpack_pack_map(&self.pk, size)
if ret == -1:
raise MemoryError
@@ -349,9 +349,16 @@ cdef class Packer(object):
return buf
def reset(self):
- """Clear internal buffer."""
+ """Reset internal buffer.
+
+ This method is usaful only when autoreset=False.
+ """
self.pk.length = 0
def bytes(self):
- """Return buffer content."""
+ """Return internal buffer contents as bytes object"""
return PyBytes_FromStringAndSize(self.pk.buf, self.pk.length)
+
+ def getbuffer(self):
+ """Return view of internal buffer."""
+ return buff_to_buff(self.pk.buf, self.pk.length)
diff --git a/msgpack/_unpacker.pyx b/msgpack/_unpacker.pyx
index d7fa5bc..3727f50 100644
--- a/msgpack/_unpacker.pyx
+++ b/msgpack/_unpacker.pyx
@@ -1,26 +1,6 @@
# coding: utf-8
-#cython: embedsignature=True, c_string_encoding=ascii
-from cpython.version cimport PY_MAJOR_VERSION
-from cpython.bytes cimport (
- PyBytes_AsString,
- PyBytes_FromStringAndSize,
- PyBytes_Size,
-)
-from cpython.buffer cimport (
- Py_buffer,
- PyObject_CheckBuffer,
- PyObject_GetBuffer,
- PyBuffer_Release,
- PyBuffer_IsContiguous,
- PyBUF_READ,
- PyBUF_SIMPLE,
- PyBUF_FULL_RO,
-)
-from cpython.mem cimport PyMem_Malloc, PyMem_Free
-from cpython.object cimport PyCallable_Check
-from cpython.ref cimport Py_DECREF
-from cpython.exc cimport PyErr_WarnEx
+from cpython cimport *
cdef extern from "Python.h":
ctypedef struct PyObject
@@ -32,13 +12,14 @@ from libc.string cimport *
from libc.limits cimport *
ctypedef unsigned long long uint64_t
-from msgpack.exceptions import (
+from .exceptions import (
BufferFull,
OutOfData,
- UnpackValueError,
ExtraData,
+ FormatError,
+ StackError,
)
-from msgpack import ExtType
+from . import ExtType
cdef extern from "unpack.h":
@@ -46,6 +27,7 @@ cdef extern from "unpack.h":
bint use_list
bint raw
bint has_pairs_hook # call object_hook with k-v pairs
+ bint strict_map_key
PyObject* object_hook
PyObject* list_hook
PyObject* ext_hook
@@ -75,7 +57,7 @@ cdef extern from "unpack.h":
cdef inline init_ctx(unpack_context *ctx,
object object_hook, object object_pairs_hook,
object list_hook, object ext_hook,
- bint use_list, bint raw,
+ bint use_list, bint raw, bint strict_map_key,
const char* encoding, const char* unicode_errors,
Py_ssize_t max_str_len, Py_ssize_t max_bin_len,
Py_ssize_t max_array_len, Py_ssize_t max_map_len,
@@ -83,6 +65,7 @@ cdef inline init_ctx(unpack_context *ctx,
unpack_init(ctx)
ctx.user.use_list = use_list
ctx.user.raw = raw
+ ctx.user.strict_map_key = strict_map_key
ctx.user.object_hook = ctx.user.list_hook = <PyObject*>NULL
ctx.user.max_str_len = max_str_len
ctx.user.max_bin_len = max_bin_len
@@ -136,10 +119,10 @@ cdef inline int get_data_from_buffer(object obj,
if view.itemsize != 1:
PyBuffer_Release(view)
raise BufferError("cannot unpack from multi-byte object")
- if PyBuffer_IsContiguous(view, 'A') == 0:
+ if PyBuffer_IsContiguous(view, b'A') == 0:
PyBuffer_Release(view)
# create a contiguous copy and get buffer
- contiguous = PyMemoryView_GetContiguous(obj, PyBUF_READ, 'C')
+ contiguous = PyMemoryView_GetContiguous(obj, PyBUF_READ, b'C')
PyObject_GetBuffer(contiguous, view, PyBUF_SIMPLE)
# view must hold the only reference to contiguous,
# so memory is freed when view is released
@@ -159,20 +142,26 @@ cdef inline int get_data_from_buffer(object obj,
return 1
def unpackb(object packed, object object_hook=None, object list_hook=None,
- bint use_list=True, bint raw=True,
+ bint use_list=True, bint raw=True, bint strict_map_key=False,
encoding=None, unicode_errors=None,
object_pairs_hook=None, ext_hook=ExtType,
- Py_ssize_t max_str_len=2147483647, # 2**32-1
- Py_ssize_t max_bin_len=2147483647,
- Py_ssize_t max_array_len=2147483647,
- Py_ssize_t max_map_len=2147483647,
- Py_ssize_t max_ext_len=2147483647):
+ Py_ssize_t max_str_len=-1,
+ Py_ssize_t max_bin_len=-1,
+ Py_ssize_t max_array_len=-1,
+ Py_ssize_t max_map_len=-1,
+ Py_ssize_t max_ext_len=-1):
"""
Unpack packed_bytes to object. Returns an unpacked object.
- Raises `ValueError` when `packed` contains extra bytes.
+ 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.
+
+ *max_xxx_len* options are configured automatically from ``len(packed)``.
"""
cdef unpack_context ctx
cdef Py_ssize_t off = 0
@@ -186,16 +175,28 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
cdef int new_protocol = 0
if encoding is not None:
- PyErr_WarnEx(PendingDeprecationWarning, "encoding is deprecated, Use raw=False instead.", 1)
+ PyErr_WarnEx(DeprecationWarning, "encoding is deprecated, Use raw=False instead.", 1)
cenc = encoding
if unicode_errors is not None:
cerr = unicode_errors
get_data_from_buffer(packed, &view, &buf, &buf_len, &new_protocol)
+
+ if max_str_len == -1:
+ max_str_len = buf_len
+ if max_bin_len == -1:
+ max_bin_len = buf_len
+ if max_array_len == -1:
+ max_array_len = buf_len
+ if max_map_len == -1:
+ max_map_len = buf_len//2
+ if max_ext_len == -1:
+ max_ext_len = buf_len
+
try:
init_ctx(&ctx, object_hook, object_pairs_hook, list_hook, ext_hook,
- use_list, raw, cenc, cerr,
+ use_list, raw, strict_map_key, cenc, cerr,
max_str_len, max_bin_len, max_array_len, max_map_len, max_ext_len)
ret = unpack_construct(&ctx, buf, buf_len, &off)
finally:
@@ -208,12 +209,18 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
raise ExtraData(obj, PyBytes_FromStringAndSize(buf+off, buf_len-off))
return obj
unpack_clear(&ctx)
- raise UnpackValueError("Unpack failed: error = %d" % (ret,))
+ if ret == 0:
+ raise ValueError("Unpack failed: incomplete input")
+ elif ret == -2:
+ raise FormatError
+ elif ret == -3:
+ raise StackError
+ raise ValueError("Unpack failed: error = %d" % (ret,))
def unpack(object stream, **kwargs):
PyErr_WarnEx(
- PendingDeprecationWarning,
+ DeprecationWarning,
"Direct calling implementation's unpack() is deprecated, Use msgpack.unpack() or unpackb() instead.", 1)
data = stream.read()
return unpackb(data, **kwargs)
@@ -222,7 +229,7 @@ def unpack(object stream, **kwargs):
cdef class Unpacker(object):
"""Streaming unpacker.
- arguments:
+ Arguments:
:param file_like:
File-like object having `.read(n)` method.
@@ -245,6 +252,11 @@ cdef class Unpacker(object):
*encoding* option which is deprecated overrides this option.
+ :param bool strict_map_key:
+ If true, only str or bytes are accepted for map (dict) keys.
+ It's False by default for backward-compatibility.
+ But it will be True from msgpack 1.0.
+
:param callable object_hook:
When specified, it should be callable.
Unpacker calls it with a dict argument after unpacking msgpack map.
@@ -261,19 +273,25 @@ cdef class Unpacker(object):
You should set this parameter when unpacking data from untrusted source.
:param int max_str_len:
- Limits max length of str. (default: 2**31-1)
+ Deprecated, use *max_buffer_size* instead.
+ Limits max length of str. (default: max_buffer_size or 1024*1024)
:param int max_bin_len:
- Limits max length of bin. (default: 2**31-1)
+ Deprecated, use *max_buffer_size* instead.
+ Limits max length of bin. (default: max_buffer_size or 1024*1024)
:param int max_array_len:
- Limits max length of array. (default: 2**31-1)
+ Limits max length of array. (default: max_buffer_size or 128*1024)
:param int max_map_len:
- Limits max length of map. (default: 2**31-1)
+ Limits max length of map. (default: max_buffer_size//2 or 32*1024)
+
+ :param int max_ext_len:
+ Deprecated, use *max_buffer_size* instead.
+ Limits max size of ext type. (default: max_buffer_size or 1024*1024)
:param str encoding:
- Deprecated, use raw instead.
+ Deprecated, use ``raw=False`` instead.
Encoding used for decoding msgpack raw.
If it is None (default), msgpack raw is deserialized to Python bytes.
@@ -283,13 +301,13 @@ cdef class Unpacker(object):
Example of streaming deserialize from file-like object::
- unpacker = Unpacker(file_like, raw=False)
+ unpacker = Unpacker(file_like, raw=False, max_buffer_size=10*1024*1024)
for o in unpacker:
process(o)
Example of streaming deserialize from socket::
- unpacker = Unpacker(raw=False)
+ unpacker = Unpacker(raw=False, max_buffer_size=10*1024*1024)
while True:
buf = sock.recv(1024**2)
if not buf:
@@ -297,6 +315,12 @@ cdef class Unpacker(object):
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.
"""
cdef unpack_context ctx
cdef char* buf
@@ -318,15 +342,15 @@ cdef class Unpacker(object):
self.buf = NULL
def __init__(self, file_like=None, Py_ssize_t read_size=0,
- bint use_list=True, bint raw=True,
+ bint use_list=True, bint raw=True, bint strict_map_key=False,
object object_hook=None, object object_pairs_hook=None, object list_hook=None,
- encoding=None, unicode_errors=None, int max_buffer_size=0,
+ encoding=None, unicode_errors=None, Py_ssize_t max_buffer_size=0,
object ext_hook=ExtType,
- Py_ssize_t max_str_len=2147483647, # 2**32-1
- Py_ssize_t max_bin_len=2147483647,
- Py_ssize_t max_array_len=2147483647,
- Py_ssize_t max_map_len=2147483647,
- Py_ssize_t max_ext_len=2147483647):
+ Py_ssize_t max_str_len=-1,
+ Py_ssize_t max_bin_len=-1,
+ Py_ssize_t max_array_len=-1,
+ Py_ssize_t max_map_len=-1,
+ Py_ssize_t max_ext_len=-1):
cdef const char *cenc=NULL,
cdef const char *cerr=NULL
@@ -340,6 +364,18 @@ cdef class Unpacker(object):
self.file_like_read = file_like.read
if not PyCallable_Check(self.file_like_read):
raise TypeError("`file_like.read` must be a callable.")
+
+ if max_str_len == -1:
+ max_str_len = max_buffer_size or 1024*1024
+ if max_bin_len == -1:
+ max_bin_len = max_buffer_size or 1024*1024
+ if max_array_len == -1:
+ max_array_len = max_buffer_size or 128*1024
+ if max_map_len == -1:
+ max_map_len = max_buffer_size//2 or 32*1024
+ if max_ext_len == -1:
+ max_ext_len = max_buffer_size or 1024*1024
+
if not max_buffer_size:
max_buffer_size = INT_MAX
if read_size > max_buffer_size:
@@ -357,7 +393,7 @@ cdef class Unpacker(object):
self.stream_offset = 0
if encoding is not None:
- PyErr_WarnEx(PendingDeprecationWarning, "encoding is deprecated, Use raw=False instead.", 1)
+ PyErr_WarnEx(DeprecationWarning, "encoding is deprecated, Use raw=False instead.", 1)
self.encoding = encoding
cenc = encoding
@@ -366,7 +402,7 @@ cdef class Unpacker(object):
cerr = unicode_errors
init_ctx(&self.ctx, object_hook, object_pairs_hook, list_hook,
- ext_hook, use_list, raw, cenc, cerr,
+ ext_hook, use_list, raw, strict_map_key, cenc, cerr,
max_str_len, max_bin_len, max_array_len,
max_map_len, max_ext_len)
@@ -438,14 +474,11 @@ cdef class Unpacker(object):
else:
self.file_like = None
- cdef object _unpack(self, execute_fn execute, object write_bytes, bint iter=0):
+ cdef object _unpack(self, execute_fn execute, bint iter=0):
cdef int ret
cdef object obj
cdef Py_ssize_t prev_head
- if write_bytes is not None:
- PyErr_WarnEx(DeprecationWarning, "`write_bytes` option is deprecated. Use `.tell()` instead.", 1)
-
if self.buf_head >= self.buf_tail and self.file_like is not None:
self.read_from_file()
@@ -457,28 +490,27 @@ cdef class Unpacker(object):
else:
raise OutOfData("No more data to unpack.")
- try:
- ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
- self.stream_offset += self.buf_head - prev_head
- if write_bytes is not None:
- write_bytes(PyBytes_FromStringAndSize(self.buf + prev_head, self.buf_head - prev_head))
-
- if ret == 1:
- obj = unpack_data(&self.ctx)
- unpack_init(&self.ctx)
- return obj
- elif ret == 0:
- if self.file_like is not None:
- self.read_from_file()
- continue
- if iter:
- raise StopIteration("No more data to unpack.")
- else:
- raise OutOfData("No more data to unpack.")
+ ret = execute(&self.ctx, self.buf, self.buf_tail, &self.buf_head)
+ self.stream_offset += self.buf_head - prev_head
+
+ if ret == 1:
+ obj = unpack_data(&self.ctx)
+ unpack_init(&self.ctx)
+ return obj
+ elif ret == 0:
+ if self.file_like is not None:
+ self.read_from_file()
+ continue
+ if iter:
+ raise StopIteration("No more data to unpack.")
else:
- raise UnpackValueError("Unpack failed: error = %d" % (ret,))
- except ValueError as e:
- raise UnpackValueError(e)
+ raise OutOfData("No more data to unpack.")
+ elif ret == -2:
+ raise FormatError
+ elif ret == -3:
+ raise StackError
+ else:
+ raise ValueError("Unpack failed: error = %d" % (ret,))
def read_bytes(self, Py_ssize_t nbytes):
"""Read a specified number of raw bytes from the stream"""
@@ -490,41 +522,35 @@ cdef class Unpacker(object):
ret += self.file_like.read(nbytes - len(ret))
return ret
- def unpack(self, object write_bytes=None):
+ def unpack(self):
"""Unpack one object
- If write_bytes is not None, it will be called with parts of the raw
- message as it is unpacked.
-
Raises `OutOfData` when there are no more bytes to unpack.
"""
- return self._unpack(unpack_construct, write_bytes)
+ return self._unpack(unpack_construct)
- def skip(self, object write_bytes=None):
+ def skip(self):
"""Read and ignore one object, returning None
- If write_bytes is not None, it will be called with parts of the raw
- message as it is unpacked.
-
Raises `OutOfData` when there are no more bytes to unpack.
"""
- return self._unpack(unpack_skip, write_bytes)
+ return self._unpack(unpack_skip)
- def read_array_header(self, object write_bytes=None):
+ def read_array_header(self):
"""assuming the next object is an array, return its size n, such that
the next n unpack() calls will iterate over its contents.
Raises `OutOfData` when there are no more bytes to unpack.
"""
- return self._unpack(read_array_header, write_bytes)
+ return self._unpack(read_array_header)
- def read_map_header(self, object write_bytes=None):
+ def read_map_header(self):
"""assuming the next object is a map, return its size n, such that the
next n * 2 unpack() calls will iterate over its key-value pairs.
Raises `OutOfData` when there are no more bytes to unpack.
"""
- return self._unpack(read_map_header, write_bytes)
+ return self._unpack(read_map_header)
def tell(self):
return self.stream_offset
@@ -533,7 +559,7 @@ cdef class Unpacker(object):
return self
def __next__(self):
- return self._unpack(unpack_construct, None, 1)
+ return self._unpack(unpack_construct, 1)
# for debug.
#def _buf(self):
diff --git a/msgpack/_version.py b/msgpack/_version.py
index d28f0de..1e73a00 100644
--- a/msgpack/_version.py
+++ b/msgpack/_version.py
@@ -1 +1 @@
-version = (0, 5, 6)
+version = (0, 6, 2)
diff --git a/msgpack/buff_converter.h b/msgpack/buff_converter.h
new file mode 100644
index 0000000..bc7227a
--- /dev/null
+++ b/msgpack/buff_converter.h
@@ -0,0 +1,28 @@
+#include "Python.h"
+
+/* cython does not support this preprocessor check => write it in raw C */
+#if PY_MAJOR_VERSION == 2
+static PyObject *
+buff_to_buff(char *buff, Py_ssize_t size)
+{
+ return PyBuffer_FromMemory(buff, size);
+}
+
+#elif (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 3)
+static PyObject *
+buff_to_buff(char *buff, Py_ssize_t size)
+{
+ return PyMemoryView_FromMemory(buff, size, PyBUF_READ);
+}
+#else
+static PyObject *
+buff_to_buff(char *buff, Py_ssize_t size)
+{
+ Py_buffer pybuf;
+ if (PyBuffer_FillInfo(&pybuf, NULL, buff, size, 1, PyBUF_FULL_RO) == -1) {
+ return NULL;
+ }
+
+ return PyMemoryView_FromBuffer(&pybuf);
+}
+#endif
diff --git a/msgpack/exceptions.py b/msgpack/exceptions.py
index 9766881..d6d2615 100644
--- a/msgpack/exceptions.py
+++ b/msgpack/exceptions.py
@@ -1,5 +1,10 @@
class UnpackException(Exception):
- """Deprecated. Use Exception instead to catch all exception during unpacking."""
+ """Base class for some exceptions raised while unpacking.
+
+ NOTE: unpack may raise exception other than subclass of
+ UnpackException. If you want to catch all error, catch
+ Exception instead.
+ """
class BufferFull(UnpackException):
@@ -10,32 +15,34 @@ class OutOfData(UnpackException):
pass
-class UnpackValueError(UnpackException, ValueError):
- """Deprecated. Use ValueError instead."""
+class FormatError(ValueError, UnpackException):
+ """Invalid msgpack format"""
-class ExtraData(UnpackValueError):
- def __init__(self, unpacked, extra):
- self.unpacked = unpacked
- self.extra = extra
-
- def __str__(self):
- return "unpack(b) received extra data."
+class StackError(ValueError, UnpackException):
+ """Too nested"""
-class PackException(Exception):
- """Deprecated. Use Exception instead to catch all exception during packing."""
+# Deprecated. Use ValueError instead
+UnpackValueError = ValueError
-class PackValueError(PackException, ValueError):
- """PackValueError is raised when type of input data is supported but it's value is unsupported.
+class ExtraData(UnpackValueError):
+ """ExtraData is raised when there is trailing data.
- Deprecated. Use ValueError instead.
+ This exception is raised while only one-shot (not streaming)
+ unpack.
"""
+ def __init__(self, unpacked, extra):
+ self.unpacked = unpacked
+ self.extra = extra
+
+ def __str__(self):
+ return "unpack(b) received extra data."
-class PackOverflowError(PackValueError, OverflowError):
- """PackOverflowError is raised when integer value is out of range of msgpack support [-2**31, 2**32).
- Deprecated. Use ValueError instead.
- """
+# Deprecated. Use Exception instead to catch all exception during packing.
+PackException = Exception
+PackValueError = ValueError
+PackOverflowError = OverflowError
diff --git a/msgpack/fallback.py b/msgpack/fallback.py
index c0e5fd6..3836e83 100644
--- a/msgpack/fallback.py
+++ b/msgpack/fallback.py
@@ -4,20 +4,30 @@ import sys
import struct
import warnings
-if sys.version_info[0] == 3:
- PY3 = True
+
+if sys.version_info[0] == 2:
+ PY2 = True
+ int_types = (int, long)
+ def dict_iteritems(d):
+ return d.iteritems()
+else:
+ PY2 = False
int_types = int
- Unicode = str
+ unicode = str
xrange = range
def dict_iteritems(d):
return d.items()
-else:
- PY3 = False
- int_types = (int, long)
- Unicode = unicode
- def dict_iteritems(d):
- return d.iteritems()
+if sys.version_info < (3, 5):
+ # Ugly hack...
+ RecursionError = RuntimeError
+
+ def _is_recursionerror(e):
+ return len(e.args) == 1 and isinstance(e.args[0], str) and \
+ e.args[0].startswith('maximum recursion depth exceeded')
+else:
+ def _is_recursionerror(e):
+ return True
if hasattr(sys, 'pypy_version_info'):
# cStringIO is slow on PyPy, StringIO is faster. However: PyPy's own
@@ -49,15 +59,15 @@ else:
newlist_hint = lambda size: []
-from msgpack.exceptions import (
+from .exceptions import (
BufferFull,
OutOfData,
- UnpackValueError,
- PackValueError,
- PackOverflowError,
- ExtraData)
+ ExtraData,
+ FormatError,
+ StackError,
+)
-from msgpack import ExtType
+from . import ExtType
EX_SKIP = 0
@@ -87,12 +97,12 @@ def _get_data_from_buffer(obj):
view = memoryview(obj)
except TypeError:
# try to use legacy buffer protocol if 2.7, otherwise re-raise
- if not PY3:
+ if PY2:
view = memoryview(buffer(obj))
warnings.warn("using old buffer interface to unpack %s; "
"this leads to unpacking errors if slicing is used and "
"will be removed in a future version" % type(obj),
- RuntimeWarning)
+ RuntimeWarning, stacklevel=3)
else:
raise
if view.itemsize != 1:
@@ -103,7 +113,7 @@ def _get_data_from_buffer(obj):
def unpack(stream, **kwargs):
warnings.warn(
"Direct calling implementation's unpack() is deprecated, Use msgpack.unpack() or unpackb() instead.",
- PendingDeprecationWarning)
+ DeprecationWarning, stacklevel=2)
data = stream.read()
return unpackb(data, **kwargs)
@@ -112,20 +122,37 @@ def unpackb(packed, **kwargs):
"""
Unpack an object from `packed`.
- Raises `ExtraData` when `packed` contains extra bytes.
+ 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, **kwargs)
+ unpacker = Unpacker(None, max_buffer_size=len(packed), **kwargs)
unpacker.feed(packed)
try:
ret = unpacker._unpack()
except OutOfData:
- raise UnpackValueError("Data is not enough.")
+ raise ValueError("Unpack failed: incomplete input")
+ except RecursionError as e:
+ if _is_recursionerror(e):
+ raise StackError
+ raise
if unpacker._got_extradata():
raise ExtraData(ret, unpacker._get_extradata())
return ret
+if sys.version_info < (2, 7, 6):
+ def _unpack_from(f, b, o=0):
+ """Explicit typcast for legacy struct.unpack_from"""
+ return struct.unpack_from(f, bytes(b), o)
+else:
+ _unpack_from = struct.unpack_from
+
+
class Unpacker(object):
"""Streaming unpacker.
@@ -152,6 +179,11 @@ class Unpacker(object):
*encoding* option which is deprecated overrides this option.
+ :param bool strict_map_key:
+ If true, only str or bytes are accepted for map (dict) keys.
+ It's False by default for backward-compatibility.
+ But it will be True from msgpack 1.0.
+
:param callable object_hook:
When specified, it should be callable.
Unpacker calls it with a dict argument after unpacking msgpack map.
@@ -176,27 +208,34 @@ class Unpacker(object):
You should set this parameter when unpacking data from untrusted source.
:param int max_str_len:
- Limits max length of str. (default: 2**31-1)
+ Deprecated, use *max_buffer_size* instead.
+ Limits max length of str. (default: max_buffer_size or 1024*1024)
:param int max_bin_len:
- Limits max length of bin. (default: 2**31-1)
+ Deprecated, use *max_buffer_size* instead.
+ Limits max length of bin. (default: max_buffer_size or 1024*1024)
:param int max_array_len:
- Limits max length of array. (default: 2**31-1)
+ Limits max length of array.
+ (default: max_buffer_size or 128*1024)
:param int max_map_len:
- Limits max length of map. (default: 2**31-1)
+ Limits max length of map.
+ (default: max_buffer_size//2 or 32*1024)
+ :param int max_ext_len:
+ Deprecated, use *max_buffer_size* instead.
+ Limits max size of ext type. (default: max_buffer_size or 1024*1024)
- example of streaming deserialize from file-like object::
+ Example of streaming deserialize from file-like object::
- unpacker = Unpacker(file_like, raw=False)
+ unpacker = Unpacker(file_like, raw=False, max_buffer_size=10*1024*1024)
for o in unpacker:
process(o)
- example of streaming deserialize from socket::
+ Example of streaming deserialize from socket::
- unpacker = Unpacker(raw=False)
+ unpacker = Unpacker(raw=False, max_buffer_size=10*1024*1024)
while True:
buf = sock.recv(1024**2)
if not buf:
@@ -204,22 +243,27 @@ class Unpacker(object):
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=True,
+ def __init__(self, file_like=None, read_size=0, use_list=True, raw=True, strict_map_key=False,
object_hook=None, object_pairs_hook=None, list_hook=None,
encoding=None, unicode_errors=None, max_buffer_size=0,
ext_hook=ExtType,
- max_str_len=2147483647, # 2**32-1
- max_bin_len=2147483647,
- max_array_len=2147483647,
- max_map_len=2147483647,
- max_ext_len=2147483647):
-
+ max_str_len=-1,
+ max_bin_len=-1,
+ max_array_len=-1,
+ max_map_len=-1,
+ max_ext_len=-1):
if encoding is not None:
warnings.warn(
"encoding is deprecated, Use raw=False instead.",
- PendingDeprecationWarning)
+ DeprecationWarning, stacklevel=2)
if unicode_errors is None:
unicode_errors = 'strict'
@@ -246,11 +290,23 @@ class Unpacker(object):
# state, which _buf_checkpoint records.
self._buf_checkpoint = 0
+ if max_str_len == -1:
+ max_str_len = max_buffer_size or 1024*1024
+ if max_bin_len == -1:
+ max_bin_len = max_buffer_size or 1024*1024
+ if max_array_len == -1:
+ max_array_len = max_buffer_size or 128*1024
+ if max_map_len == -1:
+ max_map_len = max_buffer_size//2 or 32*1024
+ if max_ext_len == -1:
+ max_ext_len = max_buffer_size or 1024*1024
+
self._max_buffer_size = max_buffer_size or 2**31-1
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._encoding = encoding
self._unicode_errors = unicode_errors
self._use_list = use_list
@@ -289,7 +345,8 @@ class Unpacker(object):
self._buff_i -= self._buf_checkpoint
self._buf_checkpoint = 0
- self._buffer += view
+ # Use extend here: INPLACE_ADD += doesn't reliably typecast memoryview in jython
+ self._buffer.extend(view)
def _consume(self):
""" Gets rid of the used parts of the buffer. """
@@ -359,18 +416,18 @@ class Unpacker(object):
n = b & 0b00011111
typ = TYPE_RAW
if n > self._max_str_len:
- raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
+ raise ValueError("%s exceeds max_str_len(%s)", n, 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 UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
+ raise ValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
elif b & 0b11110000 == 0b10000000:
n = b & 0b00001111
typ = TYPE_MAP
if n > self._max_map_len:
- raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
+ raise ValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
elif b == 0xc0:
obj = None
elif b == 0xc2:
@@ -383,55 +440,55 @@ class Unpacker(object):
n = self._buffer[self._buff_i]
self._buff_i += 1
if n > self._max_bin_len:
- raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
+ raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
obj = self._read(n)
elif b == 0xc5:
typ = TYPE_BIN
self._reserve(2)
- n = struct.unpack_from(">H", self._buffer, self._buff_i)[0]
+ n = _unpack_from(">H", self._buffer, self._buff_i)[0]
self._buff_i += 2
if n > self._max_bin_len:
- raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
+ raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
obj = self._read(n)
elif b == 0xc6:
typ = TYPE_BIN
self._reserve(4)
- n = struct.unpack_from(">I", self._buffer, self._buff_i)[0]
+ n = _unpack_from(">I", self._buffer, self._buff_i)[0]
self._buff_i += 4
if n > self._max_bin_len:
- raise UnpackValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
+ raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
obj = self._read(n)
elif b == 0xc7: # ext 8
typ = TYPE_EXT
self._reserve(2)
- L, n = struct.unpack_from('Bb', self._buffer, self._buff_i)
+ L, n = _unpack_from('Bb', self._buffer, self._buff_i)
self._buff_i += 2
if L > self._max_ext_len:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
obj = self._read(L)
elif b == 0xc8: # ext 16
typ = TYPE_EXT
self._reserve(3)
- L, n = struct.unpack_from('>Hb', self._buffer, self._buff_i)
+ L, n = _unpack_from('>Hb', self._buffer, self._buff_i)
self._buff_i += 3
if L > self._max_ext_len:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
obj = self._read(L)
elif b == 0xc9: # ext 32
typ = TYPE_EXT
self._reserve(5)
- L, n = struct.unpack_from('>Ib', self._buffer, self._buff_i)
+ L, n = _unpack_from('>Ib', self._buffer, self._buff_i)
self._buff_i += 5
if L > self._max_ext_len:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
obj = self._read(L)
elif b == 0xca:
self._reserve(4)
- obj = struct.unpack_from(">f", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">f", self._buffer, self._buff_i)[0]
self._buff_i += 4
elif b == 0xcb:
self._reserve(8)
- obj = struct.unpack_from(">d", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">d", self._buffer, self._buff_i)[0]
self._buff_i += 8
elif b == 0xcc:
self._reserve(1)
@@ -439,66 +496,66 @@ class Unpacker(object):
self._buff_i += 1
elif b == 0xcd:
self._reserve(2)
- obj = struct.unpack_from(">H", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">H", self._buffer, self._buff_i)[0]
self._buff_i += 2
elif b == 0xce:
self._reserve(4)
- obj = struct.unpack_from(">I", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">I", self._buffer, self._buff_i)[0]
self._buff_i += 4
elif b == 0xcf:
self._reserve(8)
- obj = struct.unpack_from(">Q", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">Q", self._buffer, self._buff_i)[0]
self._buff_i += 8
elif b == 0xd0:
self._reserve(1)
- obj = struct.unpack_from("b", self._buffer, self._buff_i)[0]
+ obj = _unpack_from("b", self._buffer, self._buff_i)[0]
self._buff_i += 1
elif b == 0xd1:
self._reserve(2)
- obj = struct.unpack_from(">h", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">h", self._buffer, self._buff_i)[0]
self._buff_i += 2
elif b == 0xd2:
self._reserve(4)
- obj = struct.unpack_from(">i", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">i", self._buffer, self._buff_i)[0]
self._buff_i += 4
elif b == 0xd3:
self._reserve(8)
- obj = struct.unpack_from(">q", self._buffer, self._buff_i)[0]
+ obj = _unpack_from(">q", self._buffer, self._buff_i)[0]
self._buff_i += 8
elif b == 0xd4: # fixext 1
typ = TYPE_EXT
if self._max_ext_len < 1:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (1, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (1, self._max_ext_len))
self._reserve(2)
- n, obj = struct.unpack_from("b1s", self._buffer, self._buff_i)
+ n, obj = _unpack_from("b1s", self._buffer, self._buff_i)
self._buff_i += 2
elif b == 0xd5: # fixext 2
typ = TYPE_EXT
if self._max_ext_len < 2:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (2, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (2, self._max_ext_len))
self._reserve(3)
- n, obj = struct.unpack_from("b2s", self._buffer, self._buff_i)
+ n, obj = _unpack_from("b2s", self._buffer, self._buff_i)
self._buff_i += 3
elif b == 0xd6: # fixext 4
typ = TYPE_EXT
if self._max_ext_len < 4:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (4, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (4, self._max_ext_len))
self._reserve(5)
- n, obj = struct.unpack_from("b4s", self._buffer, self._buff_i)
+ n, obj = _unpack_from("b4s", self._buffer, self._buff_i)
self._buff_i += 5
elif b == 0xd7: # fixext 8
typ = TYPE_EXT
if self._max_ext_len < 8:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (8, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (8, self._max_ext_len))
self._reserve(9)
- n, obj = struct.unpack_from("b8s", self._buffer, self._buff_i)
+ n, obj = _unpack_from("b8s", self._buffer, self._buff_i)
self._buff_i += 9
elif b == 0xd8: # fixext 16
typ = TYPE_EXT
if self._max_ext_len < 16:
- raise UnpackValueError("%s exceeds max_ext_len(%s)" % (16, self._max_ext_len))
+ raise ValueError("%s exceeds max_ext_len(%s)" % (16, self._max_ext_len))
self._reserve(17)
- n, obj = struct.unpack_from("b16s", self._buffer, self._buff_i)
+ n, obj = _unpack_from("b16s", self._buffer, self._buff_i)
self._buff_i += 17
elif b == 0xd9:
typ = TYPE_RAW
@@ -506,54 +563,54 @@ class Unpacker(object):
n = self._buffer[self._buff_i]
self._buff_i += 1
if n > self._max_str_len:
- raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
+ raise ValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
obj = self._read(n)
elif b == 0xda:
typ = TYPE_RAW
self._reserve(2)
- n, = struct.unpack_from(">H", self._buffer, self._buff_i)
+ n, = _unpack_from(">H", self._buffer, self._buff_i)
self._buff_i += 2
if n > self._max_str_len:
- raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
+ raise ValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
obj = self._read(n)
elif b == 0xdb:
typ = TYPE_RAW
self._reserve(4)
- n, = struct.unpack_from(">I", self._buffer, self._buff_i)
+ n, = _unpack_from(">I", self._buffer, self._buff_i)
self._buff_i += 4
if n > self._max_str_len:
- raise UnpackValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
+ raise ValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
obj = self._read(n)
elif b == 0xdc:
typ = TYPE_ARRAY
self._reserve(2)
- n, = struct.unpack_from(">H", self._buffer, self._buff_i)
+ n, = _unpack_from(">H", self._buffer, self._buff_i)
self._buff_i += 2
if n > self._max_array_len:
- raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
+ raise ValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
elif b == 0xdd:
typ = TYPE_ARRAY
self._reserve(4)
- n, = struct.unpack_from(">I", self._buffer, self._buff_i)
+ n, = _unpack_from(">I", self._buffer, self._buff_i)
self._buff_i += 4
if n > self._max_array_len:
- raise UnpackValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
+ raise ValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
elif b == 0xde:
self._reserve(2)
- n, = struct.unpack_from(">H", self._buffer, self._buff_i)
+ n, = _unpack_from(">H", self._buffer, self._buff_i)
self._buff_i += 2
if n > self._max_map_len:
- raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
+ raise ValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
typ = TYPE_MAP
elif b == 0xdf:
self._reserve(4)
- n, = struct.unpack_from(">I", self._buffer, self._buff_i)
+ n, = _unpack_from(">I", self._buffer, self._buff_i)
self._buff_i += 4
if n > self._max_map_len:
- raise UnpackValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
+ raise ValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
typ = TYPE_MAP
else:
- raise UnpackValueError("Unknown header: 0x%x" % b)
+ raise FormatError("Unknown header: 0x%x" % b)
return typ, n, obj
def _unpack(self, execute=EX_CONSTRUCT):
@@ -561,11 +618,11 @@ class Unpacker(object):
if execute == EX_READ_ARRAY_HEADER:
if typ != TYPE_ARRAY:
- raise UnpackValueError("Expected array")
+ raise ValueError("Expected array")
return n
if execute == EX_READ_MAP_HEADER:
if typ != TYPE_MAP:
- raise UnpackValueError("Expected map")
+ raise ValueError("Expected map")
return n
# TODO should we eliminate the recursion?
if typ == TYPE_ARRAY:
@@ -597,6 +654,8 @@ class Unpacker(object):
ret = {}
for _ in xrange(n):
key = self._unpack(EX_CONSTRUCT)
+ if self._strict_map_key and type(key) not in (unicode, bytes):
+ raise ValueError("%s is not allowed for map key" % str(type(key)))
ret[key] = self._unpack(EX_CONSTRUCT)
if self._object_hook is not None:
ret = self._object_hook(ret)
@@ -629,37 +688,30 @@ class Unpacker(object):
except OutOfData:
self._consume()
raise StopIteration
+ except RecursionError:
+ raise StackError
next = __next__
- def skip(self, write_bytes=None):
+ def skip(self):
self._unpack(EX_SKIP)
- if write_bytes is not None:
- warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning)
- write_bytes(self._buffer[self._buf_checkpoint:self._buff_i])
self._consume()
- def unpack(self, write_bytes=None):
- ret = self._unpack(EX_CONSTRUCT)
- if write_bytes is not None:
- warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning)
- write_bytes(self._buffer[self._buf_checkpoint:self._buff_i])
+ def unpack(self):
+ try:
+ ret = self._unpack(EX_CONSTRUCT)
+ except RecursionError:
+ raise StackError
self._consume()
return ret
- def read_array_header(self, write_bytes=None):
+ def read_array_header(self):
ret = self._unpack(EX_READ_ARRAY_HEADER)
- if write_bytes is not None:
- warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning)
- write_bytes(self._buffer[self._buf_checkpoint:self._buff_i])
self._consume()
return ret
- def read_map_header(self, write_bytes=None):
+ def read_map_header(self):
ret = self._unpack(EX_READ_MAP_HEADER)
- if write_bytes is not None:
- warnings.warn("`write_bytes` option is deprecated. Use `.tell()` instead.", DeprecationWarning)
- write_bytes(self._buffer[self._buf_checkpoint:self._buff_i])
self._consume()
return ret
@@ -716,7 +768,7 @@ class Packer(object):
else:
warnings.warn(
"encoding is deprecated, Use raw=False instead.",
- PendingDeprecationWarning)
+ DeprecationWarning, stacklevel=2)
if unicode_errors is None:
unicode_errors = 'strict'
@@ -743,7 +795,7 @@ class Packer(object):
list_types = (list, tuple)
while True:
if nest_limit < 0:
- raise PackValueError("recursion limit exceeded")
+ raise ValueError("recursion limit exceeded")
if obj is None:
return self._buffer.write(b"\xc0")
if check(obj, bool):
@@ -775,14 +827,14 @@ class Packer(object):
obj = self._default(obj)
default_used = True
continue
- raise PackOverflowError("Integer value out of range")
+ raise OverflowError("Integer value out of range")
if check(obj, (bytes, bytearray)):
n = len(obj)
if n >= 2**32:
- raise PackValueError("%s is too large" % type(obj).__name__)
+ raise ValueError("%s is too large" % type(obj).__name__)
self._pack_bin_header(n)
return self._buffer.write(obj)
- if check(obj, Unicode):
+ if check(obj, unicode):
if self._encoding is None:
raise TypeError(
"Can't encode unicode string: "
@@ -790,13 +842,13 @@ class Packer(object):
obj = obj.encode(self._encoding, self._unicode_errors)
n = len(obj)
if n >= 2**32:
- raise PackValueError("String is too large")
+ raise ValueError("String is too large")
self._pack_raw_header(n)
return self._buffer.write(obj)
if check(obj, memoryview):
n = len(obj) * obj.itemsize
if n >= 2**32:
- raise PackValueError("Memoryview is too large")
+ raise ValueError("Memoryview is too large")
self._pack_bin_header(n)
return self._buffer.write(obj)
if check(obj, float):
@@ -849,43 +901,35 @@ class Packer(object):
except:
self._buffer = StringIO() # force reset
raise
- ret = self._buffer.getvalue()
if self._autoreset:
+ ret = self._buffer.getvalue()
self._buffer = StringIO()
- elif USING_STRINGBUILDER:
- self._buffer = StringIO(ret)
- return ret
+ return ret
def pack_map_pairs(self, pairs):
self._pack_map_pairs(len(pairs), pairs)
- ret = self._buffer.getvalue()
if self._autoreset:
+ ret = self._buffer.getvalue()
self._buffer = StringIO()
- elif USING_STRINGBUILDER:
- self._buffer = StringIO(ret)
- return ret
+ return ret
def pack_array_header(self, n):
if n >= 2**32:
- raise PackValueError
+ raise ValueError
self._pack_array_header(n)
- ret = self._buffer.getvalue()
if self._autoreset:
+ ret = self._buffer.getvalue()
self._buffer = StringIO()
- elif USING_STRINGBUILDER:
- self._buffer = StringIO(ret)
- return ret
+ return ret
def pack_map_header(self, n):
if n >= 2**32:
- raise PackValueError
+ raise ValueError
self._pack_map_header(n)
- ret = self._buffer.getvalue()
if self._autoreset:
+ ret = self._buffer.getvalue()
self._buffer = StringIO()
- elif USING_STRINGBUILDER:
- self._buffer = StringIO(ret)
- return ret
+ return ret
def pack_ext_type(self, typecode, data):
if not isinstance(typecode, int):
@@ -896,7 +940,7 @@ class Packer(object):
raise TypeError("data must have bytes type")
L = len(data)
if L > 0xffffffff:
- raise PackValueError("Too large data")
+ raise ValueError("Too large data")
if L == 1:
self._buffer.write(b'\xd4')
elif L == 2:
@@ -923,7 +967,7 @@ class Packer(object):
return self._buffer.write(struct.pack(">BH", 0xdc, n))
if n <= 0xffffffff:
return self._buffer.write(struct.pack(">BI", 0xdd, n))
- raise PackValueError("Array is too large")
+ raise ValueError("Array is too large")
def _pack_map_header(self, n):
if n <= 0x0f:
@@ -932,7 +976,7 @@ class Packer(object):
return self._buffer.write(struct.pack(">BH", 0xde, n))
if n <= 0xffffffff:
return self._buffer.write(struct.pack(">BI", 0xdf, n))
- raise PackValueError("Dict is too large")
+ raise ValueError("Dict is too large")
def _pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT):
self._pack_map_header(n)
@@ -950,7 +994,7 @@ class Packer(object):
elif n <= 0xffffffff:
self._buffer.write(struct.pack(">BI", 0xdb, n))
else:
- raise PackValueError('Raw is too large')
+ raise ValueError('Raw is too large')
def _pack_bin_header(self, n):
if not self._use_bin_type:
@@ -962,10 +1006,22 @@ class Packer(object):
elif n <= 0xffffffff:
return self._buffer.write(struct.pack(">BI", 0xc6, n))
else:
- raise PackValueError('Bin is too large')
+ raise ValueError('Bin is too large')
def bytes(self):
+ """Return internal buffer contents as bytes object"""
return self._buffer.getvalue()
def reset(self):
+ """Reset internal buffer.
+
+ This method is usaful only when autoreset=False.
+ """
self._buffer = StringIO()
+
+ def getbuffer(self):
+ """Return view of internal buffer."""
+ if USING_STRINGBUILDER or PY2:
+ return memoryview(self.bytes())
+ else:
+ return self._buffer.getbuffer()
diff --git a/msgpack/pack_template.h b/msgpack/pack_template.h
index 5d1088f..69982f4 100644
--- a/msgpack/pack_template.h
+++ b/msgpack/pack_template.h
@@ -566,24 +566,17 @@ if(sizeof(unsigned long long) == 2) {
static inline int msgpack_pack_float(msgpack_packer* x, float d)
{
- union { float f; uint32_t i; } mem;
- mem.f = d;
unsigned char buf[5];
- buf[0] = 0xca; _msgpack_store32(&buf[1], mem.i);
+ buf[0] = 0xca;
+ _PyFloat_Pack4(d, &buf[1], 0);
msgpack_pack_append_buffer(x, buf, 5);
}
static inline int msgpack_pack_double(msgpack_packer* x, double d)
{
- union { double f; uint64_t i; } mem;
- mem.f = d;
unsigned char buf[9];
buf[0] = 0xcb;
-#if defined(__arm__) && !(__ARM_EABI__) // arm-oabi
- // https://github.com/msgpack/msgpack-perl/pull/1
- mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL);
-#endif
- _msgpack_store64(&buf[1], mem.i);
+ _PyFloat_Pack8(d, &buf[1], 0);
msgpack_pack_append_buffer(x, buf, 9);
}
diff --git a/msgpack/unpack.h b/msgpack/unpack.h
index 63e5543..85dbbed 100644
--- a/msgpack/unpack.h
+++ b/msgpack/unpack.h
@@ -23,6 +23,7 @@ typedef struct unpack_user {
bool use_list;
bool raw;
bool has_pairs_hook;
+ bool strict_map_key;
PyObject *object_hook;
PyObject *list_hook;
PyObject *ext_hook;
@@ -188,6 +189,10 @@ static inline int unpack_callback_map(unpack_user* u, unsigned int n, msgpack_un
static inline int unpack_callback_map_item(unpack_user* u, unsigned int current, msgpack_unpack_object* c, msgpack_unpack_object k, msgpack_unpack_object v)
{
+ if (u->strict_map_key && !PyUnicode_CheckExact(k) && !PyBytes_CheckExact(k)) {
+ PyErr_Format(PyExc_ValueError, "%.100s is not allowed for map key", Py_TYPE(k)->tp_name);
+ return -1;
+ }
if (u->has_pairs_hook) {
msgpack_unpack_object item = PyTuple_Pack(2, k, v);
if (!item)
diff --git a/msgpack/unpack_template.h b/msgpack/unpack_template.h
index 525dea2..9924b9c 100644
--- a/msgpack/unpack_template.h
+++ b/msgpack/unpack_template.h
@@ -123,7 +123,7 @@ static inline int unpack_execute(unpack_context* ctx, const char* data, Py_ssize
goto _fixed_trail_again
#define start_container(func, count_, ct_) \
- if(top >= MSGPACK_EMBED_STACK_SIZE) { goto _failed; } /* FIXME */ \
+ if(top >= MSGPACK_EMBED_STACK_SIZE) { ret = -3; goto _end; } \
if(construct_cb(func)(user, count_, &stack[top].obj) < 0) { goto _failed; } \
if((count_) == 0) { obj = stack[top].obj; \
if (construct_cb(func##_end)(user, &obj) < 0) { goto _failed; } \
@@ -132,27 +132,6 @@ static inline int unpack_execute(unpack_context* ctx, const char* data, Py_ssize
stack[top].size = count_; \
stack[top].count = 0; \
++top; \
- /*printf("container %d count %d stack %d\n",stack[top].obj,count_,top);*/ \
- /*printf("stack push %d\n", top);*/ \
- /* FIXME \
- if(top >= stack_size) { \
- if(stack_size == MSGPACK_EMBED_STACK_SIZE) { \
- size_t csize = sizeof(unpack_stack) * MSGPACK_EMBED_STACK_SIZE; \
- size_t nsize = csize * 2; \
- unpack_stack* tmp = (unpack_stack*)malloc(nsize); \
- if(tmp == NULL) { goto _failed; } \
- memcpy(tmp, ctx->stack, csize); \
- ctx->stack = stack = tmp; \
- ctx->stack_size = stack_size = MSGPACK_EMBED_STACK_SIZE * 2; \
- } else { \
- size_t nsize = sizeof(unpack_stack) * ctx->stack_size * 2; \
- unpack_stack* tmp = (unpack_stack*)realloc(ctx->stack, nsize); \
- if(tmp == NULL) { goto _failed; } \
- ctx->stack = stack = tmp; \
- ctx->stack_size = stack_size = stack_size * 2; \
- } \
- } \
- */ \
goto _header_again
#define NEXT_CS(p) ((unsigned int)*p & 0x1f)
@@ -229,7 +208,8 @@ static inline int unpack_execute(unpack_context* ctx, const char* data, Py_ssize
case 0xdf: // map 32
again_fixed_trail(NEXT_CS(p), 2 << (((unsigned int)*p) & 0x01));
default:
- goto _failed;
+ ret = -2;
+ goto _end;
}
SWITCH_RANGE(0xa0, 0xbf) // FixRaw
again_fixed_trail_if_zero(ACS_RAW_VALUE, ((unsigned int)*p & 0x1f), _raw_zero);
@@ -239,7 +219,8 @@ static inline int unpack_execute(unpack_context* ctx, const char* data, Py_ssize
start_container(_map, ((unsigned int)*p) & 0x0f, CT_MAP_KEY);
SWITCH_RANGE_DEFAULT
- goto _failed;
+ ret = -2;
+ goto _end;
SWITCH_RANGE_END
// end CS_HEADER
@@ -262,17 +243,11 @@ static inline int unpack_execute(unpack_context* ctx, const char* data, Py_ssize
_msgpack_load32(uint32_t,n)+1,
_ext_zero);
case CS_FLOAT: {
- union { uint32_t i; float f; } mem;
- mem.i = _msgpack_load32(uint32_t,n);
- push_fixed_value(_float, mem.f); }
+ double f = _PyFloat_Unpack4((unsigned char*)n, 0);
+ push_fixed_value(_float, f); }
case CS_DOUBLE: {
- union { uint64_t i; double f; } mem;
- mem.i = _msgpack_load64(uint64_t,n);
-#if defined(__arm__) && !(__ARM_EABI__) // arm-oabi
- // https://github.com/msgpack/msgpack-perl/pull/1
- mem.i = (mem.i & 0xFFFFFFFFUL) << 32UL | (mem.i >> 32UL);
-#endif
- push_fixed_value(_double, mem.f); }
+ double f = _PyFloat_Unpack8((unsigned char*)n, 0);
+ push_fixed_value(_double, f); }
case CS_UINT_8:
push_fixed_value(_uint8, *(uint8_t*)n);
case CS_UINT_16: