blob: 9bce20e89a5ef172879790bd041460975fd0bd45 [file] [log] [blame]
Guido van Rossum2e19bd71998-10-07 14:36:10 +00001/***********************************************************
Guido van Rossumfd71b9e2000-06-30 23:50:40 +00002Copyright (c) 2000, BeOpen.com.
3Copyright (c) 1995-2000, Corporation for National Research Initiatives.
4Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
5All rights reserved.
Guido van Rossum2e19bd71998-10-07 14:36:10 +00006
Guido van Rossumfd71b9e2000-06-30 23:50:40 +00007See the file "Misc/COPYRIGHT" for information on usage and
8redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
Guido van Rossum2e19bd71998-10-07 14:36:10 +00009******************************************************************/
10
11/* Buffer object implementation */
12
13#include "Python.h"
14
15
16typedef struct {
17 PyObject_HEAD
18 PyObject *b_base;
19 void *b_ptr;
20 int b_size;
21 int b_readonly;
22#ifdef CACHE_HASH
23 long b_hash;
24#endif
25} PyBufferObject;
26
27
28static PyObject *
29_PyBuffer_FromMemory(base, ptr, size, readonly)
30 PyObject *base;
31 void *ptr;
32 int size;
33 int readonly;
34{
35 PyBufferObject * b;
36
Guido van Rossum49ded3e1999-03-19 19:04:25 +000037 if ( size < 0 ) {
38 PyErr_SetString(PyExc_ValueError,
39 "size must be zero or positive");
40 return NULL;
41 }
42
Guido van Rossum2e19bd71998-10-07 14:36:10 +000043 b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
44 if ( b == NULL )
45 return NULL;
46
47 Py_XINCREF(base);
48 b->b_base = base;
49 b->b_ptr = ptr;
50 b->b_size = size;
51 b->b_readonly = readonly;
52#ifdef CACHE_HASH
53 b->b_hash = -1;
54#endif
55
56 return (PyObject *) b;
57}
58
59static PyObject *
60_PyBuffer_FromObject(base, offset, size, proc, readonly)
61 PyObject *base;
62 int offset;
63 int size;
64 getreadbufferproc proc;
65 int readonly;
66{
67 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
68 void *p;
69 int count;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000070
Guido van Rossum49ded3e1999-03-19 19:04:25 +000071 if ( offset < 0 ) {
72 PyErr_SetString(PyExc_ValueError,
73 "offset must be zero or positive");
74 return NULL;
75 }
76
Guido van Rossum2e19bd71998-10-07 14:36:10 +000077 if ( (*pb->bf_getsegcount)(base, NULL) != 1 )
78 {
Guido van Rossumcd037e71999-03-24 19:05:31 +000079 PyErr_SetString(PyExc_TypeError,
80 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +000081 return NULL;
82 }
83 if ( (count = (*proc)(base, 0, &p)) < 0 )
84 return NULL;
85
86 /* apply constraints to the start/end */
Guido van Rossum49ded3e1999-03-19 19:04:25 +000087 if ( size == Py_END_OF_BUFFER || size < 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +000088 size = count;
89 if ( offset > count )
90 offset = count;
91 if ( offset + size > count )
92 size = count - offset;
93
94 /* if the base object is another buffer, then "deref" it */
95 if ( PyBuffer_Check(base) )
96 base = ((PyBufferObject *)base)->b_base;
97
98 return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
99}
100
101
102PyObject *
103PyBuffer_FromObject(base, offset, size)
104 PyObject *base;
105 int offset;
106 int size;
107{
108 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
109
110 if ( pb == NULL ||
111 pb->bf_getreadbuffer == NULL ||
112 pb->bf_getsegcount == NULL )
113 {
114 PyErr_SetString(PyExc_TypeError, "buffer object expected");
115 return NULL;
116 }
117
Guido van Rossumcd037e71999-03-24 19:05:31 +0000118 return _PyBuffer_FromObject(base, offset, size,
119 pb->bf_getreadbuffer, 1);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000120}
121
122PyObject *
123PyBuffer_FromReadWriteObject(base, offset, size)
124 PyObject *base;
125 int offset;
126 int size;
127{
128 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
129
130 if ( pb == NULL ||
131 pb->bf_getwritebuffer == NULL ||
132 pb->bf_getsegcount == NULL )
133 {
134 PyErr_SetString(PyExc_TypeError, "buffer object expected");
135 return NULL;
136 }
137
Guido van Rossumcd037e71999-03-24 19:05:31 +0000138 return _PyBuffer_FromObject(base, offset, size,
139 (getreadbufferproc)pb->bf_getwritebuffer,
140 0);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000141}
142
143PyObject *
144PyBuffer_FromMemory(ptr, size)
145 void *ptr;
146 int size;
147{
148 return _PyBuffer_FromMemory(NULL, ptr, size, 1);
149}
150
151PyObject *
152PyBuffer_FromReadWriteMemory(ptr, size)
153 void *ptr;
154 int size;
155{
156 return _PyBuffer_FromMemory(NULL, ptr, size, 0);
157}
158
159PyObject *
160PyBuffer_New(size)
161 int size;
162{
163 PyBufferObject * b;
164
Fred Drake4574f231999-08-04 13:08:19 +0000165 if (size < 0) {
166 PyErr_SetString(PyExc_ValueError,
167 "size must be zero or positive");
168 return NULL;
169 }
Guido van Rossumb18618d2000-05-03 23:44:39 +0000170 /* PyObject_New is inlined */
171 b = (PyBufferObject *) PyObject_MALLOC(sizeof(*b) + size);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000172 if ( b == NULL )
Fred Drake4574f231999-08-04 13:08:19 +0000173 return PyErr_NoMemory();
Guido van Rossumb18618d2000-05-03 23:44:39 +0000174 PyObject_INIT((PyObject *)b, &PyBuffer_Type);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000175
176 b->b_base = NULL;
177 b->b_ptr = (void *)(b + 1);
178 b->b_size = size;
179 b->b_readonly = 0;
180#ifdef CACHE_HASH
181 b->b_hash = -1;
182#endif
183
184 return (PyObject *) b;
185}
186
187/* Methods */
188
189static void
190buffer_dealloc(self)
191 PyBufferObject *self;
192{
193 Py_XDECREF(self->b_base);
Guido van Rossumb18618d2000-05-03 23:44:39 +0000194 PyObject_DEL(self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000195}
196
197static int
198buffer_compare(self, other)
199 PyBufferObject *self;
200 PyBufferObject *other;
201{
202 int len_self = self->b_size;
203 int len_other = other->b_size;
204 int min_len = (len_self < len_other) ? len_self : len_other;
205 int cmp;
206 if (min_len > 0) {
207 cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
208 if (cmp != 0)
209 return cmp;
210 }
211 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
212}
213
214static PyObject *
215buffer_repr(self)
216 PyBufferObject *self;
217{
218 char buf[300];
219 char *status = self->b_readonly ? "read-only" : "read-write";
220
221 if ( self->b_base == NULL )
222 {
Fred Drakea44d3532000-06-30 15:01:00 +0000223 sprintf(buf, "<%s buffer ptr %p, size %d at %p>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000224 status,
Fred Drakea44d3532000-06-30 15:01:00 +0000225 self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000226 self->b_size,
Fred Drakea44d3532000-06-30 15:01:00 +0000227 self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000228 }
229 else
230 {
Fred Drakea44d3532000-06-30 15:01:00 +0000231 sprintf(buf, "<%s buffer for %p, ptr %p, size %d at %p>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000232 status,
Fred Drakea44d3532000-06-30 15:01:00 +0000233 self->b_base,
234 self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000235 self->b_size,
Fred Drakea44d3532000-06-30 15:01:00 +0000236 self);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000237 }
238
239 return PyString_FromString(buf);
240}
241
242static long
243buffer_hash(self)
244 PyBufferObject *self;
245{
246 register int len;
247 register unsigned char *p;
248 register long x;
249
250#ifdef CACHE_HASH
251 if ( self->b_hash != -1 )
252 return self->b_hash;
253#endif
254
255 if ( !self->b_readonly )
256 {
257 /* ### use different wording, since this is conditional? */
258 PyErr_SetString(PyExc_TypeError, "unhashable type");
259 return -1;
260 }
261
262 len = self->b_size;
263 p = (unsigned char *) self->b_ptr;
264 x = *p << 7;
265 while (--len >= 0)
266 x = (1000003*x) ^ *p++;
267 x ^= self->b_size;
268 if (x == -1)
269 x = -2;
270#ifdef CACHE_HASH
271 self->b_hash = x;
272#endif
273 return x;
274}
275
276static PyObject *
277buffer_str(self)
278 PyBufferObject *self;
279{
280 return PyString_FromStringAndSize(self->b_ptr, self->b_size);
281}
282
283/* Sequence methods */
284
285static int
286buffer_length(self)
287 PyBufferObject *self;
288{
289 return self->b_size;
290}
291
292static PyObject *
293buffer_concat(self, other)
294 PyBufferObject *self;
295 PyObject *other;
296{
297 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
298 char *p1;
299 void *p2;
300 PyObject *ob;
301 int count;
302
303 if ( pb == NULL ||
304 pb->bf_getreadbuffer == NULL ||
305 pb->bf_getsegcount == NULL )
306 {
307 PyErr_BadArgument();
308 return NULL;
309 }
310 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
311 {
312 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000313 PyErr_SetString(PyExc_TypeError,
314 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000315 return NULL;
316 }
317
318 /* optimize special case */
319 if ( self->b_size == 0 )
320 {
321 Py_INCREF(other);
322 return other;
323 }
324
325 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
326 return NULL;
327
328 /* optimize special case */
329 if ( count == 0 )
330 {
331 Py_INCREF(self);
332 return (PyObject *)self;
333 }
334
335 ob = PyString_FromStringAndSize(NULL, self->b_size + count);
336 p1 = PyString_AS_STRING(ob);
337 memcpy(p1, self->b_ptr, self->b_size);
338 memcpy(p1 + self->b_size, p2, count);
339
340 /* there is an extra byte in the string object, so this is safe */
341 p1[self->b_size + count] = '\0';
342
343 return ob;
344}
345
346static PyObject *
347buffer_repeat(self, count)
348 PyBufferObject *self;
349 int count;
350{
351 PyObject *ob;
352 register char *p;
353 void *ptr = self->b_ptr;
354 int size = self->b_size;
355
356 if ( count < 0 )
357 count = 0;
358 ob = PyString_FromStringAndSize(NULL, size * count);
359 if ( ob == NULL )
360 return NULL;
361
362 p = PyString_AS_STRING(ob);
363 while ( count-- )
364 {
365 memcpy(p, ptr, size);
366 p += size;
367 }
368
369 /* there is an extra byte in the string object, so this is safe */
370 *p = '\0';
371
372 return ob;
373}
374
375static PyObject *
376buffer_item(self, idx)
377 PyBufferObject *self;
378 int idx;
379{
380 if ( idx < 0 || idx >= self->b_size )
381 {
382 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
383 return NULL;
384 }
385 return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
386}
387
388static PyObject *
389buffer_slice(self, left, right)
390 PyBufferObject *self;
391 int left;
392 int right;
393{
394 if ( left < 0 )
395 left = 0;
396 if ( right < 0 )
397 right = 0;
398 if ( right > self->b_size )
399 right = self->b_size;
400 if ( left == 0 && right == self->b_size )
401 {
402 /* same as self */
403 Py_INCREF(self);
404 return (PyObject *)self;
405 }
406 if ( right < left )
407 right = left;
Guido van Rossumcd037e71999-03-24 19:05:31 +0000408 return PyString_FromStringAndSize((char *)self->b_ptr + left,
409 right - left);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000410}
411
412static int
413buffer_ass_item(self, idx, other)
414 PyBufferObject *self;
415 int idx;
416 PyObject *other;
417{
418 PyBufferProcs *pb;
419 void *p;
420 int count;
421
422 if ( self->b_readonly ) {
423 PyErr_SetString(PyExc_TypeError,
424 "buffer is read-only");
425 return -1;
426 }
427
428 if (idx < 0 || idx >= self->b_size) {
429 PyErr_SetString(PyExc_IndexError,
430 "buffer assignment index out of range");
431 return -1;
432 }
433
434 pb = other ? other->ob_type->tp_as_buffer : NULL;
435 if ( pb == NULL ||
436 pb->bf_getreadbuffer == NULL ||
437 pb->bf_getsegcount == NULL )
438 {
439 PyErr_BadArgument();
440 return -1;
441 }
442 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
443 {
444 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000445 PyErr_SetString(PyExc_TypeError,
446 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000447 return -1;
448 }
449
450 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
451 return -1;
452 if ( count != 1 ) {
453 PyErr_SetString(PyExc_TypeError,
454 "right operand must be a single byte");
455 return -1;
456 }
457
458 ((char *)self->b_ptr)[idx] = *(char *)p;
459 return 0;
460}
461
462static int
463buffer_ass_slice(self, left, right, other)
464 PyBufferObject *self;
465 int left;
466 int right;
467 PyObject *other;
468{
469 PyBufferProcs *pb;
470 void *p;
471 int slice_len;
472 int count;
473
474 if ( self->b_readonly ) {
475 PyErr_SetString(PyExc_TypeError,
476 "buffer is read-only");
477 return -1;
478 }
479
480 pb = other ? other->ob_type->tp_as_buffer : NULL;
481 if ( pb == NULL ||
482 pb->bf_getreadbuffer == NULL ||
483 pb->bf_getsegcount == NULL )
484 {
485 PyErr_BadArgument();
486 return -1;
487 }
488 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
489 {
490 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000491 PyErr_SetString(PyExc_TypeError,
492 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000493 return -1;
494 }
495 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
496 return -1;
497
498 if ( left < 0 )
499 left = 0;
500 else if ( left > self->b_size )
501 left = self->b_size;
502 if ( right < left )
503 right = left;
504 else if ( right > self->b_size )
505 right = self->b_size;
506 slice_len = right - left;
507
508 if ( count != slice_len ) {
Guido van Rossumcd037e71999-03-24 19:05:31 +0000509 PyErr_SetString(
510 PyExc_TypeError,
511 "right operand length must match slice length");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000512 return -1;
513 }
514
515 if ( slice_len )
516 memcpy((char *)self->b_ptr + left, p, slice_len);
517
518 return 0;
519}
520
521/* Buffer methods */
522
523static int
524buffer_getreadbuf(self, idx, pp)
525 PyBufferObject *self;
526 int idx;
527 void ** pp;
528{
529 if ( idx != 0 ) {
530 PyErr_SetString(PyExc_SystemError,
Guido van Rossum1db70701998-10-08 02:18:52 +0000531 "accessing non-existent buffer segment");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000532 return -1;
533 }
534 *pp = self->b_ptr;
535 return self->b_size;
536}
537
538static int
539buffer_getwritebuf(self, idx, pp)
540 PyBufferObject *self;
541 int idx;
542 void ** pp;
543{
544 if ( self->b_readonly )
545 {
546 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
547 return -1;
548 }
549 return buffer_getreadbuf(self, idx, pp);
550}
551
552static int
553buffer_getsegcount(self, lenp)
554 PyBufferObject *self;
555 int *lenp;
556{
557 if ( lenp )
558 *lenp = self->b_size;
559 return 1;
560}
561
Guido van Rossum1db70701998-10-08 02:18:52 +0000562static int
563buffer_getcharbuf(self, idx, pp)
564 PyBufferObject *self;
565 int idx;
566 const char ** pp;
567{
568 if ( idx != 0 ) {
569 PyErr_SetString(PyExc_SystemError,
570 "accessing non-existent buffer segment");
571 return -1;
572 }
573 *pp = (const char *)self->b_ptr;
574 return self->b_size;
575}
576
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000577
578static PySequenceMethods buffer_as_sequence = {
579 (inquiry)buffer_length, /*sq_length*/
580 (binaryfunc)buffer_concat, /*sq_concat*/
581 (intargfunc)buffer_repeat, /*sq_repeat*/
582 (intargfunc)buffer_item, /*sq_item*/
583 (intintargfunc)buffer_slice, /*sq_slice*/
584 (intobjargproc)buffer_ass_item, /*sq_ass_item*/
585 (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
586};
587
588static PyBufferProcs buffer_as_buffer = {
589 (getreadbufferproc)buffer_getreadbuf,
590 (getwritebufferproc)buffer_getwritebuf,
591 (getsegcountproc)buffer_getsegcount,
Guido van Rossum1db70701998-10-08 02:18:52 +0000592 (getcharbufferproc)buffer_getcharbuf,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000593};
594
595PyTypeObject PyBuffer_Type = {
596 PyObject_HEAD_INIT(&PyType_Type)
597 0,
598 "buffer",
599 sizeof(PyBufferObject),
600 0,
601 (destructor)buffer_dealloc, /*tp_dealloc*/
602 0, /*tp_print*/
603 0, /*tp_getattr*/
604 0, /*tp_setattr*/
605 (cmpfunc)buffer_compare, /*tp_compare*/
606 (reprfunc)buffer_repr, /*tp_repr*/
607 0, /*tp_as_number*/
608 &buffer_as_sequence, /*tp_as_sequence*/
609 0, /*tp_as_mapping*/
610 (hashfunc)buffer_hash, /*tp_hash*/
611 0, /*tp_call*/
612 (reprfunc)buffer_str, /*tp_str*/
613 0, /*tp_getattro*/
614 0, /*tp_setattro*/
615 &buffer_as_buffer, /*tp_as_buffer*/
Guido van Rossum1db70701998-10-08 02:18:52 +0000616 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000617 0, /*tp_doc*/
618};
619