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