blob: 8f82cd01b8b2a8f46b0c655322f37099120dbe10 [file] [log] [blame]
Guido van Rossum2e19bd71998-10-07 14:36:10 +00001/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5 All Rights Reserved
6
Guido van Rossumfd71b9e2000-06-30 23:50:40 +00007Copyright (c) 2000, BeOpen.com.
8Copyright (c) 1995-2000, Corporation for National Research Initiatives.
9Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
10All rights reserved.
Guido van Rossum2e19bd71998-10-07 14:36:10 +000011
Guido van Rossumfd71b9e2000-06-30 23:50:40 +000012See the file "Misc/COPYRIGHT" for information on usage and
13redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
Guido van Rossum2e19bd71998-10-07 14:36:10 +000014
15******************************************************************/
16
17/* Buffer object implementation */
18
19#include "Python.h"
20
21
22typedef struct {
23 PyObject_HEAD
24 PyObject *b_base;
25 void *b_ptr;
26 int b_size;
27 int b_readonly;
28#ifdef CACHE_HASH
29 long b_hash;
30#endif
31} PyBufferObject;
32
33
34static PyObject *
35_PyBuffer_FromMemory(base, ptr, size, readonly)
36 PyObject *base;
37 void *ptr;
38 int size;
39 int readonly;
40{
41 PyBufferObject * b;
42
Guido van Rossum49ded3e1999-03-19 19:04:25 +000043 if ( size < 0 ) {
44 PyErr_SetString(PyExc_ValueError,
45 "size must be zero or positive");
46 return NULL;
47 }
48
Guido van Rossum2e19bd71998-10-07 14:36:10 +000049 b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
50 if ( b == NULL )
51 return NULL;
52
53 Py_XINCREF(base);
54 b->b_base = base;
55 b->b_ptr = ptr;
56 b->b_size = size;
57 b->b_readonly = readonly;
58#ifdef CACHE_HASH
59 b->b_hash = -1;
60#endif
61
62 return (PyObject *) b;
63}
64
65static PyObject *
66_PyBuffer_FromObject(base, offset, size, proc, readonly)
67 PyObject *base;
68 int offset;
69 int size;
70 getreadbufferproc proc;
71 int readonly;
72{
73 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
74 void *p;
75 int count;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000076
Guido van Rossum49ded3e1999-03-19 19:04:25 +000077 if ( offset < 0 ) {
78 PyErr_SetString(PyExc_ValueError,
79 "offset must be zero or positive");
80 return NULL;
81 }
82
Guido van Rossum2e19bd71998-10-07 14:36:10 +000083 if ( (*pb->bf_getsegcount)(base, NULL) != 1 )
84 {
Guido van Rossumcd037e71999-03-24 19:05:31 +000085 PyErr_SetString(PyExc_TypeError,
86 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +000087 return NULL;
88 }
89 if ( (count = (*proc)(base, 0, &p)) < 0 )
90 return NULL;
91
92 /* apply constraints to the start/end */
Guido van Rossum49ded3e1999-03-19 19:04:25 +000093 if ( size == Py_END_OF_BUFFER || size < 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +000094 size = count;
95 if ( offset > count )
96 offset = count;
97 if ( offset + size > count )
98 size = count - offset;
99
100 /* if the base object is another buffer, then "deref" it */
101 if ( PyBuffer_Check(base) )
102 base = ((PyBufferObject *)base)->b_base;
103
104 return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
105}
106
107
108PyObject *
109PyBuffer_FromObject(base, offset, size)
110 PyObject *base;
111 int offset;
112 int size;
113{
114 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
115
116 if ( pb == NULL ||
117 pb->bf_getreadbuffer == NULL ||
118 pb->bf_getsegcount == NULL )
119 {
120 PyErr_SetString(PyExc_TypeError, "buffer object expected");
121 return NULL;
122 }
123
Guido van Rossumcd037e71999-03-24 19:05:31 +0000124 return _PyBuffer_FromObject(base, offset, size,
125 pb->bf_getreadbuffer, 1);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000126}
127
128PyObject *
129PyBuffer_FromReadWriteObject(base, offset, size)
130 PyObject *base;
131 int offset;
132 int size;
133{
134 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
135
136 if ( pb == NULL ||
137 pb->bf_getwritebuffer == NULL ||
138 pb->bf_getsegcount == NULL )
139 {
140 PyErr_SetString(PyExc_TypeError, "buffer object expected");
141 return NULL;
142 }
143
Guido van Rossumcd037e71999-03-24 19:05:31 +0000144 return _PyBuffer_FromObject(base, offset, size,
145 (getreadbufferproc)pb->bf_getwritebuffer,
146 0);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000147}
148
149PyObject *
150PyBuffer_FromMemory(ptr, size)
151 void *ptr;
152 int size;
153{
154 return _PyBuffer_FromMemory(NULL, ptr, size, 1);
155}
156
157PyObject *
158PyBuffer_FromReadWriteMemory(ptr, size)
159 void *ptr;
160 int size;
161{
162 return _PyBuffer_FromMemory(NULL, ptr, size, 0);
163}
164
165PyObject *
166PyBuffer_New(size)
167 int size;
168{
169 PyBufferObject * b;
170
Fred Drake4574f231999-08-04 13:08:19 +0000171 if (size < 0) {
172 PyErr_SetString(PyExc_ValueError,
173 "size must be zero or positive");
174 return NULL;
175 }
Guido van Rossumb18618d2000-05-03 23:44:39 +0000176 /* PyObject_New is inlined */
177 b = (PyBufferObject *) PyObject_MALLOC(sizeof(*b) + size);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000178 if ( b == NULL )
Fred Drake4574f231999-08-04 13:08:19 +0000179 return PyErr_NoMemory();
Guido van Rossumb18618d2000-05-03 23:44:39 +0000180 PyObject_INIT((PyObject *)b, &PyBuffer_Type);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000181
182 b->b_base = NULL;
183 b->b_ptr = (void *)(b + 1);
184 b->b_size = size;
185 b->b_readonly = 0;
186#ifdef CACHE_HASH
187 b->b_hash = -1;
188#endif
189
190 return (PyObject *) b;
191}
192
193/* Methods */
194
195static void
196buffer_dealloc(self)
197 PyBufferObject *self;
198{
199 Py_XDECREF(self->b_base);
Guido van Rossumb18618d2000-05-03 23:44:39 +0000200 PyObject_DEL(self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000201}
202
203static int
204buffer_compare(self, other)
205 PyBufferObject *self;
206 PyBufferObject *other;
207{
208 int len_self = self->b_size;
209 int len_other = other->b_size;
210 int min_len = (len_self < len_other) ? len_self : len_other;
211 int cmp;
212 if (min_len > 0) {
213 cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
214 if (cmp != 0)
215 return cmp;
216 }
217 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
218}
219
220static PyObject *
221buffer_repr(self)
222 PyBufferObject *self;
223{
224 char buf[300];
225 char *status = self->b_readonly ? "read-only" : "read-write";
226
227 if ( self->b_base == NULL )
228 {
Fred Drakea44d3532000-06-30 15:01:00 +0000229 sprintf(buf, "<%s buffer ptr %p, size %d at %p>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000230 status,
Fred Drakea44d3532000-06-30 15:01:00 +0000231 self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000232 self->b_size,
Fred Drakea44d3532000-06-30 15:01:00 +0000233 self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000234 }
235 else
236 {
Fred Drakea44d3532000-06-30 15:01:00 +0000237 sprintf(buf, "<%s buffer for %p, ptr %p, size %d at %p>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000238 status,
Fred Drakea44d3532000-06-30 15:01:00 +0000239 self->b_base,
240 self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000241 self->b_size,
Fred Drakea44d3532000-06-30 15:01:00 +0000242 self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000243 }
244
245 return PyString_FromString(buf);
246}
247
248static long
249buffer_hash(self)
250 PyBufferObject *self;
251{
252 register int len;
253 register unsigned char *p;
254 register long x;
255
256#ifdef CACHE_HASH
257 if ( self->b_hash != -1 )
258 return self->b_hash;
259#endif
260
261 if ( !self->b_readonly )
262 {
263 /* ### use different wording, since this is conditional? */
264 PyErr_SetString(PyExc_TypeError, "unhashable type");
265 return -1;
266 }
267
268 len = self->b_size;
269 p = (unsigned char *) self->b_ptr;
270 x = *p << 7;
271 while (--len >= 0)
272 x = (1000003*x) ^ *p++;
273 x ^= self->b_size;
274 if (x == -1)
275 x = -2;
276#ifdef CACHE_HASH
277 self->b_hash = x;
278#endif
279 return x;
280}
281
282static PyObject *
283buffer_str(self)
284 PyBufferObject *self;
285{
286 return PyString_FromStringAndSize(self->b_ptr, self->b_size);
287}
288
289/* Sequence methods */
290
291static int
292buffer_length(self)
293 PyBufferObject *self;
294{
295 return self->b_size;
296}
297
298static PyObject *
299buffer_concat(self, other)
300 PyBufferObject *self;
301 PyObject *other;
302{
303 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
304 char *p1;
305 void *p2;
306 PyObject *ob;
307 int count;
308
309 if ( pb == NULL ||
310 pb->bf_getreadbuffer == NULL ||
311 pb->bf_getsegcount == NULL )
312 {
313 PyErr_BadArgument();
314 return NULL;
315 }
316 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
317 {
318 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000319 PyErr_SetString(PyExc_TypeError,
320 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000321 return NULL;
322 }
323
324 /* optimize special case */
325 if ( self->b_size == 0 )
326 {
327 Py_INCREF(other);
328 return other;
329 }
330
331 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
332 return NULL;
333
334 /* optimize special case */
335 if ( count == 0 )
336 {
337 Py_INCREF(self);
338 return (PyObject *)self;
339 }
340
341 ob = PyString_FromStringAndSize(NULL, self->b_size + count);
342 p1 = PyString_AS_STRING(ob);
343 memcpy(p1, self->b_ptr, self->b_size);
344 memcpy(p1 + self->b_size, p2, count);
345
346 /* there is an extra byte in the string object, so this is safe */
347 p1[self->b_size + count] = '\0';
348
349 return ob;
350}
351
352static PyObject *
353buffer_repeat(self, count)
354 PyBufferObject *self;
355 int count;
356{
357 PyObject *ob;
358 register char *p;
359 void *ptr = self->b_ptr;
360 int size = self->b_size;
361
362 if ( count < 0 )
363 count = 0;
364 ob = PyString_FromStringAndSize(NULL, size * count);
365 if ( ob == NULL )
366 return NULL;
367
368 p = PyString_AS_STRING(ob);
369 while ( count-- )
370 {
371 memcpy(p, ptr, size);
372 p += size;
373 }
374
375 /* there is an extra byte in the string object, so this is safe */
376 *p = '\0';
377
378 return ob;
379}
380
381static PyObject *
382buffer_item(self, idx)
383 PyBufferObject *self;
384 int idx;
385{
386 if ( idx < 0 || idx >= self->b_size )
387 {
388 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
389 return NULL;
390 }
391 return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
392}
393
394static PyObject *
395buffer_slice(self, left, right)
396 PyBufferObject *self;
397 int left;
398 int right;
399{
400 if ( left < 0 )
401 left = 0;
402 if ( right < 0 )
403 right = 0;
404 if ( right > self->b_size )
405 right = self->b_size;
406 if ( left == 0 && right == self->b_size )
407 {
408 /* same as self */
409 Py_INCREF(self);
410 return (PyObject *)self;
411 }
412 if ( right < left )
413 right = left;
Guido van Rossumcd037e71999-03-24 19:05:31 +0000414 return PyString_FromStringAndSize((char *)self->b_ptr + left,
415 right - left);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000416}
417
418static int
419buffer_ass_item(self, idx, other)
420 PyBufferObject *self;
421 int idx;
422 PyObject *other;
423{
424 PyBufferProcs *pb;
425 void *p;
426 int count;
427
428 if ( self->b_readonly ) {
429 PyErr_SetString(PyExc_TypeError,
430 "buffer is read-only");
431 return -1;
432 }
433
434 if (idx < 0 || idx >= self->b_size) {
435 PyErr_SetString(PyExc_IndexError,
436 "buffer assignment index out of range");
437 return -1;
438 }
439
440 pb = other ? other->ob_type->tp_as_buffer : NULL;
441 if ( pb == NULL ||
442 pb->bf_getreadbuffer == NULL ||
443 pb->bf_getsegcount == NULL )
444 {
445 PyErr_BadArgument();
446 return -1;
447 }
448 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
449 {
450 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000451 PyErr_SetString(PyExc_TypeError,
452 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000453 return -1;
454 }
455
456 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
457 return -1;
458 if ( count != 1 ) {
459 PyErr_SetString(PyExc_TypeError,
460 "right operand must be a single byte");
461 return -1;
462 }
463
464 ((char *)self->b_ptr)[idx] = *(char *)p;
465 return 0;
466}
467
468static int
469buffer_ass_slice(self, left, right, other)
470 PyBufferObject *self;
471 int left;
472 int right;
473 PyObject *other;
474{
475 PyBufferProcs *pb;
476 void *p;
477 int slice_len;
478 int count;
479
480 if ( self->b_readonly ) {
481 PyErr_SetString(PyExc_TypeError,
482 "buffer is read-only");
483 return -1;
484 }
485
486 pb = other ? other->ob_type->tp_as_buffer : NULL;
487 if ( pb == NULL ||
488 pb->bf_getreadbuffer == NULL ||
489 pb->bf_getsegcount == NULL )
490 {
491 PyErr_BadArgument();
492 return -1;
493 }
494 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
495 {
496 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000497 PyErr_SetString(PyExc_TypeError,
498 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000499 return -1;
500 }
501 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
502 return -1;
503
504 if ( left < 0 )
505 left = 0;
506 else if ( left > self->b_size )
507 left = self->b_size;
508 if ( right < left )
509 right = left;
510 else if ( right > self->b_size )
511 right = self->b_size;
512 slice_len = right - left;
513
514 if ( count != slice_len ) {
Guido van Rossumcd037e71999-03-24 19:05:31 +0000515 PyErr_SetString(
516 PyExc_TypeError,
517 "right operand length must match slice length");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000518 return -1;
519 }
520
521 if ( slice_len )
522 memcpy((char *)self->b_ptr + left, p, slice_len);
523
524 return 0;
525}
526
527/* Buffer methods */
528
529static int
530buffer_getreadbuf(self, idx, pp)
531 PyBufferObject *self;
532 int idx;
533 void ** pp;
534{
535 if ( idx != 0 ) {
536 PyErr_SetString(PyExc_SystemError,
Guido van Rossum1db70701998-10-08 02:18:52 +0000537 "accessing non-existent buffer segment");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000538 return -1;
539 }
540 *pp = self->b_ptr;
541 return self->b_size;
542}
543
544static int
545buffer_getwritebuf(self, idx, pp)
546 PyBufferObject *self;
547 int idx;
548 void ** pp;
549{
550 if ( self->b_readonly )
551 {
552 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
553 return -1;
554 }
555 return buffer_getreadbuf(self, idx, pp);
556}
557
558static int
559buffer_getsegcount(self, lenp)
560 PyBufferObject *self;
561 int *lenp;
562{
563 if ( lenp )
564 *lenp = self->b_size;
565 return 1;
566}
567
Guido van Rossum1db70701998-10-08 02:18:52 +0000568static int
569buffer_getcharbuf(self, idx, pp)
570 PyBufferObject *self;
571 int idx;
572 const char ** pp;
573{
574 if ( idx != 0 ) {
575 PyErr_SetString(PyExc_SystemError,
576 "accessing non-existent buffer segment");
577 return -1;
578 }
579 *pp = (const char *)self->b_ptr;
580 return self->b_size;
581}
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,
607 (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 0, /*tp_getattro*/
620 0, /*tp_setattro*/
621 &buffer_as_buffer, /*tp_as_buffer*/
Guido van Rossum1db70701998-10-08 02:18:52 +0000622 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000623 0, /*tp_doc*/
624};
625