@@ -8,16 +8,24 @@ from cpython.bytes cimport (
8
8
)
9
9
from cpython.buffer cimport (
10
10
Py_buffer,
11
- PyBuffer_Release ,
11
+ PyObject_CheckBuffer ,
12
12
PyObject_GetBuffer,
13
+ PyBuffer_Release,
14
+ PyBuffer_IsContiguous,
15
+ PyBuffer_FillInfo,
16
+ PyBUF_READ,
13
17
PyBUF_SIMPLE,
18
+ PyBUF_FULL_RO,
14
19
)
15
20
from cpython.mem cimport PyMem_Malloc, PyMem_Free
16
21
from cpython.object cimport PyCallable_Check
22
+ from cpython.ref cimport Py_DECREF
23
+ from cpython.exc cimport PyErr_WarnEx
17
24
18
25
cdef extern from " Python.h" :
19
26
ctypedef struct PyObject
20
27
cdef int PyObject_AsReadBuffer(object o, const void ** buff, Py_ssize_t* buf_len) except - 1
28
+ object PyMemoryView_GetContiguous(object obj, int buffertype, char order)
21
29
22
30
from libc.stdlib cimport *
23
31
from libc.string cimport *
@@ -110,6 +118,40 @@ cdef inline init_ctx(unpack_context *ctx,
110
118
def default_read_extended_type (typecode , data ):
111
119
raise NotImplementedError (" Cannot decode extended type with typecode=%d " % typecode)
112
120
121
+ cdef inline int get_data_from_buffer(object obj,
122
+ Py_buffer * view,
123
+ char ** buf,
124
+ Py_ssize_t * buffer_len,
125
+ int * new_protocol) except 0 :
126
+ cdef object contiguous
127
+ cdef Py_buffer tmp
128
+ if PyObject_CheckBuffer(obj):
129
+ new_protocol[0 ] = 1
130
+ if PyObject_GetBuffer(obj, view, PyBUF_FULL_RO) == - 1 :
131
+ raise
132
+ if view.itemsize != 1 :
133
+ PyBuffer_Release(view)
134
+ raise BufferError(" cannot unpack from multi-byte object" )
135
+ if PyBuffer_IsContiguous(view, ' A' ) == 0 :
136
+ contiguous = PyMemoryView_GetContiguous(obj, PyBUF_READ, ' C' )
137
+ PyObject_GetBuffer(contiguous, & tmp, PyBUF_SIMPLE)
138
+ PyBuffer_Release(view)
139
+ PyBuffer_FillInfo(view, contiguous, tmp.buf, tmp.len, 1 , 0 )
140
+ Py_DECREF(contiguous)
141
+ buffer_len[0 ] = view.len
142
+ buf[0 ] = < char * > view.buf
143
+ return 1
144
+ else :
145
+ new_protocol[0 ] = 0
146
+ if PyObject_AsReadBuffer(obj, < const void ** > buf, buffer_len) == - 1 :
147
+ raise BufferError(" could not get memoryview" )
148
+ PyErr_WarnEx(RuntimeWarning ,
149
+ " using old buffer interface to unpack %s ; "
150
+ " this leads to unpacking errors if slicing is used and "
151
+ " will be removed in a future version" % type (obj),
152
+ 1 )
153
+ return 1
154
+
113
155
def unpackb (object packed , object object_hook = None , object list_hook = None ,
114
156
bint use_list =
8000
1 , encoding = None , unicode_errors = " strict" ,
115
157
object_pairs_hook = None , ext_hook = ExtType,
@@ -129,12 +171,14 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
129
171
cdef Py_ssize_t off = 0
130
172
cdef int ret
131
173
132
- cdef char * buf
174
+ cdef Py_buffer view
175
+ cdef char * buf = NULL
133
176
cdef Py_ssize_t buf_len
134
177
cdef char * cenc = NULL
135
178
cdef char * cerr = NULL
179
+ cdef int new_protocol = 0
136
180
137
- PyObject_AsReadBuffer (packed, < const void ** > & buf, & buf_len)
181
+ get_data_from_buffer (packed, & view, & buf, & buf_len, & new_protocol )
138
182
139
183
if encoding is not None :
140
184
if isinstance (encoding, unicode ):
@@ -150,6 +194,8 @@ def unpackb(object packed, object object_hook=None, object list_hook=None,
150
194
use_list, cenc, cerr,
151
195
max_str_len, max_bin_len, max_array_len, max_map_len, max_ext_len)
152
196
ret = unpack_construct(& ctx, buf, buf_len, & off)
197
+ if new_protocol:
198
+ PyBuffer_Release(& view);
153
199
if ret == 1 :
154
200
obj = unpack_data(& ctx)
155
201
if off < buf_len:
@@ -335,14 +381,20 @@ cdef class Unpacker(object):
335
381
def feed (self , object next_bytes ):
336
382
""" Append `next_bytes` to internal buffer."""
337
383
cdef Py_buffer pybuff
384
+ cdef int new_protocol = 0
385
+ cdef char * buf
386
+ cdef Py_ssize_t buf_len
387
+
338
388
if self .file_like is not None :
339
389
raise AssertionError (
340
390
" unpacker.feed() is not be able to use with `file_like`." )
341
- PyObject_GetBuffer(next_bytes, & pybuff, PyBUF_SIMPLE)
391
+
392
+ get_data_from_buffer(next_bytes, & pybuff, & buf, & buf_len, & new_protocol)
342
393
try :
<
9E88
/td>343
- self .append_buffer(< char * > pybuff. buf, pybuff.len )
394
+ self .append_buffer(buf, buf_len )
344
395
finally :
345
- PyBuffer_Release(& pybuff)
396
+ if new_protocol:
397
+ PyBuffer_Release(& pybuff)
346
398
347
399
cdef append_buffer(self , void * _buf, Py_ssize_t _buf_len):
348
400
cdef:
0 commit comments