• 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 = 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 *
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     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 *
buffer_str(PyBufferObject * self)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
buffer_length(PyBufferObject * self)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 *
buffer_concat(PyBufferObject * self,PyObject * other)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 *
buffer_repeat(PyBufferObject * self,Py_ssize_t count)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 *
buffer_item(PyBufferObject * self,Py_ssize_t idx)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 *
buffer_slice(PyBufferObject * self,Py_ssize_t left,Py_ssize_t right)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 *
buffer_subscript(PyBufferObject * self,PyObject * item)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
buffer_ass_item(PyBufferObject * self,Py_ssize_t idx,PyObject * other)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
buffer_ass_slice(PyBufferObject * self,Py_ssize_t left,Py_ssize_t right,PyObject * other)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
buffer_ass_subscript(PyBufferObject * self,PyObject * item,PyObject * value)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
buffer_getreadbuf(PyBufferObject * self,Py_ssize_t idx,void ** pp)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
buffer_getwritebuf(PyBufferObject * self,Py_ssize_t idx,void ** pp)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
buffer_getsegcount(PyBufferObject * self,Py_ssize_t * lenp)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
buffer_getcharbuf(PyBufferObject * self,Py_ssize_t idx,const char ** pp)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 };
858