Index: bufferobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/bufferobject.c,v retrieving revision 2.17 diff -c -c -r2.17 bufferobject.c *** bufferobject.c 29 Mar 2002 03:29:07 -0000 2.17 --- bufferobject.c 5 May 2002 03:57:43 -0000 *************** *** 1,37 **** - /* Buffer object implementation */ #include "Python.h" - typedef struct { PyObject_HEAD ! PyObject *b_base; ! void *b_ptr; ! int b_size; int b_readonly; long b_hash; } PyBufferObject; static PyObject * ! _PyBuffer_FromMemory(PyObject *base, void *ptr, int size, int readonly) { PyBufferObject * b; ! if ( size < 0 ) { PyErr_SetString(PyExc_ValueError, "size must be zero or positive"); return NULL; } b = PyObject_NEW(PyBufferObject, &PyBuffer_Type); ! if ( b == NULL ) return NULL; Py_XINCREF(base); b->b_base = base; b->b_ptr = ptr; b->b_size = size; b->b_readonly = readonly; b->b_hash = -1; --- 1,50 ---- /* Buffer object implementation */ #include "Python.h" typedef struct { PyObject_HEAD ! PyObject *b_base; /* non-null iff created from object */ ! void *b_ptr; /* non-null iff created from memory */ ! int b_off; /* zero if created from memory */ ! int b_size; /* can be <0 if created from object */ int b_readonly; long b_hash; } PyBufferObject; static PyObject * ! _PyBuffer_FromMemory(PyObject *base, void *ptr, ! int offset, int size, int readonly) { PyBufferObject * b; ! /* one or the other, not both */ ! assert( ! ((ptr == NULL) && (base != NULL)) || ! ((ptr != NULL) && (base == NULL)) ! ); ! ! if ((ptr != NULL) && (size < 0)) { PyErr_SetString(PyExc_ValueError, "size must be zero or positive"); return NULL; } + if (offset < 0) { + PyErr_SetString(PyExc_ValueError, + "offset must be zero or positive"); + return NULL; + } + b = PyObject_NEW(PyBufferObject, &PyBuffer_Type); ! if (b == NULL) return NULL; Py_XINCREF(base); b->b_base = base; b->b_ptr = ptr; + b->b_off = offset; b->b_size = size; b->b_readonly = readonly; b->b_hash = -1; *************** *** 40,100 **** } static PyObject * ! _PyBuffer_FromObject(PyObject *base, int offset, int size, ! getreadbufferproc proc, int readonly) { ! PyBufferProcs *pb = base->ob_type->tp_as_buffer; void *p; int count; ! if ( offset < 0 ) { ! PyErr_SetString(PyExc_ValueError, ! "offset must be zero or positive"); ! return NULL; ! } ! if ( (*pb->bf_getsegcount)(base, NULL) != 1 ) ! { PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); ! return NULL; } - if ( (count = (*proc)(base, 0, &p)) < 0 ) - return NULL; /* apply constraints to the start/end */ ! if ( size == Py_END_OF_BUFFER || size < 0 ) ! size = count; ! if ( offset > count ) ! offset = count; ! if ( offset + size > count ) ! size = count - offset; ! ! /* if the base object is another buffer, then "deref" it, ! * except if the base of the other buffer is NULL ! */ ! if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) ! base = ((PyBufferObject *)base)->b_base; ! ! return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly); ! } PyObject * PyBuffer_FromObject(PyObject *base, int offset, int size) { PyBufferProcs *pb = base->ob_type->tp_as_buffer; ! if ( pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL ) ! { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return NULL; } ! return _PyBuffer_FromObject(base, offset, size, ! pb->bf_getreadbuffer, 1); } PyObject * --- 53,148 ---- } static PyObject * ! _PyBuffer_FromObject(PyObject *base, int offset, int size, int readonly) { ! /* if the base object is another buffer, then "deref" it, ! * except if the base of the other buffer is NULL ! */ ! if (PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base)) ! base = ((PyBufferObject *)base)->b_base; ! ! /* We have to defer all calculation of pointers/offsets/size ! * etc until they are actually used. The pointer returned ! * from PyBufferProcs is only valid while no operations change ! * it. (IOW, you have to hold the GIL the entire time you're ! * using it, and not invoke any code that might cause a realloc ! * in the base PyObject.) ! */ ! return _PyBuffer_FromMemory(base, NULL, offset, size, readonly); ! } ! ! /* Returns true on success, always sets an exception on failure */ ! static int ! _getptrandsize(PyBufferObject* self, void** ptr, int* size) ! { ! PyBufferProcs *pb; ! PyObject* base = self->b_base; ! int s = self->b_size; ! int off = self->b_off; void *p; int count; ! assert(base != NULL); ! assert(base->ob_type->tp_as_buffer != NULL); ! pb = base->ob_type->tp_as_buffer; ! ! /* XXX: If the number of segcounts is not allowed to change, then ! * this test could be pulled into PyBuffer_FromObject and ! * PyBuffer_FromReadWriteObject. ! */ ! assert(pb->bf_getsegcount != NULL); ! if ((*pb->bf_getsegcount)(base, NULL) != 1) { PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); ! return 0; ! } ! ! if ( self->b_readonly ) { ! assert(pb->bf_getreadbuffer != NULL); ! if ((count = pb->bf_getreadbuffer(base, 0, &p)) < 0) { ! if (!PyErr_Occurred()) ! PyErr_SetString(PyExc_TypeError, ! "unknown error getting read buffer"); ! return 0; ! } ! } else { ! assert(pb->bf_getwritebuffer != NULL); ! if ((count = pb->bf_getwritebuffer(base, 0, &p)) < 0) { ! if (!PyErr_Occurred()) ! PyErr_SetString(PyExc_TypeError, ! "unknown error getting write buffer"); ! return 0; ! } } /* apply constraints to the start/end */ ! if (s == Py_END_OF_BUFFER || s < 0) ! s = count; ! if (off > count) ! off = count; ! if (off + s > count) ! s = count - off; + *ptr = (void*)(off + (char*)p); + *size = s; + + return 1; + } PyObject * PyBuffer_FromObject(PyObject *base, int offset, int size) { PyBufferProcs *pb = base->ob_type->tp_as_buffer; ! if (pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return NULL; } ! return _PyBuffer_FromObject(base, offset, size, 1); } PyObject * *************** *** 102,130 **** { PyBufferProcs *pb = base->ob_type->tp_as_buffer; ! if ( pb == NULL || ! pb->bf_getwritebuffer == NULL || ! pb->bf_getsegcount == NULL ) ! { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return NULL; } ! return _PyBuffer_FromObject(base, offset, size, ! (getreadbufferproc)pb->bf_getwritebuffer, ! 0); } PyObject * PyBuffer_FromMemory(void *ptr, int size) { ! return _PyBuffer_FromMemory(NULL, ptr, size, 1); } PyObject * PyBuffer_FromReadWriteMemory(void *ptr, int size) { ! return _PyBuffer_FromMemory(NULL, ptr, size, 0); } PyObject * --- 150,175 ---- { PyBufferProcs *pb = base->ob_type->tp_as_buffer; ! if (pb == NULL || ! pb->bf_getwritebuffer == NULL || ! pb->bf_getsegcount == NULL) { PyErr_SetString(PyExc_TypeError, "buffer object expected"); return NULL; } ! return _PyBuffer_FromObject(base, offset, size, 0); } PyObject * PyBuffer_FromMemory(void *ptr, int size) { ! return _PyBuffer_FromMemory(NULL, ptr, 0, size, 1); } PyObject * PyBuffer_FromReadWriteMemory(void *ptr, int size) { ! return _PyBuffer_FromMemory(NULL, ptr, 0, size, 0); } PyObject * *************** *** 132,137 **** --- 177,188 ---- { PyObject *o; PyBufferObject * b; + /* pad to double alignment */ + int padding = sizeof(double) - sizeof(*b)%sizeof(double); + + /* don't need to pad a full double, only partials */ + if (padding == sizeof(double)) + padding = 0; if (size < 0) { PyErr_SetString(PyExc_ValueError, *************** *** 139,151 **** return NULL; } /* PyObject_New is inlined */ ! o = PyObject_MALLOC(sizeof(*b) + size); ! if ( o == NULL ) return PyErr_NoMemory(); b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type); b->b_base = NULL; ! b->b_ptr = (void *)(b + 1); b->b_size = size; b->b_readonly = 0; b->b_hash = -1; --- 190,204 ---- return NULL; } /* PyObject_New is inlined */ ! o = PyObject_MALLOC(sizeof(*b) + padding + size); ! if (o == NULL) return PyErr_NoMemory(); b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type); b->b_base = NULL; ! b->b_ptr = (void *)(sizeof(*b) + padding + (char*)b); ! assert(((long)b->b_ptr)%sizeof(double) == 0); ! b->b_off = 0; b->b_size = size; b->b_readonly = 0; b->b_hash = -1; *************** *** 167,176 **** { int len_self = self->b_size; int len_other = other->b_size; ! int min_len = (len_self < len_other) ? len_self : len_other; int cmp; if (min_len > 0) { ! cmp = memcmp(self->b_ptr, other->b_ptr, min_len); if (cmp != 0) return cmp; } --- 220,239 ---- { int len_self = self->b_size; int len_other = other->b_size; ! void* ptr_self = self->b_ptr; ! void* ptr_other = other->b_ptr; ! int min_len; int cmp; + + if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) + return -2; + + if (ptr_other == NULL && !_getptrandsize(other, &ptr_other, &len_other)) + return -2; + + min_len = (len_self < len_other) ? len_self : len_other; if (min_len > 0) { ! cmp = memcmp(ptr_self, ptr_other, min_len); if (cmp != 0) return cmp; } *************** *** 181,200 **** buffer_repr(PyBufferObject *self) { char *status = self->b_readonly ? "read-only" : "read-write"; ! if ( self->b_base == NULL ) return PyString_FromFormat("<%s buffer ptr %p, size %d at %p>", status, ! self->b_ptr, ! self->b_size, self); else return PyString_FromFormat( "<%s buffer for %p, ptr %p, size %d at %p>", status, self->b_base, ! self->b_ptr, ! self->b_size, self); } --- 244,268 ---- buffer_repr(PyBufferObject *self) { char *status = self->b_readonly ? "read-only" : "read-write"; + void *ptr_self = self->b_ptr; + int len_self = self->b_size; + + if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) + return NULL; ! if (self->b_base == NULL) return PyString_FromFormat("<%s buffer ptr %p, size %d at %p>", status, ! ptr_self, ! len_self, self); else return PyString_FromFormat( "<%s buffer for %p, ptr %p, size %d at %p>", status, self->b_base, ! ptr_self, ! len_self, self); } *************** *** 204,226 **** register int len; register unsigned char *p; register long x; ! if ( self->b_hash != -1 ) return self->b_hash; ! if ( !self->b_readonly ) ! { /* ### use different wording, since this is conditional? */ PyErr_SetString(PyExc_TypeError, "unhashable type"); return -1; } ! len = self->b_size; ! p = (unsigned char *) self->b_ptr; x = *p << 7; while (--len >= 0) x = (1000003*x) ^ *p++; ! x ^= self->b_size; if (x == -1) x = -2; self->b_hash = x; --- 272,312 ---- register int len; register unsigned char *p; register long x; + int len_self = self->b_size; + void* ptr_self = self->b_ptr; + + if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) + return -1; ! if (self->b_hash != -1) return self->b_hash; ! /* XXX This makes the incorrect assumption that readonly implies ! * const. Someone could easily create a read-only buffer object ! * from a pointer to memory that is read-write elsewhere. ! * ! * Since the hash of a readonly object is only calculated the first ! * time it is needed, it is easy to break the invariant: ! * ! * a == b => hash(a) == hash(b) ! * ! * I think the correct solution is for buffer objects not to ! * calculate their own hash values. ! */ ! ! if (!self->b_readonly) { /* ### use different wording, since this is conditional? */ PyErr_SetString(PyExc_TypeError, "unhashable type"); return -1; } ! len = len_self; ! p = (unsigned char *) ptr_self; ! x = *p << 7; while (--len >= 0) x = (1000003*x) ^ *p++; ! x ^= len_self; if (x == -1) x = -2; self->b_hash = x; *************** *** 230,236 **** static PyObject * buffer_str(PyBufferObject *self) { ! return PyString_FromStringAndSize(self->b_ptr, self->b_size); } /* Sequence methods */ --- 316,328 ---- static PyObject * buffer_str(PyBufferObject *self) { ! int len_self = self->b_size; ! void* ptr_self = self->b_ptr; ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return NULL; ! ! return PyString_FromStringAndSize(ptr_self, len_self); } /* Sequence methods */ *************** *** 238,244 **** static int buffer_length(PyBufferObject *self) { ! return self->b_size; } static PyObject * --- 330,342 ---- static int buffer_length(PyBufferObject *self) { ! int len_self = self->b_size; ! void* ptr_self = self->b_ptr; ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return -1; ! ! return len_self; } static PyObject * *************** *** 249,264 **** void *p2; PyObject *ob; int count; ! if ( pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL ) ! { PyErr_BadArgument(); return NULL; } ! if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) ! { /* ### use a different exception type/message? */ PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); --- 347,365 ---- void *p2; PyObject *ob; int count; + int len_self = self->b_size; + void* ptr_self = self->b_ptr; ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return NULL; ! ! if (pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL) { PyErr_BadArgument(); return NULL; } ! if ((*pb->bf_getsegcount)(other, NULL) != 1) { /* ### use a different exception type/message? */ PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); *************** *** 266,272 **** } /* optimize special case */ ! if ( self->b_size == 0 ) { Py_INCREF(other); return other; --- 367,373 ---- } /* optimize special case */ ! if (len_self == 0) { Py_INCREF(other); return other; *************** *** 276,294 **** return NULL; /* optimize special case */ ! if ( count == 0 ) ! { Py_INCREF(self); return (PyObject *)self; } ! ob = PyString_FromStringAndSize(NULL, self->b_size + count); p1 = PyString_AS_STRING(ob); ! memcpy(p1, self->b_ptr, self->b_size); ! memcpy(p1 + self->b_size, p2, count); /* there is an extra byte in the string object, so this is safe */ ! p1[self->b_size + count] = '\0'; return ob; } --- 377,394 ---- return NULL; /* optimize special case */ ! if (count == 0) { Py_INCREF(self); return (PyObject *)self; } ! ob = PyString_FromStringAndSize(NULL, len_self + count); p1 = PyString_AS_STRING(ob); ! memcpy(p1, ptr_self, len_self); ! memcpy(p1 + len_self, p2, count); /* there is an extra byte in the string object, so this is safe */ ! p1[len_self + count] = '\0'; return ob; } *************** *** 298,317 **** { PyObject *ob; register char *p; ! void *ptr = self->b_ptr; ! int size = self->b_size; ! if ( count < 0 ) count = 0; ! ob = PyString_FromStringAndSize(NULL, size * count); ! if ( ob == NULL ) return NULL; p = PyString_AS_STRING(ob); ! while ( count-- ) ! { ! memcpy(p, ptr, size); ! p += size; } /* there is an extra byte in the string object, so this is safe */ --- 398,419 ---- { PyObject *ob; register char *p; ! int len_self = self->b_size; ! void *ptr_self = self->b_ptr; ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return NULL; ! if (count < 0) count = 0; ! ob = PyString_FromStringAndSize(NULL, len_self * count); ! if (ob == NULL) return NULL; p = PyString_AS_STRING(ob); ! while (count--) { ! memcpy(p, ptr_self, len_self); ! p += len_self; } /* there is an extra byte in the string object, so this is safe */ *************** *** 323,354 **** static PyObject * buffer_item(PyBufferObject *self, int idx) { ! if ( idx < 0 || idx >= self->b_size ) ! { PyErr_SetString(PyExc_IndexError, "buffer index out of range"); return NULL; } ! return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1); } static PyObject * buffer_slice(PyBufferObject *self, int left, int right) { ! if ( left < 0 ) left = 0; ! if ( right < 0 ) right = 0; ! if ( right > self->b_size ) ! right = self->b_size; ! if ( left == 0 && right == self->b_size ) { /* same as self */ Py_INCREF(self); return (PyObject *)self; } ! if ( right < left ) right = left; ! return PyString_FromStringAndSize((char *)self->b_ptr + left, right - left); } --- 425,467 ---- static PyObject * buffer_item(PyBufferObject *self, int idx) { ! int len_self = self->b_size; ! void *ptr_self = self->b_ptr; ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return NULL; ! ! if (idx < 0 || idx >= len_self) { PyErr_SetString(PyExc_IndexError, "buffer index out of range"); return NULL; } ! return PyString_FromStringAndSize((char *)ptr_self + idx, 1); } static PyObject * buffer_slice(PyBufferObject *self, int left, int right) { ! int len_self = self->b_size; ! void *ptr_self = self->b_ptr; ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return NULL; ! ! if (left < 0) left = 0; ! if (right < 0) right = 0; ! if (right > len_self) ! right = len_self; ! if (left == 0 && right == len_self) { /* same as self */ Py_INCREF(self); return (PyObject *)self; } ! if (right < left) right = left; ! return PyString_FromStringAndSize((char *)ptr_self + left, right - left); } *************** *** 358,401 **** PyBufferProcs *pb; void *p; int count; ! if ( self->b_readonly ) { PyErr_SetString(PyExc_TypeError, "buffer is read-only"); return -1; } ! if (idx < 0 || idx >= self->b_size) { PyErr_SetString(PyExc_IndexError, "buffer assignment index out of range"); return -1; } pb = other ? other->ob_type->tp_as_buffer : NULL; ! if ( pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL ) ! { PyErr_BadArgument(); return -1; } ! if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) ! { /* ### use a different exception type/message? */ PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); return -1; } ! if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 ) return -1; ! if ( count != 1 ) { PyErr_SetString(PyExc_TypeError, "right operand must be a single byte"); return -1; } ! ((char *)self->b_ptr)[idx] = *(char *)p; return 0; } --- 471,517 ---- PyBufferProcs *pb; void *p; int count; + int len_self = self->b_size; + void *ptr_self = self->b_ptr; ! if (self->b_readonly) { PyErr_SetString(PyExc_TypeError, "buffer is read-only"); return -1; } ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return -1; ! ! if (idx < 0 || idx >= len_self) { PyErr_SetString(PyExc_IndexError, "buffer assignment index out of range"); return -1; } pb = other ? other->ob_type->tp_as_buffer : NULL; ! if (pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL ) { PyErr_BadArgument(); return -1; } ! if ((*pb->bf_getsegcount)(other, NULL) != 1) { /* ### use a different exception type/message? */ PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); return -1; } ! if ((count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0) return -1; ! if (count != 1) { PyErr_SetString(PyExc_TypeError, "right operand must be a single byte"); return -1; } ! ((char *)ptr_self)[idx] = *(char *)p; return 0; } *************** *** 406,455 **** void *p; int slice_len; int count; ! if ( self->b_readonly ) { PyErr_SetString(PyExc_TypeError, "buffer is read-only"); return -1; } pb = other ? other->ob_type->tp_as_buffer : NULL; ! if ( pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL ) ! { PyErr_BadArgument(); return -1; } ! if ( (*pb->bf_getsegcount)(other, NULL) != 1 ) ! { /* ### use a different exception type/message? */ PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); return -1; } ! if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 ) return -1; ! if ( left < 0 ) left = 0; ! else if ( left > self->b_size ) ! left = self->b_size; ! if ( right < left ) right = left; ! else if ( right > self->b_size ) ! right = self->b_size; slice_len = right - left; ! if ( count != slice_len ) { PyErr_SetString( PyExc_TypeError, "right operand length must match slice length"); return -1; } ! if ( slice_len ) ! memcpy((char *)self->b_ptr + left, p, slice_len); return 0; } --- 522,574 ---- void *p; int slice_len; int count; + int len_self = self->b_size; + void *ptr_self = self->b_ptr; ! if (self->b_readonly) { PyErr_SetString(PyExc_TypeError, "buffer is read-only"); return -1; } + if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) + return -1; + pb = other ? other->ob_type->tp_as_buffer : NULL; ! if (pb == NULL || ! pb->bf_getreadbuffer == NULL || ! pb->bf_getsegcount == NULL) { PyErr_BadArgument(); return -1; } ! if ((*pb->bf_getsegcount)(other, NULL) != 1) { /* ### use a different exception type/message? */ PyErr_SetString(PyExc_TypeError, "single-segment buffer object expected"); return -1; } ! if ((count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0) return -1; ! if (left < 0) left = 0; ! else if ( left > len_self ) ! left = len_self; ! if (right < left) right = left; ! else if ( right > len_self ) ! right = len_self; slice_len = right - left; ! if (count != slice_len) { PyErr_SetString( PyExc_TypeError, "right operand length must match slice length"); return -1; } ! if (slice_len) ! memcpy((char *)ptr_self + left, p, slice_len); return 0; } *************** *** 459,478 **** static int buffer_getreadbuf(PyBufferObject *self, int idx, void **pp) { ! if ( idx != 0 ) { PyErr_SetString(PyExc_SystemError, "accessing non-existent buffer segment"); return -1; } ! *pp = self->b_ptr; ! return self->b_size; } static int buffer_getwritebuf(PyBufferObject *self, int idx, void **pp) { ! if ( self->b_readonly ) ! { PyErr_SetString(PyExc_TypeError, "buffer is read-only"); return -1; } --- 578,603 ---- static int buffer_getreadbuf(PyBufferObject *self, int idx, void **pp) { ! int len_self = self->b_size; ! void *ptr_self = self->b_ptr; ! ! if (idx != 0) { PyErr_SetString(PyExc_SystemError, "accessing non-existent buffer segment"); return -1; } ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return -1; ! ! *pp = ptr_self; ! return len_self; } static int buffer_getwritebuf(PyBufferObject *self, int idx, void **pp) { ! if (self->b_readonly) { PyErr_SetString(PyExc_TypeError, "buffer is read-only"); return -1; } *************** *** 482,502 **** static int buffer_getsegcount(PyBufferObject *self, int *lenp) { ! if ( lenp ) ! *lenp = self->b_size; return 1; } static int buffer_getcharbuf(PyBufferObject *self, int idx, const char **pp) { ! if ( idx != 0 ) { PyErr_SetString(PyExc_SystemError, "accessing non-existent buffer segment"); return -1; } ! *pp = (const char *)self->b_ptr; ! return self->b_size; } --- 607,648 ---- static int buffer_getsegcount(PyBufferObject *self, int *lenp) { ! int len_self = self->b_size; ! void *ptr_self = self->b_ptr; ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) { ! /* The docs say this function is not allowed to fail, so ! * returning 0 seems like the best choice here. */ ! if (PyErr_Occurred()) ! PyErr_Clear(); ! ! if ( lenp ) ! *lenp = 0; ! return 0; ! } ! ! if (lenp != NULL) ! *lenp = len_self; return 1; } static int buffer_getcharbuf(PyBufferObject *self, int idx, const char **pp) { ! int len_self = self->b_size; ! void *ptr_self = self->b_ptr; ! ! if (idx != 0) { PyErr_SetString(PyExc_SystemError, "accessing non-existent buffer segment"); return -1; } ! ! if (ptr_self == NULL && !_getptrandsize(self, &ptr_self, &len_self)) ! return -1; ! ! *pp = (const char *)ptr_self; ! return len_self; } *************** *** 523,543 **** "buffer", sizeof(PyBufferObject), 0, ! (destructor)buffer_dealloc, /* tp_dealloc */ ! 0, /* tp_print */ ! 0, /* tp_getattr */ ! 0, /* tp_setattr */ ! (cmpfunc)buffer_compare, /* tp_compare */ ! (reprfunc)buffer_repr, /* tp_repr */ ! 0, /* tp_as_number */ ! &buffer_as_sequence, /* tp_as_sequence */ ! 0, /* tp_as_mapping */ ! (hashfunc)buffer_hash, /* tp_hash */ ! 0, /* tp_call */ ! (reprfunc)buffer_str, /* tp_str */ ! PyObject_GenericGetAttr, /* tp_getattro */ ! 0, /* tp_setattro */ ! &buffer_as_buffer, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /* tp_flags */ ! 0, /* tp_doc */ }; --- 669,689 ---- "buffer", sizeof(PyBufferObject), 0, ! (destructor)buffer_dealloc, /* tp_dealloc */ ! 0, /* tp_print */ ! 0, /* tp_getattr */ ! 0, /* tp_setattr */ ! (cmpfunc)buffer_compare, /* tp_compare */ ! (reprfunc)buffer_repr, /* tp_repr */ ! 0, /* tp_as_number */ ! &buffer_as_sequence, /* tp_as_sequence */ ! 0, /* tp_as_mapping */ ! (hashfunc)buffer_hash, /* tp_hash */ ! 0, /* tp_call */ ! (reprfunc)buffer_str, /* tp_str */ ! PyObject_GenericGetAttr, /* tp_getattro */ ! 0, /* tp_setattro */ ! &buffer_as_buffer, /* tp_as_buffer */ ! Py_TPFLAGS_DEFAULT, /* tp_flags */ ! 0, /* tp_doc */ };