home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
- The Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI or Corporation for National Research Initiatives or
- CNRI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior
- permission.
-
- While CWI is the initial source for this software, a modified version
- is made available by the Corporation for National Research Initiatives
- (CNRI) at the Internet address ftp://ftp.python.org.
-
- STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
- CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /* Buffer object implementation */
-
- #include "Python.h"
-
- typedef struct {
- PyObject_HEAD
- PyObject *b_base;
- void *b_ptr;
- int b_size;
- int b_readonly;
- #ifdef CACHE_HASH
- long b_hash;
- #endif
- } PyBufferObject;
-
- #include "protos/bufferobject.h"
-
- static PyObject *
- _PyBuffer_FromMemory(base, ptr, size, readonly)
- 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;
- #ifdef CACHE_HASH
- b->b_hash = -1;
- #endif
-
- return (PyObject *) b;
- }
-
- static PyObject *
- _PyBuffer_FromObject(base, offset, size, proc, readonly)
- 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 */
- if ( PyBuffer_Check(base) )
- base = ((PyBufferObject *)base)->b_base;
-
- return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
- }
-
-
- PyObject *
- PyBuffer_FromObject(base, offset, size)
- 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 *
- PyBuffer_FromReadWriteObject(base, offset, size)
- PyObject *base;
- int offset;
- int size;
- {
- 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(ptr, size)
- void *ptr;
- int size;
- {
- return _PyBuffer_FromMemory(NULL, ptr, size, 1);
- }
-
- PyObject *
- PyBuffer_FromReadWriteMemory(ptr, size)
- void *ptr;
- int size;
- {
- return _PyBuffer_FromMemory(NULL, ptr, size, 0);
- }
-
- PyObject *
- PyBuffer_New(size)
- int size;
- {
- PyBufferObject * b;
-
- b = (PyBufferObject *)malloc(sizeof(*b) + size);
- if ( b == NULL )
- return NULL;
- b->ob_type = &PyBuffer_Type;
- _Py_NewReference((PyObject *)b);
-
- b->b_base = NULL;
- b->b_ptr = (void *)(b + 1);
- b->b_size = size;
- b->b_readonly = 0;
- #ifdef CACHE_HASH
- b->b_hash = -1;
- #endif
-
- return (PyObject *) b;
- }
-
- /* Methods */
-
- static void
- buffer_dealloc(self)
- PyBufferObject *self;
- {
- Py_XDECREF(self->b_base);
- free((void *)self);
- }
-
- static int
- buffer_compare(self, other)
- PyBufferObject *self;
- PyBufferObject *other;
- {
- 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;
- }
- return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
- }
-
- static PyObject *
- buffer_repr(self)
- PyBufferObject *self;
- {
- char buf[300];
- char *status = self->b_readonly ? "read-only" : "read-write";
-
- if ( self->b_base == NULL )
- {
- sprintf(buf, "<%s buffer ptr %lx, size %d at %lx>",
- status,
- (long)self->b_ptr,
- self->b_size,
- (long)self);
- }
- else
- {
- sprintf(buf, "<%s buffer for %lx, ptr %lx, size %d at %lx>",
- status,
- (long)self->b_base,
- (long)self->b_ptr,
- self->b_size,
- (long)self);
- }
-
- return PyString_FromString(buf);
- }
-
- static long
- buffer_hash(self)
- PyBufferObject *self;
- {
- register int len;
- register unsigned char *p;
- register long x;
-
- #ifdef CACHE_HASH
- if ( self->b_hash != -1 )
- return self->b_hash;
- #endif
-
- 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;
- #ifdef CACHE_HASH
- self->b_hash = x;
- #endif
- return x;
- }
-
- static PyObject *
- buffer_str(self)
- PyBufferObject *self;
- {
- return PyString_FromStringAndSize(self->b_ptr, self->b_size);
- }
-
- /* Sequence methods */
-
- static int
- buffer_length(self)
- PyBufferObject *self;
- {
- return self->b_size;
- }
-
- static PyObject *
- buffer_concat(self, other)
- PyBufferObject *self;
- PyObject *other;
- {
- PyBufferProcs *pb = other->ob_type->tp_as_buffer;
- char *p1;
- 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");
- return NULL;
- }
-
- /* optimize special case */
- if ( self->b_size == 0 )
- {
- Py_INCREF(other);
- return other;
- }
-
- if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
- 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;
- }
-
- static PyObject *
- buffer_repeat(self, count)
- PyBufferObject *self;
- int count;
- {
- 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 */
- *p = '\0';
-
- return ob;
- }
-
- static PyObject *
- buffer_item(self, idx)
- 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(self, left, right)
- 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);
- }
-
- static int
- buffer_ass_item(self, idx, other)
- PyBufferObject *self;
- int idx;
- PyObject *other;
- {
- 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;
- }
-
- static int
- buffer_ass_slice(self, left, right, other)
- PyBufferObject *self;
- int left;
- int right;
- PyObject *other;
- {
- PyBufferProcs *pb;
- 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;
- }
-
- /* Buffer methods */
-
- static int
- buffer_getreadbuf(self, idx, pp)
- 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(self, idx, pp)
- PyBufferObject *self;
- int idx;
- void ** pp;
- {
- if ( self->b_readonly )
- {
- PyErr_SetString(PyExc_TypeError, "buffer is read-only");
- return -1;
- }
- return buffer_getreadbuf(self, idx, pp);
- }
-
- static int
- buffer_getsegcount(self, lenp)
- PyBufferObject *self;
- int *lenp;
- {
- if ( lenp )
- *lenp = self->b_size;
- return 1;
- }
-
- static int
- buffer_getcharbuf(self, idx, pp)
- 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;
- }
-
-
- static PySequenceMethods buffer_as_sequence = {
- (inquiry)buffer_length, /*sq_length*/
- (binaryfunc)buffer_concat, /*sq_concat*/
- (intargfunc)buffer_repeat, /*sq_repeat*/
- (intargfunc)buffer_item, /*sq_item*/
- (intintargfunc)buffer_slice, /*sq_slice*/
- (intobjargproc)buffer_ass_item, /*sq_ass_item*/
- (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
- };
-
- static PyBufferProcs buffer_as_buffer = {
- (getreadbufferproc)buffer_getreadbuf,
- (getwritebufferproc)buffer_getwritebuf,
- (getsegcountproc)buffer_getsegcount,
- (getcharbufferproc)buffer_getcharbuf,
- };
-
- PyTypeObject PyBuffer_Type = {
- PyObject_HEAD_INIT(&PyType_Type)
- 0,
- "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*/
- 0, /*tp_getattro*/
- 0, /*tp_setattro*/
- &buffer_as_buffer, /*tp_as_buffer*/
- Py_TPFLAGS_DEFAULT, /*tp_flags*/
- 0, /*tp_doc*/
- };
-
-