source: vendor/python/2.5/Objects/bufferobject.c

Last change on this file was 3225, checked in by bird, 18 years ago

Python 2.5

File size: 15.5 KB
Line 
1
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 Py_ssize_t b_size;
12 Py_ssize_t b_offset;
13 int b_readonly;
14 long b_hash;
15} PyBufferObject;
16
17
18enum buffer_t {
19 READ_BUFFER,
20 WRITE_BUFFER,
21 CHAR_BUFFER,
22 ANY_BUFFER,
23};
24
25static int
26get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
27 enum buffer_t buffer_type)
28{
29 if (self->b_base == NULL) {
30 assert (ptr != NULL);
31 *ptr = self->b_ptr;
32 *size = self->b_size;
33 }
34 else {
35 Py_ssize_t count, offset;
36 readbufferproc proc = 0;
37 PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
38 if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
39 PyErr_SetString(PyExc_TypeError,
40 "single-segment buffer object expected");
41 return 0;
42 }
43 if ((buffer_type == READ_BUFFER) ||
44 ((buffer_type == ANY_BUFFER) && self->b_readonly))
45 proc = bp->bf_getreadbuffer;
46 else if ((buffer_type == WRITE_BUFFER) ||
47 (buffer_type == ANY_BUFFER))
48 proc = (readbufferproc)bp->bf_getwritebuffer;
49 else if (buffer_type == CHAR_BUFFER) {
50 if (!PyType_HasFeature(self->ob_type,
51 Py_TPFLAGS_HAVE_GETCHARBUFFER)) {
52 PyErr_SetString(PyExc_TypeError,
53 "Py_TPFLAGS_HAVE_GETCHARBUFFER needed");
54 return 0;
55 }
56 proc = (readbufferproc)bp->bf_getcharbuffer;
57 }
58 if (!proc) {
59 char *buffer_type_name;
60 switch (buffer_type) {
61 case READ_BUFFER:
62 buffer_type_name = "read";
63 break;
64 case WRITE_BUFFER:
65 buffer_type_name = "write";
66 break;
67 case CHAR_BUFFER:
68 buffer_type_name = "char";
69 break;
70 default:
71 buffer_type_name = "no";
72 break;
73 }
74 PyErr_Format(PyExc_TypeError,
75 "%s buffer type not available",
76 buffer_type_name);
77 return 0;
78 }
79 if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
80 return 0;
81 /* apply constraints to the start/end */
82 if (self->b_offset > count)
83 offset = count;
84 else
85 offset = self->b_offset;
86 *(char **)ptr = *(char **)ptr + offset;
87 if (self->b_size == Py_END_OF_BUFFER)
88 *size = count;
89 else
90 *size = self->b_size;
91 if (offset + *size > count)
92 *size = count - offset;
93 }
94 return 1;
95}
96
97
98static PyObject *
99buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
100 int readonly)
101{
102 PyBufferObject * b;
103
104 if (size < 0 && size != Py_END_OF_BUFFER) {
105 PyErr_SetString(PyExc_ValueError,
106 "size must be zero or positive");
107 return NULL;
108 }
109 if (offset < 0) {
110 PyErr_SetString(PyExc_ValueError,
111 "offset must be zero or positive");
112 return NULL;
113 }
114
115 b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
116 if ( b == NULL )
117 return NULL;
118
119 Py_XINCREF(base);
120 b->b_base = base;
121 b->b_ptr = ptr;
122 b->b_size = size;
123 b->b_offset = offset;
124 b->b_readonly = readonly;
125 b->b_hash = -1;
126
127 return (PyObject *) b;
128}
129
130static PyObject *
131buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly)
132{
133 if (offset < 0) {
134 PyErr_SetString(PyExc_ValueError,
135 "offset must be zero or positive");
136 return NULL;
137 }
138 if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
139 /* another buffer, refer to the base object */
140 PyBufferObject *b = (PyBufferObject *)base;
141 if (b->b_size != Py_END_OF_BUFFER) {
142 Py_ssize_t base_size = b->b_size - offset;
143 if (base_size < 0)
144 base_size = 0;
145 if (size == Py_END_OF_BUFFER || size > base_size)
146 size = base_size;
147 }
148 offset += b->b_offset;
149 base = b->b_base;
150 }
151 return buffer_from_memory(base, size, offset, NULL, readonly);
152}
153
154
155PyObject *
156PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
157{
158 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
159
160 if ( pb == NULL ||
161 pb->bf_getreadbuffer == NULL ||
162 pb->bf_getsegcount == NULL )
163 {
164 PyErr_SetString(PyExc_TypeError, "buffer object expected");
165 return NULL;
166 }
167
168 return buffer_from_object(base, size, offset, 1);
169}
170
171PyObject *
172PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
173{
174 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
175
176 if ( pb == NULL ||
177 pb->bf_getwritebuffer == NULL ||
178 pb->bf_getsegcount == NULL )
179 {
180 PyErr_SetString(PyExc_TypeError, "buffer object expected");
181 return NULL;
182 }
183
184 return buffer_from_object(base, size, offset, 0);
185}
186
187PyObject *
188PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
189{
190 return buffer_from_memory(NULL, size, 0, ptr, 1);
191}
192
193PyObject *
194PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
195{
196 return buffer_from_memory(NULL, size, 0, ptr, 0);
197}
198
199PyObject *
200PyBuffer_New(Py_ssize_t size)
201{
202 PyObject *o;
203 PyBufferObject * b;
204
205 if (size < 0) {
206 PyErr_SetString(PyExc_ValueError,
207 "size must be zero or positive");
208 return NULL;
209 }
210 /* XXX: check for overflow in multiply */
211 /* Inline PyObject_New */
212 o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size);
213 if ( o == NULL )
214 return PyErr_NoMemory();
215 b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
216
217 b->b_base = NULL;
218 b->b_ptr = (void *)(b + 1);
219 b->b_size = size;
220 b->b_offset = 0;
221 b->b_readonly = 0;
222 b->b_hash = -1;
223
224 return o;
225}
226
227/* Methods */
228
229static PyObject *
230buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
231{
232 PyObject *ob;
233 Py_ssize_t offset = 0;
234 Py_ssize_t size = Py_END_OF_BUFFER;
235
236 if (!_PyArg_NoKeywords("buffer()", kw))
237 return NULL;
238
239 if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size))
240 return NULL;
241 return PyBuffer_FromObject(ob, offset, size);
242}
243
244PyDoc_STRVAR(buffer_doc,
245"buffer(object [, offset[, size]])\n\
246\n\
247Create a new buffer object which references the given object.\n\
248The buffer will reference a slice of the target object from the\n\
249start of the object (or at the specified offset). The slice will\n\
250extend to the end of the target object (or with the specified size).");
251
252
253static void
254buffer_dealloc(PyBufferObject *self)
255{
256 Py_XDECREF(self->b_base);
257 PyObject_DEL(self);
258}
259
260static int
261buffer_compare(PyBufferObject *self, PyBufferObject *other)
262{
263 void *p1, *p2;
264 Py_ssize_t len_self, len_other, min_len;
265 int cmp;
266
267 if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
268 return -1;
269 if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
270 return -1;
271 min_len = (len_self < len_other) ? len_self : len_other;
272 if (min_len > 0) {
273 cmp = memcmp(p1, p2, min_len);
274 if (cmp != 0)
275 return cmp < 0 ? -1 : 1;
276 }
277 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
278}
279
280static PyObject *
281buffer_repr(PyBufferObject *self)
282{
283 const char *status = self->b_readonly ? "read-only" : "read-write";
284
285 if ( self->b_base == NULL )
286 return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>",
287 status,
288 self->b_ptr,
289 self->b_size,
290 self);
291 else
292 return PyString_FromFormat(
293 "<%s buffer for %p, size %zd, offset %zd at %p>",
294 status,
295 self->b_base,
296 self->b_size,
297 self->b_offset,
298 self);
299}
300
301static long
302buffer_hash(PyBufferObject *self)
303{
304 void *ptr;
305 Py_ssize_t size;
306 register Py_ssize_t len;
307 register unsigned char *p;
308 register long x;
309
310 if ( self->b_hash != -1 )
311 return self->b_hash;
312
313 /* XXX potential bugs here, a readonly buffer does not imply that the
314 * underlying memory is immutable. b_readonly is a necessary but not
315 * sufficient condition for a buffer to be hashable. Perhaps it would
316 * be better to only allow hashing if the underlying object is known to
317 * be immutable (e.g. PyString_Check() is true). Another idea would
318 * be to call tp_hash on the underlying object and see if it raises
319 * an error. */
320 if ( !self->b_readonly )
321 {
322 PyErr_SetString(PyExc_TypeError,
323 "writable buffers are not hashable");
324 return -1;
325 }
326
327 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
328 return -1;
329 p = (unsigned char *) ptr;
330 len = size;
331 x = *p << 7;
332 while (--len >= 0)
333 x = (1000003*x) ^ *p++;
334 x ^= size;
335 if (x == -1)
336 x = -2;
337 self->b_hash = x;
338 return x;
339}
340
341static PyObject *
342buffer_str(PyBufferObject *self)
343{
344 void *ptr;
345 Py_ssize_t size;
346 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
347 return NULL;
348 return PyString_FromStringAndSize((const char *)ptr, size);
349}
350
351/* Sequence methods */
352
353static Py_ssize_t
354buffer_length(PyBufferObject *self)
355{
356 void *ptr;
357 Py_ssize_t size;
358 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
359 return -1;
360 return size;
361}
362
363static PyObject *
364buffer_concat(PyBufferObject *self, PyObject *other)
365{
366 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
367 void *ptr1, *ptr2;
368 char *p;
369 PyObject *ob;
370 Py_ssize_t size, count;
371
372 if ( pb == NULL ||
373 pb->bf_getreadbuffer == NULL ||
374 pb->bf_getsegcount == NULL )
375 {
376 PyErr_BadArgument();
377 return NULL;
378 }
379 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
380 {
381 /* ### use a different exception type/message? */
382 PyErr_SetString(PyExc_TypeError,
383 "single-segment buffer object expected");
384 return NULL;
385 }
386
387 if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
388 return NULL;
389
390 /* optimize special case */
391 if ( size == 0 )
392 {
393 Py_INCREF(other);
394 return other;
395 }
396
397 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
398 return NULL;
399
400 ob = PyString_FromStringAndSize(NULL, size + count);
401 if ( ob == NULL )
402 return NULL;
403 p = PyString_AS_STRING(ob);
404 memcpy(p, ptr1, size);
405 memcpy(p + size, ptr2, count);
406
407 /* there is an extra byte in the string object, so this is safe */
408 p[size + count] = '\0';
409
410 return ob;
411}
412
413static PyObject *
414buffer_repeat(PyBufferObject *self, Py_ssize_t count)
415{
416 PyObject *ob;
417 register char *p;
418 void *ptr;
419 Py_ssize_t size;
420
421 if ( count < 0 )
422 count = 0;
423 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
424 return NULL;
425 ob = PyString_FromStringAndSize(NULL, size * count);
426 if ( ob == NULL )
427 return NULL;
428
429 p = PyString_AS_STRING(ob);
430 while ( count-- )
431 {
432 memcpy(p, ptr, size);
433 p += size;
434 }
435
436 /* there is an extra byte in the string object, so this is safe */
437 *p = '\0';
438
439 return ob;
440}
441
442static PyObject *
443buffer_item(PyBufferObject *self, Py_ssize_t idx)
444{
445 void *ptr;
446 Py_ssize_t size;
447 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
448 return NULL;
449 if ( idx < 0 || idx >= size ) {
450 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
451 return NULL;
452 }
453 return PyString_FromStringAndSize((char *)ptr + idx, 1);
454}
455
456static PyObject *
457buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
458{
459 void *ptr;
460 Py_ssize_t size;
461 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
462 return NULL;
463 if ( left < 0 )
464 left = 0;
465 if ( right < 0 )
466 right = 0;
467 if ( right > size )
468 right = size;
469 if ( right < left )
470 right = left;
471 return PyString_FromStringAndSize((char *)ptr + left,
472 right - left);
473}
474
475static int
476buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
477{
478 PyBufferProcs *pb;
479 void *ptr1, *ptr2;
480 Py_ssize_t size;
481 Py_ssize_t count;
482
483 if ( self->b_readonly ) {
484 PyErr_SetString(PyExc_TypeError,
485 "buffer is read-only");
486 return -1;
487 }
488
489 if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
490 return -1;
491
492 if (idx < 0 || idx >= size) {
493 PyErr_SetString(PyExc_IndexError,
494 "buffer assignment index out of range");
495 return -1;
496 }
497
498 pb = other ? other->ob_type->tp_as_buffer : NULL;
499 if ( pb == NULL ||
500 pb->bf_getreadbuffer == NULL ||
501 pb->bf_getsegcount == NULL )
502 {
503 PyErr_BadArgument();
504 return -1;
505 }
506 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
507 {
508 /* ### use a different exception type/message? */
509 PyErr_SetString(PyExc_TypeError,
510 "single-segment buffer object expected");
511 return -1;
512 }
513
514 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
515 return -1;
516 if ( count != 1 ) {
517 PyErr_SetString(PyExc_TypeError,
518 "right operand must be a single byte");
519 return -1;
520 }
521
522 ((char *)ptr1)[idx] = *(char *)ptr2;
523 return 0;
524}
525
526static int
527buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
528{
529 PyBufferProcs *pb;
530 void *ptr1, *ptr2;
531 Py_ssize_t size;
532 Py_ssize_t slice_len;
533 Py_ssize_t count;
534
535 if ( self->b_readonly ) {
536 PyErr_SetString(PyExc_TypeError,
537 "buffer is read-only");
538 return -1;
539 }
540
541 pb = other ? other->ob_type->tp_as_buffer : NULL;
542 if ( pb == NULL ||
543 pb->bf_getreadbuffer == NULL ||
544 pb->bf_getsegcount == NULL )
545 {
546 PyErr_BadArgument();
547 return -1;
548 }
549 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
550 {
551 /* ### use a different exception type/message? */
552 PyErr_SetString(PyExc_TypeError,
553 "single-segment buffer object expected");
554 return -1;
555 }
556 if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
557 return -1;
558 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
559 return -1;
560
561 if ( left < 0 )
562 left = 0;
563 else if ( left > size )
564 left = size;
565 if ( right < left )
566 right = left;
567 else if ( right > size )
568 right = size;
569 slice_len = right - left;
570
571 if ( count != slice_len ) {
572 PyErr_SetString(
573 PyExc_TypeError,
574 "right operand length must match slice length");
575 return -1;
576 }
577
578 if ( slice_len )
579 memcpy((char *)ptr1 + left, ptr2, slice_len);
580
581 return 0;
582}
583
584/* Buffer methods */
585
586static Py_ssize_t
587buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
588{
589 Py_ssize_t size;
590 if ( idx != 0 ) {
591 PyErr_SetString(PyExc_SystemError,
592 "accessing non-existent buffer segment");
593 return -1;
594 }
595 if (!get_buf(self, pp, &size, READ_BUFFER))
596 return -1;
597 return size;
598}
599
600static Py_ssize_t
601buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
602{
603 Py_ssize_t size;
604
605 if ( self->b_readonly )
606 {
607 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
608 return -1;
609 }
610
611 if ( idx != 0 ) {
612 PyErr_SetString(PyExc_SystemError,
613 "accessing non-existent buffer segment");
614 return -1;
615 }
616 if (!get_buf(self, pp, &size, WRITE_BUFFER))
617 return -1;
618 return size;
619}
620
621static Py_ssize_t
622buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
623{
624 void *ptr;
625 Py_ssize_t size;
626 if (!get_buf(self, &ptr, &size, ANY_BUFFER))
627 return -1;
628 if (lenp)
629 *lenp = size;
630 return 1;
631}
632
633static Py_ssize_t
634buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
635{
636 void *ptr;
637 Py_ssize_t size;
638 if ( idx != 0 ) {
639 PyErr_SetString(PyExc_SystemError,
640 "accessing non-existent buffer segment");
641 return -1;
642 }
643 if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
644 return -1;
645 *pp = (const char *)ptr;
646 return size;
647}
648
649static PySequenceMethods buffer_as_sequence = {
650 (lenfunc)buffer_length, /*sq_length*/
651 (binaryfunc)buffer_concat, /*sq_concat*/
652 (ssizeargfunc)buffer_repeat, /*sq_repeat*/
653 (ssizeargfunc)buffer_item, /*sq_item*/
654 (ssizessizeargfunc)buffer_slice, /*sq_slice*/
655 (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/
656 (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/
657};
658
659static PyBufferProcs buffer_as_buffer = {
660 (readbufferproc)buffer_getreadbuf,
661 (writebufferproc)buffer_getwritebuf,
662 (segcountproc)buffer_getsegcount,
663 (charbufferproc)buffer_getcharbuf,
664};
665
666PyTypeObject PyBuffer_Type = {
667 PyObject_HEAD_INIT(&PyType_Type)
668 0,
669 "buffer",
670 sizeof(PyBufferObject),
671 0,
672 (destructor)buffer_dealloc, /* tp_dealloc */
673 0, /* tp_print */
674 0, /* tp_getattr */
675 0, /* tp_setattr */
676 (cmpfunc)buffer_compare, /* tp_compare */
677 (reprfunc)buffer_repr, /* tp_repr */
678 0, /* tp_as_number */
679 &buffer_as_sequence, /* tp_as_sequence */
680 0, /* tp_as_mapping */
681 (hashfunc)buffer_hash, /* tp_hash */
682 0, /* tp_call */
683 (reprfunc)buffer_str, /* tp_str */
684 PyObject_GenericGetAttr, /* tp_getattro */
685 0, /* tp_setattro */
686 &buffer_as_buffer, /* tp_as_buffer */
687 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */
688 buffer_doc, /* tp_doc */
689 0, /* tp_traverse */
690 0, /* tp_clear */
691 0, /* tp_richcompare */
692 0, /* tp_weaklistoffset */
693 0, /* tp_iter */
694 0, /* tp_iternext */
695 0, /* tp_methods */
696 0, /* tp_members */
697 0, /* tp_getset */
698 0, /* tp_base */
699 0, /* tp_dict */
700 0, /* tp_descr_get */
701 0, /* tp_descr_set */
702 0, /* tp_dictoffset */
703 0, /* tp_init */
704 0, /* tp_alloc */
705 buffer_new, /* tp_new */
706};
Note: See TracBrowser for help on using the repository browser.