1 |
|
---|
2 | /* Buffer object implementation */
|
---|
3 |
|
---|
4 | #include "Python.h"
|
---|
5 |
|
---|
6 |
|
---|
7 | typedef struct {
|
---|
8 | PyObject_HEAD
|
---|
9 | PyObject *b_base;
|
---|
10 | void *b_ptr;
|
---|
11 | Py_ssize_t b_size;
|
---|
12 | Py_ssize_t b_offset;
|
---|
13 | int b_readonly;
|
---|
14 | long b_hash;
|
---|
15 | } PyBufferObject;
|
---|
16 |
|
---|
17 |
|
---|
18 | enum buffer_t {
|
---|
19 | READ_BUFFER,
|
---|
20 | WRITE_BUFFER,
|
---|
21 | CHAR_BUFFER,
|
---|
22 | ANY_BUFFER
|
---|
23 | };
|
---|
24 |
|
---|
25 | static int
|
---|
26 | get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
|
---|
27 | enum buffer_t buffer_type)
|
---|
28 | {
|
---|
29 | if (self->b_base == NULL) {
|
---|
30 | assert (ptr != NULL);
|
---|
31 | *ptr = self->b_ptr;
|
---|
32 | *size = self->b_size;
|
---|
33 | }
|
---|
34 | else {
|
---|
35 | Py_ssize_t count, offset;
|
---|
36 | readbufferproc proc = 0;
|
---|
37 | PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
|
---|
38 | if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
|
---|
39 | PyErr_SetString(PyExc_TypeError,
|
---|
40 | "single-segment buffer object expected");
|
---|
41 | return 0;
|
---|
42 | }
|
---|
43 | if ((buffer_type == READ_BUFFER) ||
|
---|
44 | ((buffer_type == ANY_BUFFER) && self->b_readonly))
|
---|
45 | proc = bp->bf_getreadbuffer;
|
---|
46 | else if ((buffer_type == WRITE_BUFFER) ||
|
---|
47 | (buffer_type == ANY_BUFFER))
|
---|
48 | proc = (readbufferproc)bp->bf_getwritebuffer;
|
---|
49 | else if (buffer_type == CHAR_BUFFER) {
|
---|
50 | if (!PyType_HasFeature(self->ob_type,
|
---|
51 | Py_TPFLAGS_HAVE_GETCHARBUFFER)) {
|
---|
52 | PyErr_SetString(PyExc_TypeError,
|
---|
53 | "Py_TPFLAGS_HAVE_GETCHARBUFFER needed");
|
---|
54 | return 0;
|
---|
55 | }
|
---|
56 | proc = (readbufferproc)bp->bf_getcharbuffer;
|
---|
57 | }
|
---|
58 | if (!proc) {
|
---|
59 | char *buffer_type_name;
|
---|
60 | switch (buffer_type) {
|
---|
61 | case READ_BUFFER:
|
---|
62 | buffer_type_name = "read";
|
---|
63 | break;
|
---|
64 | case WRITE_BUFFER:
|
---|
65 | buffer_type_name = "write";
|
---|
66 | break;
|
---|
67 | case CHAR_BUFFER:
|
---|
68 | buffer_type_name = "char";
|
---|
69 | break;
|
---|
70 | default:
|
---|
71 | buffer_type_name = "no";
|
---|
72 | break;
|
---|
73 | }
|
---|
74 | PyErr_Format(PyExc_TypeError,
|
---|
75 | "%s buffer type not available",
|
---|
76 | buffer_type_name);
|
---|
77 | return 0;
|
---|
78 | }
|
---|
79 | if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
|
---|
80 | return 0;
|
---|
81 | /* apply constraints to the start/end */
|
---|
82 | if (self->b_offset > count)
|
---|
83 | offset = count;
|
---|
84 | else
|
---|
85 | offset = self->b_offset;
|
---|
86 | *(char **)ptr = *(char **)ptr + offset;
|
---|
87 | if (self->b_size == Py_END_OF_BUFFER)
|
---|
88 | *size = count;
|
---|
89 | else
|
---|
90 | *size = self->b_size;
|
---|
91 | if (offset + *size > count)
|
---|
92 | *size = count - offset;
|
---|
93 | }
|
---|
94 | return 1;
|
---|
95 | }
|
---|
96 |
|
---|
97 |
|
---|
98 | static PyObject *
|
---|
99 | buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
|
---|
100 | int readonly)
|
---|
101 | {
|
---|
102 | PyBufferObject * b;
|
---|
103 |
|
---|
104 | if (size < 0 && size != Py_END_OF_BUFFER) {
|
---|
105 | PyErr_SetString(PyExc_ValueError,
|
---|
106 | "size must be zero or positive");
|
---|
107 | return NULL;
|
---|
108 | }
|
---|
109 | if (offset < 0) {
|
---|
110 | PyErr_SetString(PyExc_ValueError,
|
---|
111 | "offset must be zero or positive");
|
---|
112 | return NULL;
|
---|
113 | }
|
---|
114 |
|
---|
115 | b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
|
---|
116 | if ( b == NULL )
|
---|
117 | return NULL;
|
---|
118 |
|
---|
119 | Py_XINCREF(base);
|
---|
120 | b->b_base = base;
|
---|
121 | b->b_ptr = ptr;
|
---|
122 | b->b_size = size;
|
---|
123 | b->b_offset = offset;
|
---|
124 | b->b_readonly = readonly;
|
---|
125 | b->b_hash = -1;
|
---|
126 |
|
---|
127 | return (PyObject *) b;
|
---|
128 | }
|
---|
129 |
|
---|
130 | static PyObject *
|
---|
131 | buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly)
|
---|
132 | {
|
---|
133 | if (offset < 0) {
|
---|
134 | PyErr_SetString(PyExc_ValueError,
|
---|
135 | "offset must be zero or positive");
|
---|
136 | return NULL;
|
---|
137 | }
|
---|
138 | if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
|
---|
139 | /* another buffer, refer to the base object */
|
---|
140 | PyBufferObject *b = (PyBufferObject *)base;
|
---|
141 | if (b->b_size != Py_END_OF_BUFFER) {
|
---|
142 | Py_ssize_t base_size = b->b_size - offset;
|
---|
143 | if (base_size < 0)
|
---|
144 | base_size = 0;
|
---|
145 | if (size == Py_END_OF_BUFFER || size > base_size)
|
---|
146 | size = base_size;
|
---|
147 | }
|
---|
148 | offset += b->b_offset;
|
---|
149 | base = b->b_base;
|
---|
150 | }
|
---|
151 | return buffer_from_memory(base, size, offset, NULL, readonly);
|
---|
152 | }
|
---|
153 |
|
---|
154 |
|
---|
155 | PyObject *
|
---|
156 | PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
|
---|
157 | {
|
---|
158 | PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
---|
159 |
|
---|
160 | if ( pb == NULL ||
|
---|
161 | pb->bf_getreadbuffer == NULL ||
|
---|
162 | pb->bf_getsegcount == NULL )
|
---|
163 | {
|
---|
164 | PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
---|
165 | return NULL;
|
---|
166 | }
|
---|
167 |
|
---|
168 | return buffer_from_object(base, size, offset, 1);
|
---|
169 | }
|
---|
170 |
|
---|
171 | PyObject *
|
---|
172 | PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
|
---|
173 | {
|
---|
174 | PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
---|
175 |
|
---|
176 | if ( pb == NULL ||
|
---|
177 | pb->bf_getwritebuffer == NULL ||
|
---|
178 | pb->bf_getsegcount == NULL )
|
---|
179 | {
|
---|
180 | PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
---|
181 | return NULL;
|
---|
182 | }
|
---|
183 |
|
---|
184 | return buffer_from_object(base, size, offset, 0);
|
---|
185 | }
|
---|
186 |
|
---|
187 | PyObject *
|
---|
188 | PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
|
---|
189 | {
|
---|
190 | return buffer_from_memory(NULL, size, 0, ptr, 1);
|
---|
191 | }
|
---|
192 |
|
---|
193 | PyObject *
|
---|
194 | PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
|
---|
195 | {
|
---|
196 | return buffer_from_memory(NULL, size, 0, ptr, 0);
|
---|
197 | }
|
---|
198 |
|
---|
199 | PyObject *
|
---|
200 | PyBuffer_New(Py_ssize_t size)
|
---|
201 | {
|
---|
202 | PyObject *o;
|
---|
203 | PyBufferObject * b;
|
---|
204 |
|
---|
205 | if (size < 0) {
|
---|
206 | PyErr_SetString(PyExc_ValueError,
|
---|
207 | "size must be zero or positive");
|
---|
208 | return NULL;
|
---|
209 | }
|
---|
210 | if (sizeof(*b) > PY_SSIZE_T_MAX - size) {
|
---|
211 | /* unlikely */
|
---|
212 | return PyErr_NoMemory();
|
---|
213 | }
|
---|
214 | /* Inline PyObject_New */
|
---|
215 | o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size);
|
---|
216 | if ( o == NULL )
|
---|
217 | return PyErr_NoMemory();
|
---|
218 | b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
|
---|
219 |
|
---|
220 | b->b_base = NULL;
|
---|
221 | b->b_ptr = (void *)(b + 1);
|
---|
222 | b->b_size = size;
|
---|
223 | b->b_offset = 0;
|
---|
224 | b->b_readonly = 0;
|
---|
225 | b->b_hash = -1;
|
---|
226 |
|
---|
227 | return o;
|
---|
228 | }
|
---|
229 |
|
---|
230 | /* Methods */
|
---|
231 |
|
---|
232 | static PyObject *
|
---|
233 | buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
---|
234 | {
|
---|
235 | PyObject *ob;
|
---|
236 | Py_ssize_t offset = 0;
|
---|
237 | Py_ssize_t size = Py_END_OF_BUFFER;
|
---|
238 |
|
---|
239 | if (PyErr_WarnPy3k("buffer() not supported in 3.x", 1) < 0)
|
---|
240 | return NULL;
|
---|
241 |
|
---|
242 | if (!_PyArg_NoKeywords("buffer()", kw))
|
---|
243 | return NULL;
|
---|
244 |
|
---|
245 | if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size))
|
---|
246 | return NULL;
|
---|
247 | return PyBuffer_FromObject(ob, offset, size);
|
---|
248 | }
|
---|
249 |
|
---|
250 | PyDoc_STRVAR(buffer_doc,
|
---|
251 | "buffer(object [, offset[, size]])\n\
|
---|
252 | \n\
|
---|
253 | Create a new buffer object which references the given object.\n\
|
---|
254 | The buffer will reference a slice of the target object from the\n\
|
---|
255 | start of the object (or at the specified offset). The slice will\n\
|
---|
256 | extend to the end of the target object (or with the specified size).");
|
---|
257 |
|
---|
258 |
|
---|
259 | static void
|
---|
260 | buffer_dealloc(PyBufferObject *self)
|
---|
261 | {
|
---|
262 | Py_XDECREF(self->b_base);
|
---|
263 | PyObject_DEL(self);
|
---|
264 | }
|
---|
265 |
|
---|
266 | static int
|
---|
267 | buffer_compare(PyBufferObject *self, PyBufferObject *other)
|
---|
268 | {
|
---|
269 | void *p1, *p2;
|
---|
270 | Py_ssize_t len_self, len_other, min_len;
|
---|
271 | int cmp;
|
---|
272 |
|
---|
273 | if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
|
---|
274 | return -1;
|
---|
275 | if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
|
---|
276 | return -1;
|
---|
277 | min_len = (len_self < len_other) ? len_self : len_other;
|
---|
278 | if (min_len > 0) {
|
---|
279 | cmp = memcmp(p1, p2, min_len);
|
---|
280 | if (cmp != 0)
|
---|
281 | return cmp < 0 ? -1 : 1;
|
---|
282 | }
|
---|
283 | return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
|
---|
284 | }
|
---|
285 |
|
---|
286 | static PyObject *
|
---|
287 | buffer_repr(PyBufferObject *self)
|
---|
288 | {
|
---|
289 | const char *status = self->b_readonly ? "read-only" : "read-write";
|
---|
290 |
|
---|
291 | if ( self->b_base == NULL )
|
---|
292 | return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>",
|
---|
293 | status,
|
---|
294 | self->b_ptr,
|
---|
295 | self->b_size,
|
---|
296 | self);
|
---|
297 | else
|
---|
298 | return PyString_FromFormat(
|
---|
299 | "<%s buffer for %p, size %zd, offset %zd at %p>",
|
---|
300 | status,
|
---|
301 | self->b_base,
|
---|
302 | self->b_size,
|
---|
303 | self->b_offset,
|
---|
304 | self);
|
---|
305 | }
|
---|
306 |
|
---|
307 | static long
|
---|
308 | buffer_hash(PyBufferObject *self)
|
---|
309 | {
|
---|
310 | void *ptr;
|
---|
311 | Py_ssize_t size;
|
---|
312 | register Py_ssize_t len;
|
---|
313 | register unsigned char *p;
|
---|
314 | register long x;
|
---|
315 |
|
---|
316 | if ( self->b_hash != -1 )
|
---|
317 | return self->b_hash;
|
---|
318 |
|
---|
319 | /* XXX potential bugs here, a readonly buffer does not imply that the
|
---|
320 | * underlying memory is immutable. b_readonly is a necessary but not
|
---|
321 | * sufficient condition for a buffer to be hashable. Perhaps it would
|
---|
322 | * be better to only allow hashing if the underlying object is known to
|
---|
323 | * be immutable (e.g. PyString_Check() is true). Another idea would
|
---|
324 | * be to call tp_hash on the underlying object and see if it raises
|
---|
325 | * an error. */
|
---|
326 | if ( !self->b_readonly )
|
---|
327 | {
|
---|
328 | PyErr_SetString(PyExc_TypeError,
|
---|
329 | "writable buffers are not hashable");
|
---|
330 | return -1;
|
---|
331 | }
|
---|
332 |
|
---|
333 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
334 | return -1;
|
---|
335 | p = (unsigned char *) ptr;
|
---|
336 | len = size;
|
---|
337 | x = *p << 7;
|
---|
338 | while (--len >= 0)
|
---|
339 | x = (1000003*x) ^ *p++;
|
---|
340 | x ^= size;
|
---|
341 | if (x == -1)
|
---|
342 | x = -2;
|
---|
343 | self->b_hash = x;
|
---|
344 | return x;
|
---|
345 | }
|
---|
346 |
|
---|
347 | static PyObject *
|
---|
348 | buffer_str(PyBufferObject *self)
|
---|
349 | {
|
---|
350 | void *ptr;
|
---|
351 | Py_ssize_t size;
|
---|
352 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
353 | return NULL;
|
---|
354 | return PyString_FromStringAndSize((const char *)ptr, size);
|
---|
355 | }
|
---|
356 |
|
---|
357 | /* Sequence methods */
|
---|
358 |
|
---|
359 | static Py_ssize_t
|
---|
360 | buffer_length(PyBufferObject *self)
|
---|
361 | {
|
---|
362 | void *ptr;
|
---|
363 | Py_ssize_t size;
|
---|
364 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
365 | return -1;
|
---|
366 | return size;
|
---|
367 | }
|
---|
368 |
|
---|
369 | static PyObject *
|
---|
370 | buffer_concat(PyBufferObject *self, PyObject *other)
|
---|
371 | {
|
---|
372 | PyBufferProcs *pb = other->ob_type->tp_as_buffer;
|
---|
373 | void *ptr1, *ptr2;
|
---|
374 | char *p;
|
---|
375 | PyObject *ob;
|
---|
376 | Py_ssize_t size, count;
|
---|
377 |
|
---|
378 | if ( pb == NULL ||
|
---|
379 | pb->bf_getreadbuffer == NULL ||
|
---|
380 | pb->bf_getsegcount == NULL )
|
---|
381 | {
|
---|
382 | PyErr_BadArgument();
|
---|
383 | return NULL;
|
---|
384 | }
|
---|
385 | if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
---|
386 | {
|
---|
387 | /* ### use a different exception type/message? */
|
---|
388 | PyErr_SetString(PyExc_TypeError,
|
---|
389 | "single-segment buffer object expected");
|
---|
390 | return NULL;
|
---|
391 | }
|
---|
392 |
|
---|
393 | if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
---|
394 | return NULL;
|
---|
395 |
|
---|
396 | /* optimize special case */
|
---|
397 | if ( size == 0 )
|
---|
398 | {
|
---|
399 | Py_INCREF(other);
|
---|
400 | return other;
|
---|
401 | }
|
---|
402 |
|
---|
403 | if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
---|
404 | return NULL;
|
---|
405 |
|
---|
406 | assert(count <= PY_SIZE_MAX - size);
|
---|
407 |
|
---|
408 | ob = PyString_FromStringAndSize(NULL, size + count);
|
---|
409 | if ( ob == NULL )
|
---|
410 | return NULL;
|
---|
411 | p = PyString_AS_STRING(ob);
|
---|
412 | memcpy(p, ptr1, size);
|
---|
413 | memcpy(p + size, ptr2, count);
|
---|
414 |
|
---|
415 | /* there is an extra byte in the string object, so this is safe */
|
---|
416 | p[size + count] = '\0';
|
---|
417 |
|
---|
418 | return ob;
|
---|
419 | }
|
---|
420 |
|
---|
421 | static PyObject *
|
---|
422 | buffer_repeat(PyBufferObject *self, Py_ssize_t count)
|
---|
423 | {
|
---|
424 | PyObject *ob;
|
---|
425 | register char *p;
|
---|
426 | void *ptr;
|
---|
427 | Py_ssize_t size;
|
---|
428 |
|
---|
429 | if ( count < 0 )
|
---|
430 | count = 0;
|
---|
431 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
432 | return NULL;
|
---|
433 | if (count > PY_SSIZE_T_MAX / size) {
|
---|
434 | PyErr_SetString(PyExc_MemoryError, "result too large");
|
---|
435 | return NULL;
|
---|
436 | }
|
---|
437 | ob = PyString_FromStringAndSize(NULL, size * count);
|
---|
438 | if ( ob == NULL )
|
---|
439 | return NULL;
|
---|
440 |
|
---|
441 | p = PyString_AS_STRING(ob);
|
---|
442 | while ( count-- )
|
---|
443 | {
|
---|
444 | memcpy(p, ptr, size);
|
---|
445 | p += size;
|
---|
446 | }
|
---|
447 |
|
---|
448 | /* there is an extra byte in the string object, so this is safe */
|
---|
449 | *p = '\0';
|
---|
450 |
|
---|
451 | return ob;
|
---|
452 | }
|
---|
453 |
|
---|
454 | static PyObject *
|
---|
455 | buffer_item(PyBufferObject *self, Py_ssize_t idx)
|
---|
456 | {
|
---|
457 | void *ptr;
|
---|
458 | Py_ssize_t size;
|
---|
459 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
460 | return NULL;
|
---|
461 | if ( idx < 0 || idx >= size ) {
|
---|
462 | PyErr_SetString(PyExc_IndexError, "buffer index out of range");
|
---|
463 | return NULL;
|
---|
464 | }
|
---|
465 | return PyString_FromStringAndSize((char *)ptr + idx, 1);
|
---|
466 | }
|
---|
467 |
|
---|
468 | static PyObject *
|
---|
469 | buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
|
---|
470 | {
|
---|
471 | void *ptr;
|
---|
472 | Py_ssize_t size;
|
---|
473 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
474 | return NULL;
|
---|
475 | if ( left < 0 )
|
---|
476 | left = 0;
|
---|
477 | if ( right < 0 )
|
---|
478 | right = 0;
|
---|
479 | if ( right > size )
|
---|
480 | right = size;
|
---|
481 | if ( right < left )
|
---|
482 | right = left;
|
---|
483 | return PyString_FromStringAndSize((char *)ptr + left,
|
---|
484 | right - left);
|
---|
485 | }
|
---|
486 |
|
---|
487 | static PyObject *
|
---|
488 | buffer_subscript(PyBufferObject *self, PyObject *item)
|
---|
489 | {
|
---|
490 | void *p;
|
---|
491 | Py_ssize_t size;
|
---|
492 |
|
---|
493 | if (!get_buf(self, &p, &size, ANY_BUFFER))
|
---|
494 | return NULL;
|
---|
495 | if (PyIndex_Check(item)) {
|
---|
496 | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
---|
497 | if (i == -1 && PyErr_Occurred())
|
---|
498 | return NULL;
|
---|
499 | if (i < 0)
|
---|
500 | i += size;
|
---|
501 | return buffer_item(self, i);
|
---|
502 | }
|
---|
503 | else if (PySlice_Check(item)) {
|
---|
504 | Py_ssize_t start, stop, step, slicelength, cur, i;
|
---|
505 |
|
---|
506 | if (PySlice_GetIndicesEx((PySliceObject*)item, size,
|
---|
507 | &start, &stop, &step, &slicelength) < 0) {
|
---|
508 | return NULL;
|
---|
509 | }
|
---|
510 |
|
---|
511 | if (slicelength <= 0)
|
---|
512 | return PyString_FromStringAndSize("", 0);
|
---|
513 | else if (step == 1)
|
---|
514 | return PyString_FromStringAndSize((char *)p + start,
|
---|
515 | stop - start);
|
---|
516 | else {
|
---|
517 | PyObject *result;
|
---|
518 | char *source_buf = (char *)p;
|
---|
519 | char *result_buf = (char *)PyMem_Malloc(slicelength);
|
---|
520 |
|
---|
521 | if (result_buf == NULL)
|
---|
522 | return PyErr_NoMemory();
|
---|
523 |
|
---|
524 | for (cur = start, i = 0; i < slicelength;
|
---|
525 | cur += step, i++) {
|
---|
526 | result_buf[i] = source_buf[cur];
|
---|
527 | }
|
---|
528 |
|
---|
529 | result = PyString_FromStringAndSize(result_buf,
|
---|
530 | slicelength);
|
---|
531 | PyMem_Free(result_buf);
|
---|
532 | return result;
|
---|
533 | }
|
---|
534 | }
|
---|
535 | else {
|
---|
536 | PyErr_SetString(PyExc_TypeError,
|
---|
537 | "sequence index must be integer");
|
---|
538 | return NULL;
|
---|
539 | }
|
---|
540 | }
|
---|
541 |
|
---|
542 | static int
|
---|
543 | buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
|
---|
544 | {
|
---|
545 | PyBufferProcs *pb;
|
---|
546 | void *ptr1, *ptr2;
|
---|
547 | Py_ssize_t size;
|
---|
548 | Py_ssize_t count;
|
---|
549 |
|
---|
550 | if ( self->b_readonly ) {
|
---|
551 | PyErr_SetString(PyExc_TypeError,
|
---|
552 | "buffer is read-only");
|
---|
553 | return -1;
|
---|
554 | }
|
---|
555 |
|
---|
556 | if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
---|
557 | return -1;
|
---|
558 |
|
---|
559 | if (idx < 0 || idx >= size) {
|
---|
560 | PyErr_SetString(PyExc_IndexError,
|
---|
561 | "buffer assignment index out of range");
|
---|
562 | return -1;
|
---|
563 | }
|
---|
564 |
|
---|
565 | pb = other ? other->ob_type->tp_as_buffer : NULL;
|
---|
566 | if ( pb == NULL ||
|
---|
567 | pb->bf_getreadbuffer == NULL ||
|
---|
568 | pb->bf_getsegcount == NULL )
|
---|
569 | {
|
---|
570 | PyErr_BadArgument();
|
---|
571 | return -1;
|
---|
572 | }
|
---|
573 | if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
---|
574 | {
|
---|
575 | /* ### use a different exception type/message? */
|
---|
576 | PyErr_SetString(PyExc_TypeError,
|
---|
577 | "single-segment buffer object expected");
|
---|
578 | return -1;
|
---|
579 | }
|
---|
580 |
|
---|
581 | if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
---|
582 | return -1;
|
---|
583 | if ( count != 1 ) {
|
---|
584 | PyErr_SetString(PyExc_TypeError,
|
---|
585 | "right operand must be a single byte");
|
---|
586 | return -1;
|
---|
587 | }
|
---|
588 |
|
---|
589 | ((char *)ptr1)[idx] = *(char *)ptr2;
|
---|
590 | return 0;
|
---|
591 | }
|
---|
592 |
|
---|
593 | static int
|
---|
594 | buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
|
---|
595 | {
|
---|
596 | PyBufferProcs *pb;
|
---|
597 | void *ptr1, *ptr2;
|
---|
598 | Py_ssize_t size;
|
---|
599 | Py_ssize_t slice_len;
|
---|
600 | Py_ssize_t count;
|
---|
601 |
|
---|
602 | if ( self->b_readonly ) {
|
---|
603 | PyErr_SetString(PyExc_TypeError,
|
---|
604 | "buffer is read-only");
|
---|
605 | return -1;
|
---|
606 | }
|
---|
607 |
|
---|
608 | pb = other ? other->ob_type->tp_as_buffer : NULL;
|
---|
609 | if ( pb == NULL ||
|
---|
610 | pb->bf_getreadbuffer == NULL ||
|
---|
611 | pb->bf_getsegcount == NULL )
|
---|
612 | {
|
---|
613 | PyErr_BadArgument();
|
---|
614 | return -1;
|
---|
615 | }
|
---|
616 | if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
---|
617 | {
|
---|
618 | /* ### use a different exception type/message? */
|
---|
619 | PyErr_SetString(PyExc_TypeError,
|
---|
620 | "single-segment buffer object expected");
|
---|
621 | return -1;
|
---|
622 | }
|
---|
623 | if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
---|
624 | return -1;
|
---|
625 | if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
---|
626 | return -1;
|
---|
627 |
|
---|
628 | if ( left < 0 )
|
---|
629 | left = 0;
|
---|
630 | else if ( left > size )
|
---|
631 | left = size;
|
---|
632 | if ( right < left )
|
---|
633 | right = left;
|
---|
634 | else if ( right > size )
|
---|
635 | right = size;
|
---|
636 | slice_len = right - left;
|
---|
637 |
|
---|
638 | if ( count != slice_len ) {
|
---|
639 | PyErr_SetString(
|
---|
640 | PyExc_TypeError,
|
---|
641 | "right operand length must match slice length");
|
---|
642 | return -1;
|
---|
643 | }
|
---|
644 |
|
---|
645 | if ( slice_len )
|
---|
646 | memcpy((char *)ptr1 + left, ptr2, slice_len);
|
---|
647 |
|
---|
648 | return 0;
|
---|
649 | }
|
---|
650 |
|
---|
651 | static int
|
---|
652 | buffer_ass_subscript(PyBufferObject *self, PyObject *item, PyObject *value)
|
---|
653 | {
|
---|
654 | PyBufferProcs *pb;
|
---|
655 | void *ptr1, *ptr2;
|
---|
656 | Py_ssize_t selfsize;
|
---|
657 | Py_ssize_t othersize;
|
---|
658 |
|
---|
659 | if ( self->b_readonly ) {
|
---|
660 | PyErr_SetString(PyExc_TypeError,
|
---|
661 | "buffer is read-only");
|
---|
662 | return -1;
|
---|
663 | }
|
---|
664 |
|
---|
665 | pb = value ? value->ob_type->tp_as_buffer : NULL;
|
---|
666 | if ( pb == NULL ||
|
---|
667 | pb->bf_getreadbuffer == NULL ||
|
---|
668 | pb->bf_getsegcount == NULL )
|
---|
669 | {
|
---|
670 | PyErr_BadArgument();
|
---|
671 | return -1;
|
---|
672 | }
|
---|
673 | if ( (*pb->bf_getsegcount)(value, NULL) != 1 )
|
---|
674 | {
|
---|
675 | /* ### use a different exception type/message? */
|
---|
676 | PyErr_SetString(PyExc_TypeError,
|
---|
677 | "single-segment buffer object expected");
|
---|
678 | return -1;
|
---|
679 | }
|
---|
680 | if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
|
---|
681 | return -1;
|
---|
682 | if (PyIndex_Check(item)) {
|
---|
683 | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
---|
684 | if (i == -1 && PyErr_Occurred())
|
---|
685 | return -1;
|
---|
686 | if (i < 0)
|
---|
687 | i += selfsize;
|
---|
688 | return buffer_ass_item(self, i, value);
|
---|
689 | }
|
---|
690 | else if (PySlice_Check(item)) {
|
---|
691 | Py_ssize_t start, stop, step, slicelength;
|
---|
692 |
|
---|
693 | if (PySlice_GetIndicesEx((PySliceObject *)item, selfsize,
|
---|
694 | &start, &stop, &step, &slicelength) < 0)
|
---|
695 | return -1;
|
---|
696 |
|
---|
697 | if ((othersize = (*pb->bf_getreadbuffer)(value, 0, &ptr2)) < 0)
|
---|
698 | return -1;
|
---|
699 |
|
---|
700 | if (othersize != slicelength) {
|
---|
701 | PyErr_SetString(
|
---|
702 | PyExc_TypeError,
|
---|
703 | "right operand length must match slice length");
|
---|
704 | return -1;
|
---|
705 | }
|
---|
706 |
|
---|
707 | if (slicelength == 0)
|
---|
708 | return 0;
|
---|
709 | else if (step == 1) {
|
---|
710 | memcpy((char *)ptr1 + start, ptr2, slicelength);
|
---|
711 | return 0;
|
---|
712 | }
|
---|
713 | else {
|
---|
714 | Py_ssize_t cur, i;
|
---|
715 |
|
---|
716 | for (cur = start, i = 0; i < slicelength;
|
---|
717 | cur += step, i++) {
|
---|
718 | ((char *)ptr1)[cur] = ((char *)ptr2)[i];
|
---|
719 | }
|
---|
720 |
|
---|
721 | return 0;
|
---|
722 | }
|
---|
723 | } else {
|
---|
724 | PyErr_SetString(PyExc_TypeError,
|
---|
725 | "buffer indices must be integers");
|
---|
726 | return -1;
|
---|
727 | }
|
---|
728 | }
|
---|
729 |
|
---|
730 | /* Buffer methods */
|
---|
731 |
|
---|
732 | static Py_ssize_t
|
---|
733 | buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
|
---|
734 | {
|
---|
735 | Py_ssize_t size;
|
---|
736 | if ( idx != 0 ) {
|
---|
737 | PyErr_SetString(PyExc_SystemError,
|
---|
738 | "accessing non-existent buffer segment");
|
---|
739 | return -1;
|
---|
740 | }
|
---|
741 | if (!get_buf(self, pp, &size, READ_BUFFER))
|
---|
742 | return -1;
|
---|
743 | return size;
|
---|
744 | }
|
---|
745 |
|
---|
746 | static Py_ssize_t
|
---|
747 | buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
|
---|
748 | {
|
---|
749 | Py_ssize_t size;
|
---|
750 |
|
---|
751 | if ( self->b_readonly )
|
---|
752 | {
|
---|
753 | PyErr_SetString(PyExc_TypeError, "buffer is read-only");
|
---|
754 | return -1;
|
---|
755 | }
|
---|
756 |
|
---|
757 | if ( idx != 0 ) {
|
---|
758 | PyErr_SetString(PyExc_SystemError,
|
---|
759 | "accessing non-existent buffer segment");
|
---|
760 | return -1;
|
---|
761 | }
|
---|
762 | if (!get_buf(self, pp, &size, WRITE_BUFFER))
|
---|
763 | return -1;
|
---|
764 | return size;
|
---|
765 | }
|
---|
766 |
|
---|
767 | static Py_ssize_t
|
---|
768 | buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
|
---|
769 | {
|
---|
770 | void *ptr;
|
---|
771 | Py_ssize_t size;
|
---|
772 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
773 | return -1;
|
---|
774 | if (lenp)
|
---|
775 | *lenp = size;
|
---|
776 | return 1;
|
---|
777 | }
|
---|
778 |
|
---|
779 | static Py_ssize_t
|
---|
780 | buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
|
---|
781 | {
|
---|
782 | void *ptr;
|
---|
783 | Py_ssize_t size;
|
---|
784 | if ( idx != 0 ) {
|
---|
785 | PyErr_SetString(PyExc_SystemError,
|
---|
786 | "accessing non-existent buffer segment");
|
---|
787 | return -1;
|
---|
788 | }
|
---|
789 | if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
|
---|
790 | return -1;
|
---|
791 | *pp = (const char *)ptr;
|
---|
792 | return size;
|
---|
793 | }
|
---|
794 |
|
---|
795 | static PySequenceMethods buffer_as_sequence = {
|
---|
796 | (lenfunc)buffer_length, /*sq_length*/
|
---|
797 | (binaryfunc)buffer_concat, /*sq_concat*/
|
---|
798 | (ssizeargfunc)buffer_repeat, /*sq_repeat*/
|
---|
799 | (ssizeargfunc)buffer_item, /*sq_item*/
|
---|
800 | (ssizessizeargfunc)buffer_slice, /*sq_slice*/
|
---|
801 | (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/
|
---|
802 | (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/
|
---|
803 | };
|
---|
804 |
|
---|
805 | static PyMappingMethods buffer_as_mapping = {
|
---|
806 | (lenfunc)buffer_length,
|
---|
807 | (binaryfunc)buffer_subscript,
|
---|
808 | (objobjargproc)buffer_ass_subscript,
|
---|
809 | };
|
---|
810 |
|
---|
811 | static PyBufferProcs buffer_as_buffer = {
|
---|
812 | (readbufferproc)buffer_getreadbuf,
|
---|
813 | (writebufferproc)buffer_getwritebuf,
|
---|
814 | (segcountproc)buffer_getsegcount,
|
---|
815 | (charbufferproc)buffer_getcharbuf,
|
---|
816 | };
|
---|
817 |
|
---|
818 | PyTypeObject PyBuffer_Type = {
|
---|
819 | PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
---|
820 | "buffer",
|
---|
821 | sizeof(PyBufferObject),
|
---|
822 | 0,
|
---|
823 | (destructor)buffer_dealloc, /* tp_dealloc */
|
---|
824 | 0, /* tp_print */
|
---|
825 | 0, /* tp_getattr */
|
---|
826 | 0, /* tp_setattr */
|
---|
827 | (cmpfunc)buffer_compare, /* tp_compare */
|
---|
828 | (reprfunc)buffer_repr, /* tp_repr */
|
---|
829 | 0, /* tp_as_number */
|
---|
830 | &buffer_as_sequence, /* tp_as_sequence */
|
---|
831 | &buffer_as_mapping, /* tp_as_mapping */
|
---|
832 | (hashfunc)buffer_hash, /* tp_hash */
|
---|
833 | 0, /* tp_call */
|
---|
834 | (reprfunc)buffer_str, /* tp_str */
|
---|
835 | PyObject_GenericGetAttr, /* tp_getattro */
|
---|
836 | 0, /* tp_setattro */
|
---|
837 | &buffer_as_buffer, /* tp_as_buffer */
|
---|
838 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */
|
---|
839 | buffer_doc, /* tp_doc */
|
---|
840 | 0, /* tp_traverse */
|
---|
841 | 0, /* tp_clear */
|
---|
842 | 0, /* tp_richcompare */
|
---|
843 | 0, /* tp_weaklistoffset */
|
---|
844 | 0, /* tp_iter */
|
---|
845 | 0, /* tp_iternext */
|
---|
846 | 0, /* tp_methods */
|
---|
847 | 0, /* tp_members */
|
---|
848 | 0, /* tp_getset */
|
---|
849 | 0, /* tp_base */
|
---|
850 | 0, /* tp_dict */
|
---|
851 | 0, /* tp_descr_get */
|
---|
852 | 0, /* tp_descr_set */
|
---|
853 | 0, /* tp_dictoffset */
|
---|
854 | 0, /* tp_init */
|
---|
855 | 0, /* tp_alloc */
|
---|
856 | buffer_new, /* tp_new */
|
---|
857 | };
|
---|