LCOV - code coverage report
Current view: top level - Objects - bufferobject.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 0 397 0.0 %
Date: 2017-04-19 Functions: 0 28 0.0 %

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

Generated by: LCOV version 1.10