• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
get_buf(PyBufferObject * self,void ** ptr,Py_ssize_t * size,enum buffer_t buffer_type)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 = Py_TYPE(self->b_base)->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(Py_TYPE(self),
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 (*size > count - offset)
92             *size = count - offset;
93     }
94     return 1;
95 }
96 
97 
98 static PyObject *
buffer_from_memory(PyObject * base,Py_ssize_t size,Py_ssize_t offset,void * ptr,int readonly)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 *
buffer_from_object(PyObject * base,Py_ssize_t size,Py_ssize_t offset,int readonly)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 *
PyBuffer_FromObject(PyObject * base,Py_ssize_t offset,Py_ssize_t size)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 *
PyBuffer_FromReadWriteObject(PyObject * base,Py_ssize_t offset,Py_ssize_t size)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 *
PyBuffer_FromMemory(void * ptr,Py_ssize_t size)188 PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
189 {
190     return buffer_from_memory(NULL, size, 0, ptr, 1);
191 }
192 
193 PyObject *
PyBuffer_FromReadWriteMemory(void * ptr,Py_ssize_t size)194 PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
195 {
196     return buffer_from_memory(NULL, size, 0, ptr, 0);
197 }
198 
199 PyObject *
PyBuffer_New(Py_ssize_t size)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 *
buffer_new(PyTypeObject * type,PyObject * args,PyObject * kw)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
buffer_dealloc(PyBufferObject * self)260 buffer_dealloc(PyBufferObject *self)
261 {
262     Py_XDECREF(self->b_base);
263     PyObject_DEL(self);
264 }
265 
266 static int
buffer_compare(PyBufferObject * self,PyBufferObject * other)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 *
buffer_repr(PyBufferObject * self)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
buffer_hash(PyBufferObject * self)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     /*
338       We make the hash of the empty buffer be 0, rather than using
339       (prefix ^ suffix), since this slightly obfuscates the hash secret
340     */
341     if (len == 0) {
342         self->b_hash = 0;
343         return 0;
344     }
345     x = _Py_HashSecret.prefix;
346     x ^= *p << 7;
347     while (--len >= 0)
348         x = (1000003*x) ^ *p++;
349     x ^= size;
350     x ^= _Py_HashSecret.suffix;
351     if (x == -1)
352         x = -2;
353     self->b_hash = x;
354     return x;
355 }
356 
357 static PyObject *
buffer_str(PyBufferObject * self)358 buffer_str(PyBufferObject *self)
359 {
360     void *ptr;
361     Py_ssize_t size;
362     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
363         return NULL;
364     return PyString_FromStringAndSize((const char *)ptr, size);
365 }
366 
367 /* Sequence methods */
368 
369 static Py_ssize_t
buffer_length(PyBufferObject * self)370 buffer_length(PyBufferObject *self)
371 {
372     void *ptr;
373     Py_ssize_t size;
374     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
375         return -1;
376     return size;
377 }
378 
379 static PyObject *
buffer_concat(PyBufferObject * self,PyObject * other)380 buffer_concat(PyBufferObject *self, PyObject *other)
381 {
382     PyBufferProcs *pb = other->ob_type->tp_as_buffer;
383     void *ptr1, *ptr2;
384     char *p;
385     PyObject *ob;
386     Py_ssize_t size, count;
387 
388     if ( pb == NULL ||
389          pb->bf_getreadbuffer == NULL ||
390          pb->bf_getsegcount == NULL )
391     {
392         PyErr_BadArgument();
393         return NULL;
394     }
395     if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
396     {
397         /* ### use a different exception type/message? */
398         PyErr_SetString(PyExc_TypeError,
399                         "single-segment buffer object expected");
400         return NULL;
401     }
402 
403     if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
404         return NULL;
405 
406     /* optimize special case */
407     if ( size == 0 )
408     {
409         Py_INCREF(other);
410         return other;
411     }
412 
413     if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
414         return NULL;
415 
416     assert(count <= PY_SIZE_MAX - size);
417 
418     ob = PyString_FromStringAndSize(NULL, size + count);
419     if ( ob == NULL )
420         return NULL;
421     p = PyString_AS_STRING(ob);
422     memcpy(p, ptr1, size);
423     memcpy(p + size, ptr2, count);
424 
425     /* there is an extra byte in the string object, so this is safe */
426     p[size + count] = '\0';
427 
428     return ob;
429 }
430 
431 static PyObject *
buffer_repeat(PyBufferObject * self,Py_ssize_t count)432 buffer_repeat(PyBufferObject *self, Py_ssize_t count)
433 {
434     PyObject *ob;
435     register char *p;
436     void *ptr;
437     Py_ssize_t size;
438 
439     if ( count < 0 )
440         count = 0;
441     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
442         return NULL;
443     if (count > PY_SSIZE_T_MAX / size) {
444         PyErr_SetString(PyExc_MemoryError, "result too large");
445         return NULL;
446     }
447     ob = PyString_FromStringAndSize(NULL, size * count);
448     if ( ob == NULL )
449         return NULL;
450 
451     p = PyString_AS_STRING(ob);
452     while ( count-- )
453     {
454         memcpy(p, ptr, size);
455         p += size;
456     }
457 
458     /* there is an extra byte in the string object, so this is safe */
459     *p = '\0';
460 
461     return ob;
462 }
463 
464 static PyObject *
buffer_item_impl(void * ptr,Py_ssize_t size,Py_ssize_t idx)465 buffer_item_impl(void *ptr, Py_ssize_t size, Py_ssize_t idx)
466 {
467     if ( idx < 0 || idx >= size ) {
468         PyErr_SetString(PyExc_IndexError, "buffer index out of range");
469         return NULL;
470     }
471     return PyString_FromStringAndSize((char *)ptr + idx, 1);
472 }
473 
474 static PyObject *
buffer_item(PyBufferObject * self,Py_ssize_t idx)475 buffer_item(PyBufferObject *self, Py_ssize_t idx)
476 {
477     void *ptr;
478     Py_ssize_t size;
479     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
480         return NULL;
481     return buffer_item_impl(ptr, size, idx);
482 }
483 
484 static PyObject *
buffer_slice(PyBufferObject * self,Py_ssize_t left,Py_ssize_t right)485 buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
486 {
487     void *ptr;
488     Py_ssize_t size;
489     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
490         return NULL;
491     if ( left < 0 )
492         left = 0;
493     if ( right < 0 )
494         right = 0;
495     if ( right > size )
496         right = size;
497     if ( right < left )
498         right = left;
499     return PyString_FromStringAndSize((char *)ptr + left,
500                                       right - left);
501 }
502 
503 static PyObject *
buffer_subscript(PyBufferObject * self,PyObject * item)504 buffer_subscript(PyBufferObject *self, PyObject *item)
505 {
506     void *p;
507     Py_ssize_t size;
508 
509     if (PyIndex_Check(item)) {
510         Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
511         if (i == -1 && PyErr_Occurred())
512             return NULL;
513         if (!get_buf(self, &p, &size, ANY_BUFFER))
514             return NULL;
515 
516         if (i < 0) {
517             i += size;
518         }
519         return buffer_item_impl(p, size, i);
520     }
521     else if (PySlice_Check(item)) {
522         Py_ssize_t start, stop, step, slicelength, cur, i;
523 
524         if (_PySlice_Unpack(item, &start, &stop, &step) < 0)
525             return NULL;
526         if (!get_buf(self, &p, &size, ANY_BUFFER))
527             return NULL;
528 
529         slicelength = _PySlice_AdjustIndices(size, &start, &stop, step);
530         if (slicelength <= 0)
531             return PyString_FromStringAndSize("", 0);
532         else if (step == 1)
533             return PyString_FromStringAndSize((char *)p + start,
534                                               stop - start);
535         else {
536             PyObject *result;
537             char *source_buf = (char *)p;
538             char *result_buf = (char *)PyMem_Malloc(slicelength);
539 
540             if (result_buf == NULL)
541                 return PyErr_NoMemory();
542 
543             for (cur = start, i = 0; i < slicelength;
544                  cur += step, i++) {
545                 result_buf[i] = source_buf[cur];
546             }
547 
548             result = PyString_FromStringAndSize(result_buf,
549                                                 slicelength);
550             PyMem_Free(result_buf);
551             return result;
552         }
553     }
554     else {
555         PyErr_SetString(PyExc_TypeError,
556                         "sequence index must be integer");
557         return NULL;
558     }
559 }
560 
561 static int
buffer_ass_item_impl(void * ptr1,Py_ssize_t size,Py_ssize_t idx,PyObject * other)562 buffer_ass_item_impl(void *ptr1, Py_ssize_t size, Py_ssize_t idx, PyObject *other)
563 {
564     PyBufferProcs *pb;
565     void *ptr2;
566     Py_ssize_t count;
567 
568     if (idx < 0 || idx >= size) {
569         PyErr_SetString(PyExc_IndexError,
570                         "buffer assignment index out of range");
571         return -1;
572     }
573 
574     pb = other ? other->ob_type->tp_as_buffer : NULL;
575     if ( pb == NULL ||
576          pb->bf_getreadbuffer == NULL ||
577          pb->bf_getsegcount == NULL )
578     {
579         PyErr_BadArgument();
580         return -1;
581     }
582     if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
583     {
584         /* ### use a different exception type/message? */
585         PyErr_SetString(PyExc_TypeError,
586                         "single-segment buffer object expected");
587         return -1;
588     }
589 
590     if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
591         return -1;
592     if ( count != 1 ) {
593         PyErr_SetString(PyExc_TypeError,
594                         "right operand must be a single byte");
595         return -1;
596     }
597 
598     ((char *)ptr1)[idx] = *(char *)ptr2;
599     return 0;
600 }
601 
602 static int
buffer_ass_item(PyBufferObject * self,Py_ssize_t idx,PyObject * other)603 buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
604 {
605     void *ptr1;
606     Py_ssize_t size;
607 
608     if ( self->b_readonly ) {
609         PyErr_SetString(PyExc_TypeError,
610                         "buffer is read-only");
611         return -1;
612     }
613 
614     if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
615         return -1;
616     return buffer_ass_item_impl(ptr1, size, idx, other);
617 }
618 
619 static int
buffer_ass_slice(PyBufferObject * self,Py_ssize_t left,Py_ssize_t right,PyObject * other)620 buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
621 {
622     PyBufferProcs *pb;
623     void *ptr1, *ptr2;
624     Py_ssize_t size;
625     Py_ssize_t slice_len;
626     Py_ssize_t count;
627 
628     if ( self->b_readonly ) {
629         PyErr_SetString(PyExc_TypeError,
630                         "buffer is read-only");
631         return -1;
632     }
633 
634     pb = other ? other->ob_type->tp_as_buffer : NULL;
635     if ( pb == NULL ||
636          pb->bf_getreadbuffer == NULL ||
637          pb->bf_getsegcount == NULL )
638     {
639         PyErr_BadArgument();
640         return -1;
641     }
642     if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
643     {
644         /* ### use a different exception type/message? */
645         PyErr_SetString(PyExc_TypeError,
646                         "single-segment buffer object expected");
647         return -1;
648     }
649     if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
650         return -1;
651     if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
652         return -1;
653 
654     if ( left < 0 )
655         left = 0;
656     else if ( left > size )
657         left = size;
658     if ( right < left )
659         right = left;
660     else if ( right > size )
661         right = size;
662     slice_len = right - left;
663 
664     if ( count != slice_len ) {
665         PyErr_SetString(
666             PyExc_TypeError,
667             "right operand length must match slice length");
668         return -1;
669     }
670 
671     if ( slice_len )
672         memcpy((char *)ptr1 + left, ptr2, slice_len);
673 
674     return 0;
675 }
676 
677 static int
buffer_ass_subscript(PyBufferObject * self,PyObject * item,PyObject * value)678 buffer_ass_subscript(PyBufferObject *self, PyObject *item, PyObject *value)
679 {
680     PyBufferProcs *pb;
681     void *ptr1, *ptr2;
682     Py_ssize_t selfsize;
683     Py_ssize_t othersize;
684 
685     if ( self->b_readonly ) {
686         PyErr_SetString(PyExc_TypeError,
687                         "buffer is read-only");
688         return -1;
689     }
690 
691     pb = value ? value->ob_type->tp_as_buffer : NULL;
692     if ( pb == NULL ||
693          pb->bf_getreadbuffer == NULL ||
694          pb->bf_getsegcount == NULL )
695     {
696         PyErr_BadArgument();
697         return -1;
698     }
699     if ( (*pb->bf_getsegcount)(value, NULL) != 1 )
700     {
701         /* ### use a different exception type/message? */
702         PyErr_SetString(PyExc_TypeError,
703                         "single-segment buffer object expected");
704         return -1;
705     }
706     if (PyIndex_Check(item)) {
707         Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
708         if (i == -1 && PyErr_Occurred())
709             return -1;
710         if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
711             return -1;
712 
713         if (i < 0)
714             i += selfsize;
715         return buffer_ass_item_impl(ptr1, selfsize, i, value);
716     }
717     else if (PySlice_Check(item)) {
718         Py_ssize_t start, stop, step, slicelength;
719 
720         if (_PySlice_Unpack(item, &start, &stop, &step) < 0)
721             return -1;
722         if (!get_buf(self, &ptr1, &selfsize, ANY_BUFFER))
723             return -1;
724 
725         slicelength = _PySlice_AdjustIndices(selfsize, &start, &stop, step);
726         if ((othersize = (*pb->bf_getreadbuffer)(value, 0, &ptr2)) < 0)
727             return -1;
728 
729         if (othersize != slicelength) {
730             PyErr_SetString(
731                 PyExc_TypeError,
732                 "right operand length must match slice length");
733             return -1;
734         }
735 
736         if (slicelength == 0)
737             return 0;
738         else if (step == 1) {
739             memcpy((char *)ptr1 + start, ptr2, slicelength);
740             return 0;
741         }
742         else {
743             Py_ssize_t cur, i;
744 
745             for (cur = start, i = 0; i < slicelength;
746                  cur += step, i++) {
747                 ((char *)ptr1)[cur] = ((char *)ptr2)[i];
748             }
749 
750             return 0;
751         }
752     } else {
753         PyErr_SetString(PyExc_TypeError,
754                         "buffer indices must be integers");
755         return -1;
756     }
757 }
758 
759 /* Buffer methods */
760 
761 static Py_ssize_t
buffer_getreadbuf(PyBufferObject * self,Py_ssize_t idx,void ** pp)762 buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
763 {
764     Py_ssize_t size;
765     if ( idx != 0 ) {
766         PyErr_SetString(PyExc_SystemError,
767                         "accessing non-existent buffer segment");
768         return -1;
769     }
770     if (!get_buf(self, pp, &size, READ_BUFFER))
771         return -1;
772     return size;
773 }
774 
775 static Py_ssize_t
buffer_getwritebuf(PyBufferObject * self,Py_ssize_t idx,void ** pp)776 buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
777 {
778     Py_ssize_t size;
779 
780     if ( self->b_readonly )
781     {
782         PyErr_SetString(PyExc_TypeError, "buffer is read-only");
783         return -1;
784     }
785 
786     if ( idx != 0 ) {
787         PyErr_SetString(PyExc_SystemError,
788                         "accessing non-existent buffer segment");
789         return -1;
790     }
791     if (!get_buf(self, pp, &size, WRITE_BUFFER))
792         return -1;
793     return size;
794 }
795 
796 static Py_ssize_t
buffer_getsegcount(PyBufferObject * self,Py_ssize_t * lenp)797 buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
798 {
799     void *ptr;
800     Py_ssize_t size;
801     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
802         return -1;
803     if (lenp)
804         *lenp = size;
805     return 1;
806 }
807 
808 static Py_ssize_t
buffer_getcharbuf(PyBufferObject * self,Py_ssize_t idx,const char ** pp)809 buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
810 {
811     void *ptr;
812     Py_ssize_t size;
813     if ( idx != 0 ) {
814         PyErr_SetString(PyExc_SystemError,
815                         "accessing non-existent buffer segment");
816         return -1;
817     }
818     if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
819         return -1;
820     *pp = (const char *)ptr;
821     return size;
822 }
823 
buffer_getbuffer(PyBufferObject * self,Py_buffer * buf,int flags)824 static int buffer_getbuffer(PyBufferObject *self, Py_buffer *buf, int flags)
825 {
826     void *ptr;
827     Py_ssize_t size;
828     if (!get_buf(self, &ptr, &size, ANY_BUFFER))
829         return -1;
830     return PyBuffer_FillInfo(buf, (PyObject*)self, ptr, size,
831                              self->b_readonly, flags);
832 }
833 
834 static PySequenceMethods buffer_as_sequence = {
835     (lenfunc)buffer_length, /*sq_length*/
836     (binaryfunc)buffer_concat, /*sq_concat*/
837     (ssizeargfunc)buffer_repeat, /*sq_repeat*/
838     (ssizeargfunc)buffer_item, /*sq_item*/
839     (ssizessizeargfunc)buffer_slice, /*sq_slice*/
840     (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/
841     (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/
842 };
843 
844 static PyMappingMethods buffer_as_mapping = {
845     (lenfunc)buffer_length,
846     (binaryfunc)buffer_subscript,
847     (objobjargproc)buffer_ass_subscript,
848 };
849 
850 static PyBufferProcs buffer_as_buffer = {
851     (readbufferproc)buffer_getreadbuf,
852     (writebufferproc)buffer_getwritebuf,
853     (segcountproc)buffer_getsegcount,
854     (charbufferproc)buffer_getcharbuf,
855     (getbufferproc)buffer_getbuffer,
856 };
857 
858 PyTypeObject PyBuffer_Type = {
859     PyVarObject_HEAD_INIT(&PyType_Type, 0)
860     "buffer",
861     sizeof(PyBufferObject),
862     0,
863     (destructor)buffer_dealloc,                 /* tp_dealloc */
864     0,                                          /* tp_print */
865     0,                                          /* tp_getattr */
866     0,                                          /* tp_setattr */
867     (cmpfunc)buffer_compare,                    /* tp_compare */
868     (reprfunc)buffer_repr,                      /* tp_repr */
869     0,                                          /* tp_as_number */
870     &buffer_as_sequence,                        /* tp_as_sequence */
871     &buffer_as_mapping,                         /* tp_as_mapping */
872     (hashfunc)buffer_hash,                      /* tp_hash */
873     0,                                          /* tp_call */
874     (reprfunc)buffer_str,                       /* tp_str */
875     PyObject_GenericGetAttr,                    /* tp_getattro */
876     0,                                          /* tp_setattro */
877     &buffer_as_buffer,                          /* tp_as_buffer */
878     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER, /* tp_flags */
879     buffer_doc,                                 /* tp_doc */
880     0,                                          /* tp_traverse */
881     0,                                          /* tp_clear */
882     0,                                          /* tp_richcompare */
883     0,                                          /* tp_weaklistoffset */
884     0,                                          /* tp_iter */
885     0,                                          /* tp_iternext */
886     0,                                          /* tp_methods */
887     0,                                          /* tp_members */
888     0,                                          /* tp_getset */
889     0,                                          /* tp_base */
890     0,                                          /* tp_dict */
891     0,                                          /* tp_descr_get */
892     0,                                          /* tp_descr_set */
893     0,                                          /* tp_dictoffset */
894     0,                                          /* tp_init */
895     0,                                          /* tp_alloc */
896     buffer_new,                                 /* tp_new */
897 };
898