1 |
|
---|
2 | /* Buffer object implementation */
|
---|
3 |
|
---|
4 | #include "Python.h"
|
---|
5 |
|
---|
6 |
|
---|
7 | typedef struct {
|
---|
8 | PyObject_HEAD
|
---|
9 | PyObject *b_base;
|
---|
10 | void *b_ptr;
|
---|
11 | Py_ssize_t b_size;
|
---|
12 | Py_ssize_t b_offset;
|
---|
13 | int b_readonly;
|
---|
14 | long b_hash;
|
---|
15 | } PyBufferObject;
|
---|
16 |
|
---|
17 |
|
---|
18 | enum buffer_t {
|
---|
19 | READ_BUFFER,
|
---|
20 | WRITE_BUFFER,
|
---|
21 | CHAR_BUFFER,
|
---|
22 | ANY_BUFFER,
|
---|
23 | };
|
---|
24 |
|
---|
25 | static int
|
---|
26 | get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size,
|
---|
27 | enum buffer_t buffer_type)
|
---|
28 | {
|
---|
29 | if (self->b_base == NULL) {
|
---|
30 | assert (ptr != NULL);
|
---|
31 | *ptr = self->b_ptr;
|
---|
32 | *size = self->b_size;
|
---|
33 | }
|
---|
34 | else {
|
---|
35 | Py_ssize_t count, offset;
|
---|
36 | readbufferproc proc = 0;
|
---|
37 | PyBufferProcs *bp = self->b_base->ob_type->tp_as_buffer;
|
---|
38 | if ((*bp->bf_getsegcount)(self->b_base, NULL) != 1) {
|
---|
39 | PyErr_SetString(PyExc_TypeError,
|
---|
40 | "single-segment buffer object expected");
|
---|
41 | return 0;
|
---|
42 | }
|
---|
43 | if ((buffer_type == READ_BUFFER) ||
|
---|
44 | ((buffer_type == ANY_BUFFER) && self->b_readonly))
|
---|
45 | proc = bp->bf_getreadbuffer;
|
---|
46 | else if ((buffer_type == WRITE_BUFFER) ||
|
---|
47 | (buffer_type == ANY_BUFFER))
|
---|
48 | proc = (readbufferproc)bp->bf_getwritebuffer;
|
---|
49 | else if (buffer_type == CHAR_BUFFER) {
|
---|
50 | if (!PyType_HasFeature(self->ob_type,
|
---|
51 | Py_TPFLAGS_HAVE_GETCHARBUFFER)) {
|
---|
52 | PyErr_SetString(PyExc_TypeError,
|
---|
53 | "Py_TPFLAGS_HAVE_GETCHARBUFFER needed");
|
---|
54 | return 0;
|
---|
55 | }
|
---|
56 | proc = (readbufferproc)bp->bf_getcharbuffer;
|
---|
57 | }
|
---|
58 | if (!proc) {
|
---|
59 | char *buffer_type_name;
|
---|
60 | switch (buffer_type) {
|
---|
61 | case READ_BUFFER:
|
---|
62 | buffer_type_name = "read";
|
---|
63 | break;
|
---|
64 | case WRITE_BUFFER:
|
---|
65 | buffer_type_name = "write";
|
---|
66 | break;
|
---|
67 | case CHAR_BUFFER:
|
---|
68 | buffer_type_name = "char";
|
---|
69 | break;
|
---|
70 | default:
|
---|
71 | buffer_type_name = "no";
|
---|
72 | break;
|
---|
73 | }
|
---|
74 | PyErr_Format(PyExc_TypeError,
|
---|
75 | "%s buffer type not available",
|
---|
76 | buffer_type_name);
|
---|
77 | return 0;
|
---|
78 | }
|
---|
79 | if ((count = (*proc)(self->b_base, 0, ptr)) < 0)
|
---|
80 | return 0;
|
---|
81 | /* apply constraints to the start/end */
|
---|
82 | if (self->b_offset > count)
|
---|
83 | offset = count;
|
---|
84 | else
|
---|
85 | offset = self->b_offset;
|
---|
86 | *(char **)ptr = *(char **)ptr + offset;
|
---|
87 | if (self->b_size == Py_END_OF_BUFFER)
|
---|
88 | *size = count;
|
---|
89 | else
|
---|
90 | *size = self->b_size;
|
---|
91 | if (offset + *size > count)
|
---|
92 | *size = count - offset;
|
---|
93 | }
|
---|
94 | return 1;
|
---|
95 | }
|
---|
96 |
|
---|
97 |
|
---|
98 | static PyObject *
|
---|
99 | buffer_from_memory(PyObject *base, Py_ssize_t size, Py_ssize_t offset, void *ptr,
|
---|
100 | int readonly)
|
---|
101 | {
|
---|
102 | PyBufferObject * b;
|
---|
103 |
|
---|
104 | if (size < 0 && size != Py_END_OF_BUFFER) {
|
---|
105 | PyErr_SetString(PyExc_ValueError,
|
---|
106 | "size must be zero or positive");
|
---|
107 | return NULL;
|
---|
108 | }
|
---|
109 | if (offset < 0) {
|
---|
110 | PyErr_SetString(PyExc_ValueError,
|
---|
111 | "offset must be zero or positive");
|
---|
112 | return NULL;
|
---|
113 | }
|
---|
114 |
|
---|
115 | b = PyObject_NEW(PyBufferObject, &PyBuffer_Type);
|
---|
116 | if ( b == NULL )
|
---|
117 | return NULL;
|
---|
118 |
|
---|
119 | Py_XINCREF(base);
|
---|
120 | b->b_base = base;
|
---|
121 | b->b_ptr = ptr;
|
---|
122 | b->b_size = size;
|
---|
123 | b->b_offset = offset;
|
---|
124 | b->b_readonly = readonly;
|
---|
125 | b->b_hash = -1;
|
---|
126 |
|
---|
127 | return (PyObject *) b;
|
---|
128 | }
|
---|
129 |
|
---|
130 | static PyObject *
|
---|
131 | buffer_from_object(PyObject *base, Py_ssize_t size, Py_ssize_t offset, int readonly)
|
---|
132 | {
|
---|
133 | if (offset < 0) {
|
---|
134 | PyErr_SetString(PyExc_ValueError,
|
---|
135 | "offset must be zero or positive");
|
---|
136 | return NULL;
|
---|
137 | }
|
---|
138 | if ( PyBuffer_Check(base) && (((PyBufferObject *)base)->b_base) ) {
|
---|
139 | /* another buffer, refer to the base object */
|
---|
140 | PyBufferObject *b = (PyBufferObject *)base;
|
---|
141 | if (b->b_size != Py_END_OF_BUFFER) {
|
---|
142 | Py_ssize_t base_size = b->b_size - offset;
|
---|
143 | if (base_size < 0)
|
---|
144 | base_size = 0;
|
---|
145 | if (size == Py_END_OF_BUFFER || size > base_size)
|
---|
146 | size = base_size;
|
---|
147 | }
|
---|
148 | offset += b->b_offset;
|
---|
149 | base = b->b_base;
|
---|
150 | }
|
---|
151 | return buffer_from_memory(base, size, offset, NULL, readonly);
|
---|
152 | }
|
---|
153 |
|
---|
154 |
|
---|
155 | PyObject *
|
---|
156 | PyBuffer_FromObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
|
---|
157 | {
|
---|
158 | PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
---|
159 |
|
---|
160 | if ( pb == NULL ||
|
---|
161 | pb->bf_getreadbuffer == NULL ||
|
---|
162 | pb->bf_getsegcount == NULL )
|
---|
163 | {
|
---|
164 | PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
---|
165 | return NULL;
|
---|
166 | }
|
---|
167 |
|
---|
168 | return buffer_from_object(base, size, offset, 1);
|
---|
169 | }
|
---|
170 |
|
---|
171 | PyObject *
|
---|
172 | PyBuffer_FromReadWriteObject(PyObject *base, Py_ssize_t offset, Py_ssize_t size)
|
---|
173 | {
|
---|
174 | PyBufferProcs *pb = base->ob_type->tp_as_buffer;
|
---|
175 |
|
---|
176 | if ( pb == NULL ||
|
---|
177 | pb->bf_getwritebuffer == NULL ||
|
---|
178 | pb->bf_getsegcount == NULL )
|
---|
179 | {
|
---|
180 | PyErr_SetString(PyExc_TypeError, "buffer object expected");
|
---|
181 | return NULL;
|
---|
182 | }
|
---|
183 |
|
---|
184 | return buffer_from_object(base, size, offset, 0);
|
---|
185 | }
|
---|
186 |
|
---|
187 | PyObject *
|
---|
188 | PyBuffer_FromMemory(void *ptr, Py_ssize_t size)
|
---|
189 | {
|
---|
190 | return buffer_from_memory(NULL, size, 0, ptr, 1);
|
---|
191 | }
|
---|
192 |
|
---|
193 | PyObject *
|
---|
194 | PyBuffer_FromReadWriteMemory(void *ptr, Py_ssize_t size)
|
---|
195 | {
|
---|
196 | return buffer_from_memory(NULL, size, 0, ptr, 0);
|
---|
197 | }
|
---|
198 |
|
---|
199 | PyObject *
|
---|
200 | PyBuffer_New(Py_ssize_t size)
|
---|
201 | {
|
---|
202 | PyObject *o;
|
---|
203 | PyBufferObject * b;
|
---|
204 |
|
---|
205 | if (size < 0) {
|
---|
206 | PyErr_SetString(PyExc_ValueError,
|
---|
207 | "size must be zero or positive");
|
---|
208 | return NULL;
|
---|
209 | }
|
---|
210 | /* XXX: check for overflow in multiply */
|
---|
211 | /* Inline PyObject_New */
|
---|
212 | o = (PyObject *)PyObject_MALLOC(sizeof(*b) + size);
|
---|
213 | if ( o == NULL )
|
---|
214 | return PyErr_NoMemory();
|
---|
215 | b = (PyBufferObject *) PyObject_INIT(o, &PyBuffer_Type);
|
---|
216 |
|
---|
217 | b->b_base = NULL;
|
---|
218 | b->b_ptr = (void *)(b + 1);
|
---|
219 | b->b_size = size;
|
---|
220 | b->b_offset = 0;
|
---|
221 | b->b_readonly = 0;
|
---|
222 | b->b_hash = -1;
|
---|
223 |
|
---|
224 | return o;
|
---|
225 | }
|
---|
226 |
|
---|
227 | /* Methods */
|
---|
228 |
|
---|
229 | static PyObject *
|
---|
230 | buffer_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
---|
231 | {
|
---|
232 | PyObject *ob;
|
---|
233 | Py_ssize_t offset = 0;
|
---|
234 | Py_ssize_t size = Py_END_OF_BUFFER;
|
---|
235 |
|
---|
236 | if (!_PyArg_NoKeywords("buffer()", kw))
|
---|
237 | return NULL;
|
---|
238 |
|
---|
239 | if (!PyArg_ParseTuple(args, "O|nn:buffer", &ob, &offset, &size))
|
---|
240 | return NULL;
|
---|
241 | return PyBuffer_FromObject(ob, offset, size);
|
---|
242 | }
|
---|
243 |
|
---|
244 | PyDoc_STRVAR(buffer_doc,
|
---|
245 | "buffer(object [, offset[, size]])\n\
|
---|
246 | \n\
|
---|
247 | Create a new buffer object which references the given object.\n\
|
---|
248 | The buffer will reference a slice of the target object from the\n\
|
---|
249 | start of the object (or at the specified offset). The slice will\n\
|
---|
250 | extend to the end of the target object (or with the specified size).");
|
---|
251 |
|
---|
252 |
|
---|
253 | static void
|
---|
254 | buffer_dealloc(PyBufferObject *self)
|
---|
255 | {
|
---|
256 | Py_XDECREF(self->b_base);
|
---|
257 | PyObject_DEL(self);
|
---|
258 | }
|
---|
259 |
|
---|
260 | static int
|
---|
261 | buffer_compare(PyBufferObject *self, PyBufferObject *other)
|
---|
262 | {
|
---|
263 | void *p1, *p2;
|
---|
264 | Py_ssize_t len_self, len_other, min_len;
|
---|
265 | int cmp;
|
---|
266 |
|
---|
267 | if (!get_buf(self, &p1, &len_self, ANY_BUFFER))
|
---|
268 | return -1;
|
---|
269 | if (!get_buf(other, &p2, &len_other, ANY_BUFFER))
|
---|
270 | return -1;
|
---|
271 | min_len = (len_self < len_other) ? len_self : len_other;
|
---|
272 | if (min_len > 0) {
|
---|
273 | cmp = memcmp(p1, p2, min_len);
|
---|
274 | if (cmp != 0)
|
---|
275 | return cmp < 0 ? -1 : 1;
|
---|
276 | }
|
---|
277 | return (len_self < len_other) ? -1 : (len_self > len_other) ? 1 : 0;
|
---|
278 | }
|
---|
279 |
|
---|
280 | static PyObject *
|
---|
281 | buffer_repr(PyBufferObject *self)
|
---|
282 | {
|
---|
283 | const char *status = self->b_readonly ? "read-only" : "read-write";
|
---|
284 |
|
---|
285 | if ( self->b_base == NULL )
|
---|
286 | return PyString_FromFormat("<%s buffer ptr %p, size %zd at %p>",
|
---|
287 | status,
|
---|
288 | self->b_ptr,
|
---|
289 | self->b_size,
|
---|
290 | self);
|
---|
291 | else
|
---|
292 | return PyString_FromFormat(
|
---|
293 | "<%s buffer for %p, size %zd, offset %zd at %p>",
|
---|
294 | status,
|
---|
295 | self->b_base,
|
---|
296 | self->b_size,
|
---|
297 | self->b_offset,
|
---|
298 | self);
|
---|
299 | }
|
---|
300 |
|
---|
301 | static long
|
---|
302 | buffer_hash(PyBufferObject *self)
|
---|
303 | {
|
---|
304 | void *ptr;
|
---|
305 | Py_ssize_t size;
|
---|
306 | register Py_ssize_t len;
|
---|
307 | register unsigned char *p;
|
---|
308 | register long x;
|
---|
309 |
|
---|
310 | if ( self->b_hash != -1 )
|
---|
311 | return self->b_hash;
|
---|
312 |
|
---|
313 | /* XXX potential bugs here, a readonly buffer does not imply that the
|
---|
314 | * underlying memory is immutable. b_readonly is a necessary but not
|
---|
315 | * sufficient condition for a buffer to be hashable. Perhaps it would
|
---|
316 | * be better to only allow hashing if the underlying object is known to
|
---|
317 | * be immutable (e.g. PyString_Check() is true). Another idea would
|
---|
318 | * be to call tp_hash on the underlying object and see if it raises
|
---|
319 | * an error. */
|
---|
320 | if ( !self->b_readonly )
|
---|
321 | {
|
---|
322 | PyErr_SetString(PyExc_TypeError,
|
---|
323 | "writable buffers are not hashable");
|
---|
324 | return -1;
|
---|
325 | }
|
---|
326 |
|
---|
327 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
328 | return -1;
|
---|
329 | p = (unsigned char *) ptr;
|
---|
330 | len = size;
|
---|
331 | x = *p << 7;
|
---|
332 | while (--len >= 0)
|
---|
333 | x = (1000003*x) ^ *p++;
|
---|
334 | x ^= size;
|
---|
335 | if (x == -1)
|
---|
336 | x = -2;
|
---|
337 | self->b_hash = x;
|
---|
338 | return x;
|
---|
339 | }
|
---|
340 |
|
---|
341 | static PyObject *
|
---|
342 | buffer_str(PyBufferObject *self)
|
---|
343 | {
|
---|
344 | void *ptr;
|
---|
345 | Py_ssize_t size;
|
---|
346 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
347 | return NULL;
|
---|
348 | return PyString_FromStringAndSize((const char *)ptr, size);
|
---|
349 | }
|
---|
350 |
|
---|
351 | /* Sequence methods */
|
---|
352 |
|
---|
353 | static Py_ssize_t
|
---|
354 | buffer_length(PyBufferObject *self)
|
---|
355 | {
|
---|
356 | void *ptr;
|
---|
357 | Py_ssize_t size;
|
---|
358 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
359 | return -1;
|
---|
360 | return size;
|
---|
361 | }
|
---|
362 |
|
---|
363 | static PyObject *
|
---|
364 | buffer_concat(PyBufferObject *self, PyObject *other)
|
---|
365 | {
|
---|
366 | PyBufferProcs *pb = other->ob_type->tp_as_buffer;
|
---|
367 | void *ptr1, *ptr2;
|
---|
368 | char *p;
|
---|
369 | PyObject *ob;
|
---|
370 | Py_ssize_t size, count;
|
---|
371 |
|
---|
372 | if ( pb == NULL ||
|
---|
373 | pb->bf_getreadbuffer == NULL ||
|
---|
374 | pb->bf_getsegcount == NULL )
|
---|
375 | {
|
---|
376 | PyErr_BadArgument();
|
---|
377 | return NULL;
|
---|
378 | }
|
---|
379 | if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
---|
380 | {
|
---|
381 | /* ### use a different exception type/message? */
|
---|
382 | PyErr_SetString(PyExc_TypeError,
|
---|
383 | "single-segment buffer object expected");
|
---|
384 | return NULL;
|
---|
385 | }
|
---|
386 |
|
---|
387 | if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
---|
388 | return NULL;
|
---|
389 |
|
---|
390 | /* optimize special case */
|
---|
391 | if ( size == 0 )
|
---|
392 | {
|
---|
393 | Py_INCREF(other);
|
---|
394 | return other;
|
---|
395 | }
|
---|
396 |
|
---|
397 | if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
---|
398 | return NULL;
|
---|
399 |
|
---|
400 | ob = PyString_FromStringAndSize(NULL, size + count);
|
---|
401 | if ( ob == NULL )
|
---|
402 | return NULL;
|
---|
403 | p = PyString_AS_STRING(ob);
|
---|
404 | memcpy(p, ptr1, size);
|
---|
405 | memcpy(p + size, ptr2, count);
|
---|
406 |
|
---|
407 | /* there is an extra byte in the string object, so this is safe */
|
---|
408 | p[size + count] = '\0';
|
---|
409 |
|
---|
410 | return ob;
|
---|
411 | }
|
---|
412 |
|
---|
413 | static PyObject *
|
---|
414 | buffer_repeat(PyBufferObject *self, Py_ssize_t count)
|
---|
415 | {
|
---|
416 | PyObject *ob;
|
---|
417 | register char *p;
|
---|
418 | void *ptr;
|
---|
419 | Py_ssize_t size;
|
---|
420 |
|
---|
421 | if ( count < 0 )
|
---|
422 | count = 0;
|
---|
423 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
424 | return NULL;
|
---|
425 | ob = PyString_FromStringAndSize(NULL, size * count);
|
---|
426 | if ( ob == NULL )
|
---|
427 | return NULL;
|
---|
428 |
|
---|
429 | p = PyString_AS_STRING(ob);
|
---|
430 | while ( count-- )
|
---|
431 | {
|
---|
432 | memcpy(p, ptr, size);
|
---|
433 | p += size;
|
---|
434 | }
|
---|
435 |
|
---|
436 | /* there is an extra byte in the string object, so this is safe */
|
---|
437 | *p = '\0';
|
---|
438 |
|
---|
439 | return ob;
|
---|
440 | }
|
---|
441 |
|
---|
442 | static PyObject *
|
---|
443 | buffer_item(PyBufferObject *self, Py_ssize_t idx)
|
---|
444 | {
|
---|
445 | void *ptr;
|
---|
446 | Py_ssize_t size;
|
---|
447 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
448 | return NULL;
|
---|
449 | if ( idx < 0 || idx >= size ) {
|
---|
450 | PyErr_SetString(PyExc_IndexError, "buffer index out of range");
|
---|
451 | return NULL;
|
---|
452 | }
|
---|
453 | return PyString_FromStringAndSize((char *)ptr + idx, 1);
|
---|
454 | }
|
---|
455 |
|
---|
456 | static PyObject *
|
---|
457 | buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
|
---|
458 | {
|
---|
459 | void *ptr;
|
---|
460 | Py_ssize_t size;
|
---|
461 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
462 | return NULL;
|
---|
463 | if ( left < 0 )
|
---|
464 | left = 0;
|
---|
465 | if ( right < 0 )
|
---|
466 | right = 0;
|
---|
467 | if ( right > size )
|
---|
468 | right = size;
|
---|
469 | if ( right < left )
|
---|
470 | right = left;
|
---|
471 | return PyString_FromStringAndSize((char *)ptr + left,
|
---|
472 | right - left);
|
---|
473 | }
|
---|
474 |
|
---|
475 | static int
|
---|
476 | buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
|
---|
477 | {
|
---|
478 | PyBufferProcs *pb;
|
---|
479 | void *ptr1, *ptr2;
|
---|
480 | Py_ssize_t size;
|
---|
481 | Py_ssize_t count;
|
---|
482 |
|
---|
483 | if ( self->b_readonly ) {
|
---|
484 | PyErr_SetString(PyExc_TypeError,
|
---|
485 | "buffer is read-only");
|
---|
486 | return -1;
|
---|
487 | }
|
---|
488 |
|
---|
489 | if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
---|
490 | return -1;
|
---|
491 |
|
---|
492 | if (idx < 0 || idx >= size) {
|
---|
493 | PyErr_SetString(PyExc_IndexError,
|
---|
494 | "buffer assignment index out of range");
|
---|
495 | return -1;
|
---|
496 | }
|
---|
497 |
|
---|
498 | pb = other ? other->ob_type->tp_as_buffer : NULL;
|
---|
499 | if ( pb == NULL ||
|
---|
500 | pb->bf_getreadbuffer == NULL ||
|
---|
501 | pb->bf_getsegcount == NULL )
|
---|
502 | {
|
---|
503 | PyErr_BadArgument();
|
---|
504 | return -1;
|
---|
505 | }
|
---|
506 | if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
---|
507 | {
|
---|
508 | /* ### use a different exception type/message? */
|
---|
509 | PyErr_SetString(PyExc_TypeError,
|
---|
510 | "single-segment buffer object expected");
|
---|
511 | return -1;
|
---|
512 | }
|
---|
513 |
|
---|
514 | if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
---|
515 | return -1;
|
---|
516 | if ( count != 1 ) {
|
---|
517 | PyErr_SetString(PyExc_TypeError,
|
---|
518 | "right operand must be a single byte");
|
---|
519 | return -1;
|
---|
520 | }
|
---|
521 |
|
---|
522 | ((char *)ptr1)[idx] = *(char *)ptr2;
|
---|
523 | return 0;
|
---|
524 | }
|
---|
525 |
|
---|
526 | static int
|
---|
527 | buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObject *other)
|
---|
528 | {
|
---|
529 | PyBufferProcs *pb;
|
---|
530 | void *ptr1, *ptr2;
|
---|
531 | Py_ssize_t size;
|
---|
532 | Py_ssize_t slice_len;
|
---|
533 | Py_ssize_t count;
|
---|
534 |
|
---|
535 | if ( self->b_readonly ) {
|
---|
536 | PyErr_SetString(PyExc_TypeError,
|
---|
537 | "buffer is read-only");
|
---|
538 | return -1;
|
---|
539 | }
|
---|
540 |
|
---|
541 | pb = other ? other->ob_type->tp_as_buffer : NULL;
|
---|
542 | if ( pb == NULL ||
|
---|
543 | pb->bf_getreadbuffer == NULL ||
|
---|
544 | pb->bf_getsegcount == NULL )
|
---|
545 | {
|
---|
546 | PyErr_BadArgument();
|
---|
547 | return -1;
|
---|
548 | }
|
---|
549 | if ( (*pb->bf_getsegcount)(other, NULL) != 1 )
|
---|
550 | {
|
---|
551 | /* ### use a different exception type/message? */
|
---|
552 | PyErr_SetString(PyExc_TypeError,
|
---|
553 | "single-segment buffer object expected");
|
---|
554 | return -1;
|
---|
555 | }
|
---|
556 | if (!get_buf(self, &ptr1, &size, ANY_BUFFER))
|
---|
557 | return -1;
|
---|
558 | if ( (count = (*pb->bf_getreadbuffer)(other, 0, &ptr2)) < 0 )
|
---|
559 | return -1;
|
---|
560 |
|
---|
561 | if ( left < 0 )
|
---|
562 | left = 0;
|
---|
563 | else if ( left > size )
|
---|
564 | left = size;
|
---|
565 | if ( right < left )
|
---|
566 | right = left;
|
---|
567 | else if ( right > size )
|
---|
568 | right = size;
|
---|
569 | slice_len = right - left;
|
---|
570 |
|
---|
571 | if ( count != slice_len ) {
|
---|
572 | PyErr_SetString(
|
---|
573 | PyExc_TypeError,
|
---|
574 | "right operand length must match slice length");
|
---|
575 | return -1;
|
---|
576 | }
|
---|
577 |
|
---|
578 | if ( slice_len )
|
---|
579 | memcpy((char *)ptr1 + left, ptr2, slice_len);
|
---|
580 |
|
---|
581 | return 0;
|
---|
582 | }
|
---|
583 |
|
---|
584 | /* Buffer methods */
|
---|
585 |
|
---|
586 | static Py_ssize_t
|
---|
587 | buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
|
---|
588 | {
|
---|
589 | Py_ssize_t size;
|
---|
590 | if ( idx != 0 ) {
|
---|
591 | PyErr_SetString(PyExc_SystemError,
|
---|
592 | "accessing non-existent buffer segment");
|
---|
593 | return -1;
|
---|
594 | }
|
---|
595 | if (!get_buf(self, pp, &size, READ_BUFFER))
|
---|
596 | return -1;
|
---|
597 | return size;
|
---|
598 | }
|
---|
599 |
|
---|
600 | static Py_ssize_t
|
---|
601 | buffer_getwritebuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
|
---|
602 | {
|
---|
603 | Py_ssize_t size;
|
---|
604 |
|
---|
605 | if ( self->b_readonly )
|
---|
606 | {
|
---|
607 | PyErr_SetString(PyExc_TypeError, "buffer is read-only");
|
---|
608 | return -1;
|
---|
609 | }
|
---|
610 |
|
---|
611 | if ( idx != 0 ) {
|
---|
612 | PyErr_SetString(PyExc_SystemError,
|
---|
613 | "accessing non-existent buffer segment");
|
---|
614 | return -1;
|
---|
615 | }
|
---|
616 | if (!get_buf(self, pp, &size, WRITE_BUFFER))
|
---|
617 | return -1;
|
---|
618 | return size;
|
---|
619 | }
|
---|
620 |
|
---|
621 | static Py_ssize_t
|
---|
622 | buffer_getsegcount(PyBufferObject *self, Py_ssize_t *lenp)
|
---|
623 | {
|
---|
624 | void *ptr;
|
---|
625 | Py_ssize_t size;
|
---|
626 | if (!get_buf(self, &ptr, &size, ANY_BUFFER))
|
---|
627 | return -1;
|
---|
628 | if (lenp)
|
---|
629 | *lenp = size;
|
---|
630 | return 1;
|
---|
631 | }
|
---|
632 |
|
---|
633 | static Py_ssize_t
|
---|
634 | buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
|
---|
635 | {
|
---|
636 | void *ptr;
|
---|
637 | Py_ssize_t size;
|
---|
638 | if ( idx != 0 ) {
|
---|
639 | PyErr_SetString(PyExc_SystemError,
|
---|
640 | "accessing non-existent buffer segment");
|
---|
641 | return -1;
|
---|
642 | }
|
---|
643 | if (!get_buf(self, &ptr, &size, CHAR_BUFFER))
|
---|
644 | return -1;
|
---|
645 | *pp = (const char *)ptr;
|
---|
646 | return size;
|
---|
647 | }
|
---|
648 |
|
---|
649 | static PySequenceMethods buffer_as_sequence = {
|
---|
650 | (lenfunc)buffer_length, /*sq_length*/
|
---|
651 | (binaryfunc)buffer_concat, /*sq_concat*/
|
---|
652 | (ssizeargfunc)buffer_repeat, /*sq_repeat*/
|
---|
653 | (ssizeargfunc)buffer_item, /*sq_item*/
|
---|
654 | (ssizessizeargfunc)buffer_slice, /*sq_slice*/
|
---|
655 | (ssizeobjargproc)buffer_ass_item, /*sq_ass_item*/
|
---|
656 | (ssizessizeobjargproc)buffer_ass_slice, /*sq_ass_slice*/
|
---|
657 | };
|
---|
658 |
|
---|
659 | static PyBufferProcs buffer_as_buffer = {
|
---|
660 | (readbufferproc)buffer_getreadbuf,
|
---|
661 | (writebufferproc)buffer_getwritebuf,
|
---|
662 | (segcountproc)buffer_getsegcount,
|
---|
663 | (charbufferproc)buffer_getcharbuf,
|
---|
664 | };
|
---|
665 |
|
---|
666 | PyTypeObject PyBuffer_Type = {
|
---|
667 | PyObject_HEAD_INIT(&PyType_Type)
|
---|
668 | 0,
|
---|
669 | "buffer",
|
---|
670 | sizeof(PyBufferObject),
|
---|
671 | 0,
|
---|
672 | (destructor)buffer_dealloc, /* tp_dealloc */
|
---|
673 | 0, /* tp_print */
|
---|
674 | 0, /* tp_getattr */
|
---|
675 | 0, /* tp_setattr */
|
---|
676 | (cmpfunc)buffer_compare, /* tp_compare */
|
---|
677 | (reprfunc)buffer_repr, /* tp_repr */
|
---|
678 | 0, /* tp_as_number */
|
---|
679 | &buffer_as_sequence, /* tp_as_sequence */
|
---|
680 | 0, /* tp_as_mapping */
|
---|
681 | (hashfunc)buffer_hash, /* tp_hash */
|
---|
682 | 0, /* tp_call */
|
---|
683 | (reprfunc)buffer_str, /* tp_str */
|
---|
684 | PyObject_GenericGetAttr, /* tp_getattro */
|
---|
685 | 0, /* tp_setattro */
|
---|
686 | &buffer_as_buffer, /* tp_as_buffer */
|
---|
687 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER, /* tp_flags */
|
---|
688 | buffer_doc, /* tp_doc */
|
---|
689 | 0, /* tp_traverse */
|
---|
690 | 0, /* tp_clear */
|
---|
691 | 0, /* tp_richcompare */
|
---|
692 | 0, /* tp_weaklistoffset */
|
---|
693 | 0, /* tp_iter */
|
---|
694 | 0, /* tp_iternext */
|
---|
695 | 0, /* tp_methods */
|
---|
696 | 0, /* tp_members */
|
---|
697 | 0, /* tp_getset */
|
---|
698 | 0, /* tp_base */
|
---|
699 | 0, /* tp_dict */
|
---|
700 | 0, /* tp_descr_get */
|
---|
701 | 0, /* tp_descr_set */
|
---|
702 | 0, /* tp_dictoffset */
|
---|
703 | 0, /* tp_init */
|
---|
704 | 0, /* tp_alloc */
|
---|
705 | buffer_new, /* tp_new */
|
---|
706 | };
|
---|