blob: 6adf8382a5c1f7f3aefe395373ed8d048511c054 [file] [log] [blame]
Guido van Rossum2e19bd71998-10-07 14:36:10 +00001
2/* Buffer object implementation */
3
4#include "Python.h"
5
6
7typedef struct {
8 PyObject_HEAD
9 PyObject *b_base;
10 void *b_ptr;
11 int b_size;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000012 int b_offset;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000013 int b_readonly;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000014 long b_hash;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000015} PyBufferObject;
16
17
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000018static int
19get_buf(PyBufferObject *self, void **ptr, int *size)
20{
21 if (self->b_base == NULL) {
22 assert (ptr != NULL);
23 *ptr = self->b_ptr;
24 *size = self->b_size;
25 }
26 else {
27 int count, offset;
28 getreadbufferproc proc;
29 PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
30 if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
31 PyErr_SetString(PyExc_TypeError,
32 "single-segment buffer object expected");
33 return 0;
34 }
35 if (self->b_readonly)
36 proc = bp->bf_getreadbuffer;
37 else
38 proc = (getreadbufferproc)bp->bf_getwritebuffer;
39 if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
40 return 0;
41 /* apply constraints to the start/end */
42 if (self->b_offset > count)
43 offset = count;
44 else
45 offset = self->b_offset;
Martin v. Löwis093c1002004-03-25 16:16:28 +000046 *(char **)ptr = *(char **)ptr + offset;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000047 if (self->b_size == Py_END_OF_BUFFER)
48 *size = count;
49 else
50 *size = self->b_size;
51 if (offset + *size > count)
52 *size = count - offset;
53 }
54 return 1;
55}
56
57
Guido van Rossum2e19bd71998-10-07 14:36:10 +000058static PyObject *
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000059buffer_from_memory(PyObject *base, int size, int offset, void *ptr,
60 int readonly)
Guido van Rossum2e19bd71998-10-07 14:36:10 +000061{
62 PyBufferObject * b;
63
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000064 if (size < 0 && size != Py_END_OF_BUFFER) {
Guido van Rossum49ded3e1999-03-19 19:04:25 +000065 PyErr_SetString(PyExc_ValueError,
66 "size must be zero or positive");
67 return NULL;
68 }
69
Guido van Rossum2e19bd71998-10-07 14:36:10 +000070 b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
71 if ( b == NULL )
72 return NULL;
73
74 Py_XINCREF(base);
75 b->b_base = base;
76 b->b_ptr = ptr;
77 b->b_size = size;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000078 b->b_offset = offset;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000079 b->b_readonly = readonly;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000080 b->b_hash = -1;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000081
82 return (PyObject *) b;
83}
84
85static PyObject *
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000086buffer_from_object(PyObject *base, int size, int offset, int readonly)
Guido van Rossum2e19bd71998-10-07 14:36:10 +000087{
Guido van Rossum49ded3e1999-03-19 19:04:25 +000088 if ( offset < 0 ) {
89 PyErr_SetString(PyExc_ValueError,
90 "offset must be zero or positive");
91 return NULL;
92 }
93
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000094 /* if the base object is another buffer, then try to refer to the
95 * base object.
Thomas Hellerfdc1bd32001-10-19 13:49:35 +000096 */
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000097 if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
Guido van Rossum2e19bd71998-10-07 14:36:10 +000098 base = ((PyBufferObject *)base)->b_base;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +000099 offset = ((PyBufferObject *)base)->b_offset + offset;
100 }
Thomas Hellerfdc1bd32001-10-19 13:49:35 +0000101
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000102 return buffer_from_memory(base, size, offset, NULL, readonly);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000103}
104
105
106PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000107PyBuffer_FromObject(PyObject *base, int offset, int size)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000108{
109 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
110
111 if ( pb == NULL ||
112 pb->bf_getreadbuffer == NULL ||
113 pb->bf_getsegcount == NULL )
114 {
115 PyErr_SetString(PyExc_TypeError, "buffer object expected");
116 return NULL;
117 }
118
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000119 return buffer_from_object(base, size, offset, 1);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000120}
121
122PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000123PyBuffer_FromReadWriteObject(PyObject *base, int offset, int size)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000124{
125 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
126
127 if ( pb == NULL ||
128 pb->bf_getwritebuffer == NULL ||
129 pb->bf_getsegcount == NULL )
130 {
131 PyErr_SetString(PyExc_TypeError, "buffer object expected");
132 return NULL;
133 }
134
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000135 return buffer_from_object(base, size, offset, 0);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000136}
137
138PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000139PyBuffer_FromMemory(void *ptr, int size)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000140{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000141 return buffer_from_memory(NULL, size, 0, ptr, 1);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000142}
143
144PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000145PyBuffer_FromReadWriteMemory(void *ptr, int size)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000146{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000147 return buffer_from_memory(NULL, size, 0, ptr, 0);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000148}
149
150PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000151PyBuffer_New(int size)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000152{
Moshe Zadkacf703f02000-08-04 15:36:13 +0000153 PyObject *o;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000154 PyBufferObject * b;
155
Fred Drake4574f231999-08-04 13:08:19 +0000156 if (size < 0) {
157 PyErr_SetString(PyExc_ValueError,
158 "size must be zero or positive");
159 return NULL;
160 }
Guido van Rossume3a8e7e2002-08-19 19:26:42 +0000161 /* Inline PyObject_New */
Moshe Zadkacf703f02000-08-04 15:36:13 +0000162 o = PyObject_MALLOC(sizeof(*b) + size);
163 if ( o == NULL )
Fred Drake4574f231999-08-04 13:08:19 +0000164 return PyErr_NoMemory();
Moshe Zadkacf703f02000-08-04 15:36:13 +0000165 b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000166
167 b->b_base = NULL;
168 b->b_ptr = (void *)(b + 1);
169 b->b_size = size;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000170 b->b_offset = 0;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000171 b->b_readonly = 0;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000172 b->b_hash = -1;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000173
Moshe Zadkacf703f02000-08-04 15:36:13 +0000174 return o;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000175}
176
177/* Methods */
178
Guido van Rossumbea18cc2002-06-14 20:41:17 +0000179static PyObject *
180buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
181{
182 PyObject *ob;
183 int offset = 0;
184 int size = Py_END_OF_BUFFER;
185
186 if ( !PyArg_ParseTuple(args, "O|ii:buffer", &ob, &offset, &size) )
187 return NULL;
188 return PyBuffer_FromObject(ob, offset, size);
189}
190
191PyDoc_STRVAR(buffer_doc,
192"buffer(object [, offset[, size]])\n\
193\n\
194Create a new buffer object which references the given object.\n\
195The buffer will reference a slice of the target object from the\n\
196start of the object (or at the specified offset). The slice will\n\
197extend to the end of the target object (or with the specified size).");
198
199
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000200static void
Fred Drake79912472000-07-09 04:06:11 +0000201buffer_dealloc(PyBufferObject *self)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000202{
203 Py_XDECREF(self->b_base);
Guido van Rossumb18618d2000-05-03 23:44:39 +0000204 PyObject_DEL(self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000205}
206
207static int
Fred Drake79912472000-07-09 04:06:11 +0000208buffer_compare(PyBufferObject *self, PyBufferObject *other)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000209{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000210 void *p1, *p2;
211 int len_self, len_other, min_len, cmp;
212
213 if (!get_buf(self, &p1, &len_self))
214 return -1;
215 if (!get_buf(other, &p2, &len_other))
216 return -1;
217 min_len = (len_self < len_other) ? len_self : len_other;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000218 if (min_len > 0) {
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000219 cmp = memcmp(p1, p2, min_len);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000220 if (cmp != 0)
221 return cmp;
222 }
223 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
224}
225
226static PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000227buffer_repr(PyBufferObject *self)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000228{
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000229 char *status = self->b_readonly ? "read-only" : "read-write";
230
231 if ( self->b_base == NULL )
Barry Warsaw7ce36942001-08-24 18:34:26 +0000232 return PyString_FromFormat("<%s buffer ptr %p, size %d at %p>",
233 status,
234 self->b_ptr,
235 self->b_size,
236 self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000237 else
Barry Warsaw7ce36942001-08-24 18:34:26 +0000238 return PyString_FromFormat(
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000239 "<%s buffer for %p, size %d, offset %d at %p>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000240 status,
Fred Drakea44d3532000-06-30 15:01:00 +0000241 self->b_base,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000242 self->b_size,
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000243 self->b_offset,
Fred Drakea44d3532000-06-30 15:01:00 +0000244 self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000245}
246
247static long
Fred Drake79912472000-07-09 04:06:11 +0000248buffer_hash(PyBufferObject *self)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000249{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000250 void *ptr;
251 int size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000252 register int len;
253 register unsigned char *p;
254 register long x;
255
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000256 if ( self->b_hash != -1 )
257 return self->b_hash;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000258
Neil Schemenauer0eadcd92004-03-11 01:00:44 +0000259 /* XXX potential bugs here, a readonly buffer does not imply that the
260 * underlying memory is immutable. b_readonly is a necessary but not
261 * sufficient condition for a buffer to be hashable. Perhaps it would
262 * be better to only allow hashing if the underlying object is known to
263 * be immutable (e.g. PyString_Check() is true). Another idea would
264 * be to call tp_hash on the underlying object and see if it raises
265 * an error. */
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000266 if ( !self->b_readonly )
267 {
Neil Schemenauer0eadcd92004-03-11 01:00:44 +0000268 PyErr_SetString(PyExc_TypeError,
269 "writable buffers are not hashable");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000270 return -1;
271 }
272
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000273 if (!get_buf(self, &ptr, &size))
274 return -1;
275 p = (unsigned char *) ptr;
276 len = size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000277 x = *p << 7;
278 while (--len >= 0)
279 x = (1000003*x) ^ *p++;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000280 x ^= size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000281 if (x == -1)
282 x = -2;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000283 self->b_hash = x;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000284 return x;
285}
286
287static PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000288buffer_str(PyBufferObject *self)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000289{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000290 void *ptr;
291 int size;
292 if (!get_buf(self, &ptr, &size))
293 return NULL;
294 return PyString_FromStringAndSize(ptr, size);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000295}
296
297/* Sequence methods */
298
299static int
Fred Drake79912472000-07-09 04:06:11 +0000300buffer_length(PyBufferObject *self)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000301{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000302 void *ptr;
303 int size;
304 if (!get_buf(self, &ptr, &size))
305 return -1;
306 return size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000307}
308
309static PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000310buffer_concat(PyBufferObject *self, PyObject *other)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000311{
312 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000313 void *ptr1, *ptr2;
314 char *p;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000315 PyObject *ob;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000316 int size, count;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000317
318 if ( pb == NULL ||
319 pb->bf_getreadbuffer == NULL ||
320 pb->bf_getsegcount == NULL )
321 {
322 PyErr_BadArgument();
323 return NULL;
324 }
325 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
326 {
327 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000328 PyErr_SetString(PyExc_TypeError,
329 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000330 return NULL;
331 }
332
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000333 if (!get_buf(self, &ptr1, &size))
334 return NULL;
335
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000336 /* optimize special case */
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000337 if ( size == 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000338 {
339 Py_INCREF(other);
340 return other;
341 }
342
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000343 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000344 return NULL;
345
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000346 ob = PyString_FromStringAndSize(NULL, size + count);
347 p = PyString_AS_STRING(ob);
348 memcpy(p, ptr1, size);
349 memcpy(p + size, ptr2, count);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000350
351 /* there is an extra byte in the string object, so this is safe */
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000352 p[size + count] = '\0';
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000353
354 return ob;
355}
356
357static PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000358buffer_repeat(PyBufferObject *self, int count)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000359{
360 PyObject *ob;
361 register char *p;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000362 void *ptr;
363 int size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000364
365 if ( count < 0 )
366 count = 0;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000367 if (!get_buf(self, &ptr, &size))
368 return NULL;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000369 ob = PyString_FromStringAndSize(NULL, size * count);
370 if ( ob == NULL )
371 return NULL;
372
373 p = PyString_AS_STRING(ob);
374 while ( count-- )
375 {
376 memcpy(p, ptr, size);
377 p += size;
378 }
379
380 /* there is an extra byte in the string object, so this is safe */
381 *p = '\0';
382
383 return ob;
384}
385
386static PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000387buffer_item(PyBufferObject *self, int idx)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000388{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000389 void *ptr;
390 int size;
391 if (!get_buf(self, &ptr, &size))
392 return NULL;
393 if ( idx < 0 || idx >= size ) {
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000394 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
395 return NULL;
396 }
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000397 return PyString_FromStringAndSize((char *)ptr + idx, 1);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000398}
399
400static PyObject *
Fred Drake79912472000-07-09 04:06:11 +0000401buffer_slice(PyBufferObject *self, int left, int right)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000402{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000403 void *ptr;
404 int size;
405 if (!get_buf(self, &ptr, &size))
406 return NULL;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000407 if ( left < 0 )
408 left = 0;
409 if ( right < 0 )
410 right = 0;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000411 if ( right > size )
412 right = size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000413 if ( right < left )
414 right = left;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000415 return PyString_FromStringAndSize((char *)ptr + left,
Guido van Rossumcd037e71999-03-24 19:05:31 +0000416 right - left);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000417}
418
419static int
Fred Drake79912472000-07-09 04:06:11 +0000420buffer_ass_item(PyBufferObject *self, int idx, PyObject *other)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000421{
422 PyBufferProcs *pb;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000423 void *ptr1, *ptr2;
424 int size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000425 int count;
426
427 if ( self->b_readonly ) {
428 PyErr_SetString(PyExc_TypeError,
429 "buffer is read-only");
430 return -1;
431 }
432
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000433 if (!get_buf(self, &ptr1, &size))
434 return -1;
435
436 if (idx < 0 || idx >= size) {
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000437 PyErr_SetString(PyExc_IndexError,
438 "buffer assignment index out of range");
439 return -1;
440 }
441
442 pb = other ? other->ob_type->tp_as_buffer : NULL;
443 if ( pb == NULL ||
444 pb->bf_getreadbuffer == NULL ||
445 pb->bf_getsegcount == NULL )
446 {
447 PyErr_BadArgument();
448 return -1;
449 }
450 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
451 {
452 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000453 PyErr_SetString(PyExc_TypeError,
454 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000455 return -1;
456 }
457
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000458 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000459 return -1;
460 if ( count != 1 ) {
461 PyErr_SetString(PyExc_TypeError,
462 "right operand must be a single byte");
463 return -1;
464 }
465
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000466 ((char *)ptr1)[idx] = *(char *)ptr2;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000467 return 0;
468}
469
470static int
Fred Drake79912472000-07-09 04:06:11 +0000471buffer_ass_slice(PyBufferObject *self, int left, int right, PyObject *other)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000472{
473 PyBufferProcs *pb;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000474 void *ptr1, *ptr2;
475 int size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000476 int slice_len;
477 int count;
478
479 if ( self->b_readonly ) {
480 PyErr_SetString(PyExc_TypeError,
481 "buffer is read-only");
482 return -1;
483 }
484
485 pb = other ? other->ob_type->tp_as_buffer : NULL;
486 if ( pb == NULL ||
487 pb->bf_getreadbuffer == NULL ||
488 pb->bf_getsegcount == NULL )
489 {
490 PyErr_BadArgument();
491 return -1;
492 }
493 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
494 {
495 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000496 PyErr_SetString(PyExc_TypeError,
497 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000498 return -1;
499 }
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000500 if (!get_buf(self, &ptr1, &size))
501 return -1;
502 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000503 return -1;
504
505 if ( left < 0 )
506 left = 0;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000507 else if ( left > size )
508 left = size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000509 if ( right < left )
510 right = left;
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000511 else if ( right > size )
512 right = size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000513 slice_len = right - left;
514
515 if ( count != slice_len ) {
Guido van Rossumcd037e71999-03-24 19:05:31 +0000516 PyErr_SetString(
517 PyExc_TypeError,
518 "right operand length must match slice length");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000519 return -1;
520 }
521
522 if ( slice_len )
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000523 memcpy((char *)ptr1 + left, ptr2, slice_len);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000524
525 return 0;
526}
527
528/* Buffer methods */
529
530static int
Fred Drake79912472000-07-09 04:06:11 +0000531buffer_getreadbuf(PyBufferObject *self, int idx, void **pp)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000532{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000533 int size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000534 if ( idx != 0 ) {
535 PyErr_SetString(PyExc_SystemError,
Guido van Rossum1db70701998-10-08 02:18:52 +0000536 "accessing non-existent buffer segment");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000537 return -1;
538 }
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000539 if (!get_buf(self, pp, &size))
540 return -1;
541 return size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000542}
543
544static int
Fred Drake79912472000-07-09 04:06:11 +0000545buffer_getwritebuf(PyBufferObject *self, int idx, void **pp)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000546{
547 if ( self->b_readonly )
548 {
549 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
550 return -1;
551 }
552 return buffer_getreadbuf(self, idx, pp);
553}
554
555static int
Fred Drake79912472000-07-09 04:06:11 +0000556buffer_getsegcount(PyBufferObject *self, int *lenp)
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000557{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000558 void *ptr;
559 int size;
560 if (!get_buf(self, &ptr, &size))
561 return -1;
562 if (lenp)
563 *lenp = size;
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000564 return 1;
565}
566
Guido van Rossum1db70701998-10-08 02:18:52 +0000567static int
Fred Drake79912472000-07-09 04:06:11 +0000568buffer_getcharbuf(PyBufferObject *self, int idx, const char **pp)
Guido van Rossum1db70701998-10-08 02:18:52 +0000569{
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000570 void *ptr;
571 int size;
Guido van Rossum1db70701998-10-08 02:18:52 +0000572 if ( idx != 0 ) {
573 PyErr_SetString(PyExc_SystemError,
574 "accessing non-existent buffer segment");
575 return -1;
576 }
Neil Schemenauer4252a7a2004-03-11 02:42:45 +0000577 if (!get_buf(self, &ptr, &size))
578 return -1;
579 *pp = (const char *)ptr;
580 return size;
Guido van Rossum1db70701998-10-08 02:18:52 +0000581}
582
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000583
584static PySequenceMethods buffer_as_sequence = {
585 (inquiry)buffer_length, /*sq_length*/
586 (binaryfunc)buffer_concat, /*sq_concat*/
587 (intargfunc)buffer_repeat, /*sq_repeat*/
588 (intargfunc)buffer_item, /*sq_item*/
589 (intintargfunc)buffer_slice, /*sq_slice*/
590 (intobjargproc)buffer_ass_item, /*sq_ass_item*/
591 (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
592};
593
594static PyBufferProcs buffer_as_buffer = {
595 (getreadbufferproc)buffer_getreadbuf,
596 (getwritebufferproc)buffer_getwritebuf,
597 (getsegcountproc)buffer_getsegcount,
Guido van Rossum1db70701998-10-08 02:18:52 +0000598 (getcharbufferproc)buffer_getcharbuf,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000599};
600
601PyTypeObject PyBuffer_Type = {
602 PyObject_HEAD_INIT(&PyType_Type)
603 0,
604 "buffer",
605 sizeof(PyBufferObject),
606 0,
Tim Peters6d6c1a32001-08-02 04:15:00 +0000607 (destructor)buffer_dealloc, /* tp_dealloc */
608 0, /* tp_print */
609 0, /* tp_getattr */
610 0, /* tp_setattr */
611 (cmpfunc)buffer_compare, /* tp_compare */
612 (reprfunc)buffer_repr, /* tp_repr */
613 0, /* tp_as_number */
614 &buffer_as_sequence, /* tp_as_sequence */
615 0, /* tp_as_mapping */
616 (hashfunc)buffer_hash, /* tp_hash */
617 0, /* tp_call */
618 (reprfunc)buffer_str, /* tp_str */
619 PyObject_GenericGetAttr, /* tp_getattro */
620 0, /* tp_setattro */
621 &buffer_as_buffer, /* tp_as_buffer */
622 Py_TPFLAGS_DEFAULT, /* tp_flags */
Guido van Rossumbea18cc2002-06-14 20:41:17 +0000623 buffer_doc, /* tp_doc */
624 0, /* tp_traverse */
625 0, /* tp_clear */
626 0, /* tp_richcompare */
627 0, /* tp_weaklistoffset */
628 0, /* tp_iter */
629 0, /* tp_iternext */
630 0, /* tp_methods */
631 0, /* tp_members */
632 0, /* tp_getset */
633 0, /* tp_base */
634 0, /* tp_dict */
635 0, /* tp_descr_get */
636 0, /* tp_descr_set */
637 0, /* tp_dictoffset */
638 0, /* tp_init */
639 0, /* tp_alloc */
640 buffer_new, /* tp_new */
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000641};