bufferobject.c revision 4252a7a5d1c0bbc41abeab2ae5ce29f42cd9ace8
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	int b_size;
12	int b_offset;
13	int b_readonly;
14	long b_hash;
15} PyBufferObject;
16
17
18static 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;
46		(char *)*ptr = (char *)*ptr + offset;
47		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
58static PyObject *
59buffer_from_memory(PyObject *base, int size, int offset, void *ptr,
60		   int readonly)
61{
62	PyBufferObject * b;
63
64	if (size < 0 && size != Py_END_OF_BUFFER) {
65		PyErr_SetString(PyExc_ValueError,
66				"size must be zero or positive");
67		return NULL;
68	}
69
70	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;
78	b->b_offset = offset;
79	b->b_readonly = readonly;
80	b->b_hash = -1;
81
82	return (PyObject *) b;
83}
84
85static PyObject *
86buffer_from_object(PyObject *base, int size, int offset, int readonly)
87{
88	if ( offset < 0 ) {
89		PyErr_SetString(PyExc_ValueError,
90				"offset must be zero or positive");
91		return NULL;
92	}
93
94	/* if the base object is another buffer, then try to refer to the
95	 * base object.
96	 */
97	if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
98		base = ((PyBufferObject *)base)->b_base;
99		offset = ((PyBufferObject *)base)->b_offset + offset;
100	}
101
102	return buffer_from_memory(base, size, offset, NULL, readonly);
103}
104
105
106PyObject *
107PyBuffer_FromObject(PyObject *base, int offset, int size)
108{
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
119	return buffer_from_object(base, size, offset, 1);
120}
121
122PyObject *
123PyBuffer_FromReadWriteObject(PyObject *base, int offset, int size)
124{
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
135	return buffer_from_object(base, size,  offset, 0);
136}
137
138PyObject *
139PyBuffer_FromMemory(void *ptr, int size)
140{
141	return buffer_from_memory(NULL, size, 0, ptr, 1);
142}
143
144PyObject *
145PyBuffer_FromReadWriteMemory(void *ptr, int size)
146{
147	return buffer_from_memory(NULL, size, 0, ptr, 0);
148}
149
150PyObject *
151PyBuffer_New(int size)
152{
153	PyObject *o;
154	PyBufferObject * b;
155
156	if (size < 0) {
157		PyErr_SetString(PyExc_ValueError,
158				"size must be zero or positive");
159		return NULL;
160	}
161	/* Inline PyObject_New */
162	o = PyObject_MALLOC(sizeof(*b) + size);
163	if ( o == NULL )
164		return PyErr_NoMemory();
165	b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
166
167	b->b_base = NULL;
168	b->b_ptr = (void *)(b + 1);
169	b->b_size = size;
170	b->b_offset = 0;
171	b->b_readonly = 0;
172	b->b_hash = -1;
173
174	return o;
175}
176
177/* Methods */
178
179static 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
200static void
201buffer_dealloc(PyBufferObject *self)
202{
203	Py_XDECREF(self->b_base);
204	PyObject_DEL(self);
205}
206
207static int
208buffer_compare(PyBufferObject *self, PyBufferObject *other)
209{
210	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;
218	if (min_len > 0) {
219		cmp = memcmp(p1, p2, min_len);
220		if (cmp != 0)
221			return cmp;
222	}
223	return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
224}
225
226static PyObject *
227buffer_repr(PyBufferObject *self)
228{
229	char *status = self->b_readonly ? "read-only" : "read-write";
230
231	if ( self->b_base == NULL )
232		return PyString_FromFormat("<%s buffer ptr %p, size %d at %p>",
233					   status,
234					   self->b_ptr,
235					   self->b_size,
236					   self);
237	else
238		return PyString_FromFormat(
239			"<%s buffer for %p, size %d, offset %d at %p>",
240			status,
241			self->b_base,
242			self->b_size,
243			self->b_offset,
244			self);
245}
246
247static long
248buffer_hash(PyBufferObject *self)
249{
250	void *ptr;
251	int size;
252	register int len;
253	register unsigned char *p;
254	register long x;
255
256	if ( self->b_hash != -1 )
257		return self->b_hash;
258
259	/* 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. */
266	if ( !self->b_readonly )
267	{
268		PyErr_SetString(PyExc_TypeError,
269				"writable buffers are not hashable");
270		return -1;
271	}
272
273	if (!get_buf(self, &ptr, &size))
274		return -1;
275	p = (unsigned char *) ptr;
276	len = size;
277	x = *p << 7;
278	while (--len >= 0)
279		x = (1000003*x) ^ *p++;
280	x ^= size;
281	if (x == -1)
282		x = -2;
283	self->b_hash = x;
284	return x;
285}
286
287static PyObject *
288buffer_str(PyBufferObject *self)
289{
290	void *ptr;
291	int size;
292	if (!get_buf(self, &ptr, &size))
293		return NULL;
294	return PyString_FromStringAndSize(ptr, size);
295}
296
297/* Sequence methods */
298
299static int
300buffer_length(PyBufferObject *self)
301{
302	void *ptr;
303	int size;
304	if (!get_buf(self, &ptr, &size))
305		return -1;
306	return size;
307}
308
309static PyObject *
310buffer_concat(PyBufferObject *self, PyObject *other)
311{
312	PyBufferProcs *pb = other->ob_type->tp_as_buffer;
313	void *ptr1, *ptr2;
314	char *p;
315	PyObject *ob;
316	int size, count;
317
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? */
328		PyErr_SetString(PyExc_TypeError,
329				"single-segment buffer object expected");
330		return NULL;
331	}
332
333 	if (!get_buf(self, &ptr1, &size))
334 		return NULL;
335
336	/* optimize special case */
337	if ( size == 0 )
338	{
339	    Py_INCREF(other);
340	    return other;
341	}
342
343	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
344		return NULL;
345
346 	ob = PyString_FromStringAndSize(NULL, size + count);
347 	p = PyString_AS_STRING(ob);
348 	memcpy(p, ptr1, size);
349 	memcpy(p + size, ptr2, count);
350
351	/* there is an extra byte in the string object, so this is safe */
352	p[size + count] = '\0';
353
354	return ob;
355}
356
357static PyObject *
358buffer_repeat(PyBufferObject *self, int count)
359{
360	PyObject *ob;
361	register char *p;
362	void *ptr;
363	int size;
364
365	if ( count < 0 )
366		count = 0;
367	if (!get_buf(self, &ptr, &size))
368		return NULL;
369	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 *
387buffer_item(PyBufferObject *self, int idx)
388{
389	void *ptr;
390	int size;
391	if (!get_buf(self, &ptr, &size))
392		return NULL;
393	if ( idx < 0 || idx >= size ) {
394		PyErr_SetString(PyExc_IndexError, "buffer index out of range");
395		return NULL;
396	}
397	return PyString_FromStringAndSize((char *)ptr + idx, 1);
398}
399
400static PyObject *
401buffer_slice(PyBufferObject *self, int left, int right)
402{
403	void *ptr;
404	int size;
405	if (!get_buf(self, &ptr, &size))
406		return NULL;
407	if ( left < 0 )
408		left = 0;
409	if ( right < 0 )
410		right = 0;
411	if ( right > size )
412		right = size;
413	if ( right < left )
414		right = left;
415	return PyString_FromStringAndSize((char *)ptr + left,
416					  right - left);
417}
418
419static int
420buffer_ass_item(PyBufferObject *self, int idx, PyObject *other)
421{
422	PyBufferProcs *pb;
423	void *ptr1, *ptr2;
424	int size;
425	int count;
426
427	if ( self->b_readonly ) {
428		PyErr_SetString(PyExc_TypeError,
429				"buffer is read-only");
430		return -1;
431	}
432
433	if (!get_buf(self, &ptr1, &size))
434		return -1;
435
436	if (idx < 0 || idx >= size) {
437		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? */
453		PyErr_SetString(PyExc_TypeError,
454				"single-segment buffer object expected");
455		return -1;
456	}
457
458	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
459		return -1;
460	if ( count != 1 ) {
461		PyErr_SetString(PyExc_TypeError,
462				"right operand must be a single byte");
463		return -1;
464	}
465
466	((char *)ptr1)[idx] = *(char *)ptr2;
467	return 0;
468}
469
470static int
471buffer_ass_slice(PyBufferObject *self, int left, int right, PyObject *other)
472{
473	PyBufferProcs *pb;
474	void *ptr1, *ptr2;
475	int size;
476	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? */
496		PyErr_SetString(PyExc_TypeError,
497				"single-segment buffer object expected");
498		return -1;
499	}
500	if (!get_buf(self, &ptr1, &size))
501		return -1;
502	if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
503		return -1;
504
505	if ( left < 0 )
506		left = 0;
507	else if ( left > size )
508		left = size;
509	if ( right < left )
510		right = left;
511	else if ( right > size )
512		right = size;
513	slice_len = right - left;
514
515	if ( count != slice_len ) {
516		PyErr_SetString(
517			PyExc_TypeError,
518			"right operand length must match slice length");
519		return -1;
520	}
521
522	if ( slice_len )
523	    memcpy((char *)ptr1 + left, ptr2, slice_len);
524
525	return 0;
526}
527
528/* Buffer methods */
529
530static int
531buffer_getreadbuf(PyBufferObject *self, int idx, void **pp)
532{
533	int size;
534	if ( idx != 0 ) {
535		PyErr_SetString(PyExc_SystemError,
536				"accessing non-existent buffer segment");
537		return -1;
538	}
539	if (!get_buf(self, pp, &size))
540		return -1;
541	return size;
542}
543
544static int
545buffer_getwritebuf(PyBufferObject *self, int idx, void **pp)
546{
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
556buffer_getsegcount(PyBufferObject *self, int *lenp)
557{
558	void *ptr;
559	int size;
560	if (!get_buf(self, &ptr, &size))
561		return -1;
562	if (lenp)
563		*lenp = size;
564	return 1;
565}
566
567static int
568buffer_getcharbuf(PyBufferObject *self, int idx, const char **pp)
569{
570	void *ptr;
571	int size;
572	if ( idx != 0 ) {
573		PyErr_SetString(PyExc_SystemError,
574				"accessing non-existent buffer segment");
575		return -1;
576	}
577	if (!get_buf(self, &ptr, &size))
578		return -1;
579	*pp = (const char *)ptr;
580	return size;
581}
582
583
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,
598	(getcharbufferproc)buffer_getcharbuf,
599};
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	PyObject_GenericGetAttr,		/* tp_getattro */
620	0,					/* tp_setattro */
621	&buffer_as_buffer,			/* tp_as_buffer */
622	Py_TPFLAGS_DEFAULT,			/* tp_flags */
623	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 */
641};
642