blob: 017ae64416bb970b011897cd206549f87c158410 [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
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
16
17While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
29
30******************************************************************/
31
32/* Buffer object implementation */
33
34#include "Python.h"
35
36
37typedef struct {
38 PyObject_HEAD
39 PyObject *b_base;
40 void *b_ptr;
41 int b_size;
42 int b_readonly;
43#ifdef CACHE_HASH
44 long b_hash;
45#endif
46} PyBufferObject;
47
48
49static PyObject *
50_PyBuffer_FromMemory(base, ptr, size, readonly)
51 PyObject *base;
52 void *ptr;
53 int size;
54 int readonly;
55{
56 PyBufferObject * b;
57
Guido van Rossum49ded3e1999-03-19 19:04:25 +000058 if ( size < 0 ) {
59 PyErr_SetString(PyExc_ValueError,
60 "size must be zero or positive");
61 return NULL;
62 }
63
Guido van Rossum2e19bd71998-10-07 14:36:10 +000064 b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
65 if ( b == NULL )
66 return NULL;
67
68 Py_XINCREF(base);
69 b->b_base = base;
70 b->b_ptr = ptr;
71 b->b_size = size;
72 b->b_readonly = readonly;
73#ifdef CACHE_HASH
74 b->b_hash = -1;
75#endif
76
77 return (PyObject *) b;
78}
79
80static PyObject *
81_PyBuffer_FromObject(base, offset, size, proc, readonly)
82 PyObject *base;
83 int offset;
84 int size;
85 getreadbufferproc proc;
86 int readonly;
87{
88 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
89 void *p;
90 int count;
Guido van Rossum2e19bd71998-10-07 14:36:10 +000091
Guido van Rossum49ded3e1999-03-19 19:04:25 +000092 if ( offset < 0 ) {
93 PyErr_SetString(PyExc_ValueError,
94 "offset must be zero or positive");
95 return NULL;
96 }
97
Guido van Rossum2e19bd71998-10-07 14:36:10 +000098 if ( (*pb->bf_getsegcount)(base, NULL) != 1 )
99 {
Guido van Rossumcd037e71999-03-24 19:05:31 +0000100 PyErr_SetString(PyExc_TypeError,
101 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000102 return NULL;
103 }
104 if ( (count = (*proc)(base, 0, &p)) < 0 )
105 return NULL;
106
107 /* apply constraints to the start/end */
Guido van Rossum49ded3e1999-03-19 19:04:25 +0000108 if ( size == Py_END_OF_BUFFER || size < 0 )
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000109 size = count;
110 if ( offset > count )
111 offset = count;
112 if ( offset + size > count )
113 size = count - offset;
114
115 /* if the base object is another buffer, then "deref" it */
116 if ( PyBuffer_Check(base) )
117 base = ((PyBufferObject *)base)->b_base;
118
119 return _PyBuffer_FromMemory(base, (char *)p + offset, size, readonly);
120}
121
122
123PyObject *
124PyBuffer_FromObject(base, offset, size)
125 PyObject *base;
126 int offset;
127 int size;
128{
129 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
130
131 if ( pb == NULL ||
132 pb->bf_getreadbuffer == NULL ||
133 pb->bf_getsegcount == NULL )
134 {
135 PyErr_SetString(PyExc_TypeError, "buffer object expected");
136 return NULL;
137 }
138
Guido van Rossumcd037e71999-03-24 19:05:31 +0000139 return _PyBuffer_FromObject(base, offset, size,
140 pb->bf_getreadbuffer, 1);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000141}
142
143PyObject *
144PyBuffer_FromReadWriteObject(base, offset, size)
145 PyObject *base;
146 int offset;
147 int size;
148{
149 PyBufferProcs *pb = base->ob_type->tp_as_buffer;
150
151 if ( pb == NULL ||
152 pb->bf_getwritebuffer == NULL ||
153 pb->bf_getsegcount == NULL )
154 {
155 PyErr_SetString(PyExc_TypeError, "buffer object expected");
156 return NULL;
157 }
158
Guido van Rossumcd037e71999-03-24 19:05:31 +0000159 return _PyBuffer_FromObject(base, offset, size,
160 (getreadbufferproc)pb->bf_getwritebuffer,
161 0);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000162}
163
164PyObject *
165PyBuffer_FromMemory(ptr, size)
166 void *ptr;
167 int size;
168{
169 return _PyBuffer_FromMemory(NULL, ptr, size, 1);
170}
171
172PyObject *
173PyBuffer_FromReadWriteMemory(ptr, size)
174 void *ptr;
175 int size;
176{
177 return _PyBuffer_FromMemory(NULL, ptr, size, 0);
178}
179
180PyObject *
181PyBuffer_New(size)
182 int size;
183{
184 PyBufferObject * b;
185
186 b = (PyBufferObject *)malloc(sizeof(*b) + size);
187 if ( b == NULL )
188 return NULL;
189 b->ob_type = &PyBuffer_Type;
190 _Py_NewReference((PyObject *)b);
191
192 b->b_base = NULL;
193 b->b_ptr = (void *)(b + 1);
194 b->b_size = size;
195 b->b_readonly = 0;
196#ifdef CACHE_HASH
197 b->b_hash = -1;
198#endif
199
200 return (PyObject *) b;
201}
202
203/* Methods */
204
205static void
206buffer_dealloc(self)
207 PyBufferObject *self;
208{
209 Py_XDECREF(self->b_base);
210 free((void *)self);
211}
212
213static int
214buffer_compare(self, other)
215 PyBufferObject *self;
216 PyBufferObject *other;
217{
218 int len_self = self->b_size;
219 int len_other = other->b_size;
220 int min_len = (len_self < len_other) ? len_self : len_other;
221 int cmp;
222 if (min_len > 0) {
223 cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
224 if (cmp != 0)
225 return cmp;
226 }
227 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
228}
229
230static PyObject *
231buffer_repr(self)
232 PyBufferObject *self;
233{
234 char buf[300];
235 char *status = self->b_readonly ? "read-only" : "read-write";
236
237 if ( self->b_base == NULL )
238 {
Guido van Rossum7148ca91998-10-07 16:22:12 +0000239 sprintf(buf, "<%s buffer ptr %lx, size %d at %lx>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000240 status,
Guido van Rossum7148ca91998-10-07 16:22:12 +0000241 (long)self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000242 self->b_size,
243 (long)self);
244 }
245 else
246 {
Guido van Rossum7148ca91998-10-07 16:22:12 +0000247 sprintf(buf, "<%s buffer for %lx, ptr %lx, size %d at %lx>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000248 status,
249 (long)self->b_base,
Guido van Rossum7148ca91998-10-07 16:22:12 +0000250 (long)self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000251 self->b_size,
252 (long)self);
253 }
254
255 return PyString_FromString(buf);
256}
257
258static long
259buffer_hash(self)
260 PyBufferObject *self;
261{
262 register int len;
263 register unsigned char *p;
264 register long x;
265
266#ifdef CACHE_HASH
267 if ( self->b_hash != -1 )
268 return self->b_hash;
269#endif
270
271 if ( !self->b_readonly )
272 {
273 /* ### use different wording, since this is conditional? */
274 PyErr_SetString(PyExc_TypeError, "unhashable type");
275 return -1;
276 }
277
278 len = self->b_size;
279 p = (unsigned char *) self->b_ptr;
280 x = *p << 7;
281 while (--len >= 0)
282 x = (1000003*x) ^ *p++;
283 x ^= self->b_size;
284 if (x == -1)
285 x = -2;
286#ifdef CACHE_HASH
287 self->b_hash = x;
288#endif
289 return x;
290}
291
292static PyObject *
293buffer_str(self)
294 PyBufferObject *self;
295{
296 return PyString_FromStringAndSize(self->b_ptr, self->b_size);
297}
298
299/* Sequence methods */
300
301static int
302buffer_length(self)
303 PyBufferObject *self;
304{
305 return self->b_size;
306}
307
308static PyObject *
309buffer_concat(self, other)
310 PyBufferObject *self;
311 PyObject *other;
312{
313 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
314 char *p1;
315 void *p2;
316 PyObject *ob;
317 int count;
318
319 if ( pb == NULL ||
320 pb->bf_getreadbuffer == NULL ||
321 pb->bf_getsegcount == NULL )
322 {
323 PyErr_BadArgument();
324 return NULL;
325 }
326 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
327 {
328 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000329 PyErr_SetString(PyExc_TypeError,
330 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000331 return NULL;
332 }
333
334 /* optimize special case */
335 if ( self->b_size == 0 )
336 {
337 Py_INCREF(other);
338 return other;
339 }
340
341 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
342 return NULL;
343
344 /* optimize special case */
345 if ( count == 0 )
346 {
347 Py_INCREF(self);
348 return (PyObject *)self;
349 }
350
351 ob = PyString_FromStringAndSize(NULL, self->b_size + count);
352 p1 = PyString_AS_STRING(ob);
353 memcpy(p1, self->b_ptr, self->b_size);
354 memcpy(p1 + self->b_size, p2, count);
355
356 /* there is an extra byte in the string object, so this is safe */
357 p1[self->b_size + count] = '\0';
358
359 return ob;
360}
361
362static PyObject *
363buffer_repeat(self, count)
364 PyBufferObject *self;
365 int count;
366{
367 PyObject *ob;
368 register char *p;
369 void *ptr = self->b_ptr;
370 int size = self->b_size;
371
372 if ( count < 0 )
373 count = 0;
374 ob = PyString_FromStringAndSize(NULL, size * count);
375 if ( ob == NULL )
376 return NULL;
377
378 p = PyString_AS_STRING(ob);
379 while ( count-- )
380 {
381 memcpy(p, ptr, size);
382 p += size;
383 }
384
385 /* there is an extra byte in the string object, so this is safe */
386 *p = '\0';
387
388 return ob;
389}
390
391static PyObject *
392buffer_item(self, idx)
393 PyBufferObject *self;
394 int idx;
395{
396 if ( idx < 0 || idx >= self->b_size )
397 {
398 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
399 return NULL;
400 }
401 return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
402}
403
404static PyObject *
405buffer_slice(self, left, right)
406 PyBufferObject *self;
407 int left;
408 int right;
409{
410 if ( left < 0 )
411 left = 0;
412 if ( right < 0 )
413 right = 0;
414 if ( right > self->b_size )
415 right = self->b_size;
416 if ( left == 0 && right == self->b_size )
417 {
418 /* same as self */
419 Py_INCREF(self);
420 return (PyObject *)self;
421 }
422 if ( right < left )
423 right = left;
Guido van Rossumcd037e71999-03-24 19:05:31 +0000424 return PyString_FromStringAndSize((char *)self->b_ptr + left,
425 right - left);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000426}
427
428static int
429buffer_ass_item(self, idx, other)
430 PyBufferObject *self;
431 int idx;
432 PyObject *other;
433{
434 PyBufferProcs *pb;
435 void *p;
436 int count;
437
438 if ( self->b_readonly ) {
439 PyErr_SetString(PyExc_TypeError,
440 "buffer is read-only");
441 return -1;
442 }
443
444 if (idx < 0 || idx >= self->b_size) {
445 PyErr_SetString(PyExc_IndexError,
446 "buffer assignment index out of range");
447 return -1;
448 }
449
450 pb = other ? other->ob_type->tp_as_buffer : NULL;
451 if ( pb == NULL ||
452 pb->bf_getreadbuffer == NULL ||
453 pb->bf_getsegcount == NULL )
454 {
455 PyErr_BadArgument();
456 return -1;
457 }
458 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
459 {
460 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000461 PyErr_SetString(PyExc_TypeError,
462 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000463 return -1;
464 }
465
466 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
467 return -1;
468 if ( count != 1 ) {
469 PyErr_SetString(PyExc_TypeError,
470 "right operand must be a single byte");
471 return -1;
472 }
473
474 ((char *)self->b_ptr)[idx] = *(char *)p;
475 return 0;
476}
477
478static int
479buffer_ass_slice(self, left, right, other)
480 PyBufferObject *self;
481 int left;
482 int right;
483 PyObject *other;
484{
485 PyBufferProcs *pb;
486 void *p;
487 int slice_len;
488 int count;
489
490 if ( self->b_readonly ) {
491 PyErr_SetString(PyExc_TypeError,
492 "buffer is read-only");
493 return -1;
494 }
495
496 pb = other ? other->ob_type->tp_as_buffer : NULL;
497 if ( pb == NULL ||
498 pb->bf_getreadbuffer == NULL ||
499 pb->bf_getsegcount == NULL )
500 {
501 PyErr_BadArgument();
502 return -1;
503 }
504 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
505 {
506 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000507 PyErr_SetString(PyExc_TypeError,
508 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000509 return -1;
510 }
511 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
512 return -1;
513
514 if ( left < 0 )
515 left = 0;
516 else if ( left > self->b_size )
517 left = self->b_size;
518 if ( right < left )
519 right = left;
520 else if ( right > self->b_size )
521 right = self->b_size;
522 slice_len = right - left;
523
524 if ( count != slice_len ) {
Guido van Rossumcd037e71999-03-24 19:05:31 +0000525 PyErr_SetString(
526 PyExc_TypeError,
527 "right operand length must match slice length");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000528 return -1;
529 }
530
531 if ( slice_len )
532 memcpy((char *)self->b_ptr + left, p, slice_len);
533
534 return 0;
535}
536
537/* Buffer methods */
538
539static int
540buffer_getreadbuf(self, idx, pp)
541 PyBufferObject *self;
542 int idx;
543 void ** pp;
544{
545 if ( idx != 0 ) {
546 PyErr_SetString(PyExc_SystemError,
Guido van Rossum1db70701998-10-08 02:18:52 +0000547 "accessing non-existent buffer segment");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000548 return -1;
549 }
550 *pp = self->b_ptr;
551 return self->b_size;
552}
553
554static int
555buffer_getwritebuf(self, idx, pp)
556 PyBufferObject *self;
557 int idx;
558 void ** pp;
559{
560 if ( self->b_readonly )
561 {
562 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
563 return -1;
564 }
565 return buffer_getreadbuf(self, idx, pp);
566}
567
568static int
569buffer_getsegcount(self, lenp)
570 PyBufferObject *self;
571 int *lenp;
572{
573 if ( lenp )
574 *lenp = self->b_size;
575 return 1;
576}
577
Guido van Rossum1db70701998-10-08 02:18:52 +0000578static int
579buffer_getcharbuf(self, idx, pp)
580 PyBufferObject *self;
581 int idx;
582 const char ** pp;
583{
584 if ( idx != 0 ) {
585 PyErr_SetString(PyExc_SystemError,
586 "accessing non-existent buffer segment");
587 return -1;
588 }
589 *pp = (const char *)self->b_ptr;
590 return self->b_size;
591}
592
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000593
594static PySequenceMethods buffer_as_sequence = {
595 (inquiry)buffer_length, /*sq_length*/
596 (binaryfunc)buffer_concat, /*sq_concat*/
597 (intargfunc)buffer_repeat, /*sq_repeat*/
598 (intargfunc)buffer_item, /*sq_item*/
599 (intintargfunc)buffer_slice, /*sq_slice*/
600 (intobjargproc)buffer_ass_item, /*sq_ass_item*/
601 (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
602};
603
604static PyBufferProcs buffer_as_buffer = {
605 (getreadbufferproc)buffer_getreadbuf,
606 (getwritebufferproc)buffer_getwritebuf,
607 (getsegcountproc)buffer_getsegcount,
Guido van Rossum1db70701998-10-08 02:18:52 +0000608 (getcharbufferproc)buffer_getcharbuf,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000609};
610
611PyTypeObject PyBuffer_Type = {
612 PyObject_HEAD_INIT(&PyType_Type)
613 0,
614 "buffer",
615 sizeof(PyBufferObject),
616 0,
617 (destructor)buffer_dealloc, /*tp_dealloc*/
618 0, /*tp_print*/
619 0, /*tp_getattr*/
620 0, /*tp_setattr*/
621 (cmpfunc)buffer_compare, /*tp_compare*/
622 (reprfunc)buffer_repr, /*tp_repr*/
623 0, /*tp_as_number*/
624 &buffer_as_sequence, /*tp_as_sequence*/
625 0, /*tp_as_mapping*/
626 (hashfunc)buffer_hash, /*tp_hash*/
627 0, /*tp_call*/
628 (reprfunc)buffer_str, /*tp_str*/
629 0, /*tp_getattro*/
630 0, /*tp_setattro*/
631 &buffer_as_buffer, /*tp_as_buffer*/
Guido van Rossum1db70701998-10-08 02:18:52 +0000632 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000633 0, /*tp_doc*/
634};
635