Home | History | Annotate | Download | only in Objects
      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 };
    858