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