blob: 05b1f11406d4f2dc0391a5c45e334dadaf5fb070 [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
Fred Drake4574f231999-08-04 13:08:19 +0000186 if (size < 0) {
187 PyErr_SetString(PyExc_ValueError,
188 "size must be zero or positive");
189 return NULL;
190 }
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000191 b = (PyBufferObject *)malloc(sizeof(*b) + size);
192 if ( b == NULL )
Fred Drake4574f231999-08-04 13:08:19 +0000193 return PyErr_NoMemory();
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000194 b->ob_type = &PyBuffer_Type;
195 _Py_NewReference((PyObject *)b);
196
197 b->b_base = NULL;
198 b->b_ptr = (void *)(b + 1);
199 b->b_size = size;
200 b->b_readonly = 0;
201#ifdef CACHE_HASH
202 b->b_hash = -1;
203#endif
204
205 return (PyObject *) b;
206}
207
208/* Methods */
209
210static void
211buffer_dealloc(self)
212 PyBufferObject *self;
213{
214 Py_XDECREF(self->b_base);
215 free((void *)self);
216}
217
218static int
219buffer_compare(self, other)
220 PyBufferObject *self;
221 PyBufferObject *other;
222{
223 int len_self = self->b_size;
224 int len_other = other->b_size;
225 int min_len = (len_self < len_other) ? len_self : len_other;
226 int cmp;
227 if (min_len > 0) {
228 cmp = memcmp(self->b_ptr, other->b_ptr, min_len);
229 if (cmp != 0)
230 return cmp;
231 }
232 return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
233}
234
235static PyObject *
236buffer_repr(self)
237 PyBufferObject *self;
238{
239 char buf[300];
240 char *status = self->b_readonly ? "read-only" : "read-write";
241
242 if ( self->b_base == NULL )
243 {
Guido van Rossum7148ca91998-10-07 16:22:12 +0000244 sprintf(buf, "<%s buffer ptr %lx, size %d at %lx>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000245 status,
Guido van Rossum7148ca91998-10-07 16:22:12 +0000246 (long)self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000247 self->b_size,
248 (long)self);
249 }
250 else
251 {
Guido van Rossum7148ca91998-10-07 16:22:12 +0000252 sprintf(buf, "<%s buffer for %lx, ptr %lx, size %d at %lx>",
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000253 status,
254 (long)self->b_base,
Guido van Rossum7148ca91998-10-07 16:22:12 +0000255 (long)self->b_ptr,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000256 self->b_size,
257 (long)self);
258 }
259
260 return PyString_FromString(buf);
261}
262
263static long
264buffer_hash(self)
265 PyBufferObject *self;
266{
267 register int len;
268 register unsigned char *p;
269 register long x;
270
271#ifdef CACHE_HASH
272 if ( self->b_hash != -1 )
273 return self->b_hash;
274#endif
275
276 if ( !self->b_readonly )
277 {
278 /* ### use different wording, since this is conditional? */
279 PyErr_SetString(PyExc_TypeError, "unhashable type");
280 return -1;
281 }
282
283 len = self->b_size;
284 p = (unsigned char *) self->b_ptr;
285 x = *p << 7;
286 while (--len >= 0)
287 x = (1000003*x) ^ *p++;
288 x ^= self->b_size;
289 if (x == -1)
290 x = -2;
291#ifdef CACHE_HASH
292 self->b_hash = x;
293#endif
294 return x;
295}
296
297static PyObject *
298buffer_str(self)
299 PyBufferObject *self;
300{
301 return PyString_FromStringAndSize(self->b_ptr, self->b_size);
302}
303
304/* Sequence methods */
305
306static int
307buffer_length(self)
308 PyBufferObject *self;
309{
310 return self->b_size;
311}
312
313static PyObject *
314buffer_concat(self, other)
315 PyBufferObject *self;
316 PyObject *other;
317{
318 PyBufferProcs *pb = other->ob_type->tp_as_buffer;
319 char *p1;
320 void *p2;
321 PyObject *ob;
322 int count;
323
324 if ( pb == NULL ||
325 pb->bf_getreadbuffer == NULL ||
326 pb->bf_getsegcount == NULL )
327 {
328 PyErr_BadArgument();
329 return NULL;
330 }
331 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
332 {
333 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000334 PyErr_SetString(PyExc_TypeError,
335 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000336 return NULL;
337 }
338
339 /* optimize special case */
340 if ( self->b_size == 0 )
341 {
342 Py_INCREF(other);
343 return other;
344 }
345
346 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p2)) < 0 )
347 return NULL;
348
349 /* optimize special case */
350 if ( count == 0 )
351 {
352 Py_INCREF(self);
353 return (PyObject *)self;
354 }
355
356 ob = PyString_FromStringAndSize(NULL, self->b_size + count);
357 p1 = PyString_AS_STRING(ob);
358 memcpy(p1, self->b_ptr, self->b_size);
359 memcpy(p1 + self->b_size, p2, count);
360
361 /* there is an extra byte in the string object, so this is safe */
362 p1[self->b_size + count] = '\0';
363
364 return ob;
365}
366
367static PyObject *
368buffer_repeat(self, count)
369 PyBufferObject *self;
370 int count;
371{
372 PyObject *ob;
373 register char *p;
374 void *ptr = self->b_ptr;
375 int size = self->b_size;
376
377 if ( count < 0 )
378 count = 0;
379 ob = PyString_FromStringAndSize(NULL, size * count);
380 if ( ob == NULL )
381 return NULL;
382
383 p = PyString_AS_STRING(ob);
384 while ( count-- )
385 {
386 memcpy(p, ptr, size);
387 p += size;
388 }
389
390 /* there is an extra byte in the string object, so this is safe */
391 *p = '\0';
392
393 return ob;
394}
395
396static PyObject *
397buffer_item(self, idx)
398 PyBufferObject *self;
399 int idx;
400{
401 if ( idx < 0 || idx >= self->b_size )
402 {
403 PyErr_SetString(PyExc_IndexError, "buffer index out of range");
404 return NULL;
405 }
406 return PyString_FromStringAndSize((char *)self->b_ptr + idx, 1);
407}
408
409static PyObject *
410buffer_slice(self, left, right)
411 PyBufferObject *self;
412 int left;
413 int right;
414{
415 if ( left < 0 )
416 left = 0;
417 if ( right < 0 )
418 right = 0;
419 if ( right > self->b_size )
420 right = self->b_size;
421 if ( left == 0 && right == self->b_size )
422 {
423 /* same as self */
424 Py_INCREF(self);
425 return (PyObject *)self;
426 }
427 if ( right < left )
428 right = left;
Guido van Rossumcd037e71999-03-24 19:05:31 +0000429 return PyString_FromStringAndSize((char *)self->b_ptr + left,
430 right - left);
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000431}
432
433static int
434buffer_ass_item(self, idx, other)
435 PyBufferObject *self;
436 int idx;
437 PyObject *other;
438{
439 PyBufferProcs *pb;
440 void *p;
441 int count;
442
443 if ( self->b_readonly ) {
444 PyErr_SetString(PyExc_TypeError,
445 "buffer is read-only");
446 return -1;
447 }
448
449 if (idx < 0 || idx >= self->b_size) {
450 PyErr_SetString(PyExc_IndexError,
451 "buffer assignment index out of range");
452 return -1;
453 }
454
455 pb = other ? other->ob_type->tp_as_buffer : NULL;
456 if ( pb == NULL ||
457 pb->bf_getreadbuffer == NULL ||
458 pb->bf_getsegcount == NULL )
459 {
460 PyErr_BadArgument();
461 return -1;
462 }
463 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
464 {
465 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000466 PyErr_SetString(PyExc_TypeError,
467 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000468 return -1;
469 }
470
471 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
472 return -1;
473 if ( count != 1 ) {
474 PyErr_SetString(PyExc_TypeError,
475 "right operand must be a single byte");
476 return -1;
477 }
478
479 ((char *)self->b_ptr)[idx] = *(char *)p;
480 return 0;
481}
482
483static int
484buffer_ass_slice(self, left, right, other)
485 PyBufferObject *self;
486 int left;
487 int right;
488 PyObject *other;
489{
490 PyBufferProcs *pb;
491 void *p;
492 int slice_len;
493 int count;
494
495 if ( self->b_readonly ) {
496 PyErr_SetString(PyExc_TypeError,
497 "buffer is read-only");
498 return -1;
499 }
500
501 pb = other ? other->ob_type->tp_as_buffer : NULL;
502 if ( pb == NULL ||
503 pb->bf_getreadbuffer == NULL ||
504 pb->bf_getsegcount == NULL )
505 {
506 PyErr_BadArgument();
507 return -1;
508 }
509 if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
510 {
511 /* ### use a different exception type/message? */
Guido van Rossumcd037e71999-03-24 19:05:31 +0000512 PyErr_SetString(PyExc_TypeError,
513 "single-segment buffer object expected");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000514 return -1;
515 }
516 if ( (count = (*pb->bf_getreadbuffer)(other, 0, &p)) < 0 )
517 return -1;
518
519 if ( left < 0 )
520 left = 0;
521 else if ( left > self->b_size )
522 left = self->b_size;
523 if ( right < left )
524 right = left;
525 else if ( right > self->b_size )
526 right = self->b_size;
527 slice_len = right - left;
528
529 if ( count != slice_len ) {
Guido van Rossumcd037e71999-03-24 19:05:31 +0000530 PyErr_SetString(
531 PyExc_TypeError,
532 "right operand length must match slice length");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000533 return -1;
534 }
535
536 if ( slice_len )
537 memcpy((char *)self->b_ptr + left, p, slice_len);
538
539 return 0;
540}
541
542/* Buffer methods */
543
544static int
545buffer_getreadbuf(self, idx, pp)
546 PyBufferObject *self;
547 int idx;
548 void ** pp;
549{
550 if ( idx != 0 ) {
551 PyErr_SetString(PyExc_SystemError,
Guido van Rossum1db70701998-10-08 02:18:52 +0000552 "accessing non-existent buffer segment");
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000553 return -1;
554 }
555 *pp = self->b_ptr;
556 return self->b_size;
557}
558
559static int
560buffer_getwritebuf(self, idx, pp)
561 PyBufferObject *self;
562 int idx;
563 void ** pp;
564{
565 if ( self->b_readonly )
566 {
567 PyErr_SetString(PyExc_TypeError, "buffer is read-only");
568 return -1;
569 }
570 return buffer_getreadbuf(self, idx, pp);
571}
572
573static int
574buffer_getsegcount(self, lenp)
575 PyBufferObject *self;
576 int *lenp;
577{
578 if ( lenp )
579 *lenp = self->b_size;
580 return 1;
581}
582
Guido van Rossum1db70701998-10-08 02:18:52 +0000583static int
584buffer_getcharbuf(self, idx, pp)
585 PyBufferObject *self;
586 int idx;
587 const char ** pp;
588{
589 if ( idx != 0 ) {
590 PyErr_SetString(PyExc_SystemError,
591 "accessing non-existent buffer segment");
592 return -1;
593 }
594 *pp = (const char *)self->b_ptr;
595 return self->b_size;
596}
597
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000598
599static PySequenceMethods buffer_as_sequence = {
600 (inquiry)buffer_length, /*sq_length*/
601 (binaryfunc)buffer_concat, /*sq_concat*/
602 (intargfunc)buffer_repeat, /*sq_repeat*/
603 (intargfunc)buffer_item, /*sq_item*/
604 (intintargfunc)buffer_slice, /*sq_slice*/
605 (intobjargproc)buffer_ass_item, /*sq_ass_item*/
606 (intintobjargproc)buffer_ass_slice, /*sq_ass_slice*/
607};
608
609static PyBufferProcs buffer_as_buffer = {
610 (getreadbufferproc)buffer_getreadbuf,
611 (getwritebufferproc)buffer_getwritebuf,
612 (getsegcountproc)buffer_getsegcount,
Guido van Rossum1db70701998-10-08 02:18:52 +0000613 (getcharbufferproc)buffer_getcharbuf,
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000614};
615
616PyTypeObject PyBuffer_Type = {
617 PyObject_HEAD_INIT(&PyType_Type)
618 0,
619 "buffer",
620 sizeof(PyBufferObject),
621 0,
622 (destructor)buffer_dealloc, /*tp_dealloc*/
623 0, /*tp_print*/
624 0, /*tp_getattr*/
625 0, /*tp_setattr*/
626 (cmpfunc)buffer_compare, /*tp_compare*/
627 (reprfunc)buffer_repr, /*tp_repr*/
628 0, /*tp_as_number*/
629 &buffer_as_sequence, /*tp_as_sequence*/
630 0, /*tp_as_mapping*/
631 (hashfunc)buffer_hash, /*tp_hash*/
632 0, /*tp_call*/
633 (reprfunc)buffer_str, /*tp_str*/
634 0, /*tp_getattro*/
635 0, /*tp_setattro*/
636 &buffer_as_buffer, /*tp_as_buffer*/
Guido van Rossum1db70701998-10-08 02:18:52 +0000637 Py_TPFLAGS_DEFAULT, /*tp_flags*/
Guido van Rossum2e19bd71998-10-07 14:36:10 +0000638 0, /*tp_doc*/
639};
640