@@ -15,8 +15,16 @@ typedef struct {
1515} PyBufferObject ;
1616
1717
18+ enum buffer_t {
19+ READBUFFER ,
20+ WRITEBUFFER ,
21+ CHARBUFFER ,
22+ ANY_BUFFER ,
23+ };
24+
1825static int
19- get_buf (PyBufferObject * self , void * * ptr , Py_ssize_t * size )
26+ get_buf (PyBufferObject * self , void * * ptr , Py_ssize_t * size ,
27+ enum buffer_t buffer_type )
2028{
2129 if (self -> b_base == NULL ) {
2230 assert (ptr != NULL );
@@ -32,10 +40,42 @@ get_buf(PyBufferObject *self, void **ptr, Py_ssize_t *size)
3240 "single-segment buffer object expected" );
3341 return 0 ;
3442 }
35- if (self -> b_readonly )
36- proc = bp -> bf_getreadbuffer ;
37- else
38- proc = (readbufferproc )bp -> bf_getwritebuffer ;
43+ if ((buffer_type == READBUFFER ) ||
44+ ((buffer_type == ANY_BUFFER ) && self -> b_readonly ))
45+ proc = bp -> bf_getreadbuffer ;
46+ else if ((buffer_type == WRITEBUFFER ) ||
47+ (buffer_type == ANY_BUFFER ))
48+ proc = (readbufferproc )bp -> bf_getwritebuffer ;
49+ else if (buffer_type == CHARBUFFER ) {
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 READBUFFER :
62+ buffer_type_name = "read" ;
63+ break ;
64+ case WRITEBUFFER :
65+ buffer_type_name = "write" ;
66+ break ;
67+ case CHARBUFFER :
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+ }
3979 if ((count = (* proc )(self -> b_base , 0 , ptr )) < 0 )
4080 return 0 ;
4181 /* apply constraints to the start/end */
@@ -224,9 +264,9 @@ buffer_compare(PyBufferObject *self, PyBufferObject *other)
224264 Py_ssize_t len_self , len_other , min_len ;
225265 int cmp ;
226266
227- if (!get_buf (self , & p1 , & len_self ))
267+ if (!get_buf (self , & p1 , & len_self , ANY_BUFFER ))
228268 return -1 ;
229- if (!get_buf (other , & p2 , & len_other ))
269+ if (!get_buf (other , & p2 , & len_other , ANY_BUFFER ))
230270 return -1 ;
231271 min_len = (len_self < len_other ) ? len_self : len_other ;
232272 if (min_len > 0 ) {
@@ -284,7 +324,7 @@ buffer_hash(PyBufferObject *self)
284324 return -1 ;
285325 }
286326
287- if (!get_buf (self , & ptr , & size ))
327+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
288328 return -1 ;
289329 p = (unsigned char * ) ptr ;
290330 len = size ;
@@ -303,7 +343,7 @@ buffer_str(PyBufferObject *self)
303343{
304344 void * ptr ;
305345 Py_ssize_t size ;
306- if (!get_buf (self , & ptr , & size ))
346+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
307347 return NULL ;
308348 return PyString_FromStringAndSize ((const char * )ptr , size );
309349}
@@ -315,7 +355,7 @@ buffer_length(PyBufferObject *self)
315355{
316356 void * ptr ;
317357 Py_ssize_t size ;
318- if (!get_buf (self , & ptr , & size ))
358+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
319359 return -1 ;
320360 return size ;
321361}
@@ -344,7 +384,7 @@ buffer_concat(PyBufferObject *self, PyObject *other)
344384 return NULL ;
345385 }
346386
347- if (!get_buf (self , & ptr1 , & size ))
387+ if (!get_buf (self , & ptr1 , & size , ANY_BUFFER ))
348388 return NULL ;
349389
350390 /* optimize special case */
@@ -380,7 +420,7 @@ buffer_repeat(PyBufferObject *self, Py_ssize_t count)
380420
381421 if ( count < 0 )
382422 count = 0 ;
383- if (!get_buf (self , & ptr , & size ))
423+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
384424 return NULL ;
385425 ob = PyString_FromStringAndSize (NULL , size * count );
386426 if ( ob == NULL )
@@ -404,7 +444,7 @@ buffer_item(PyBufferObject *self, Py_ssize_t idx)
404444{
405445 void * ptr ;
406446 Py_ssize_t size ;
407- if (!get_buf (self , & ptr , & size ))
447+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
408448 return NULL ;
409449 if ( idx < 0 || idx >= size ) {
410450 PyErr_SetString (PyExc_IndexError , "buffer index out of range" );
@@ -418,7 +458,7 @@ buffer_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right)
418458{
419459 void * ptr ;
420460 Py_ssize_t size ;
421- if (!get_buf (self , & ptr , & size ))
461+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
422462 return NULL ;
423463 if ( left < 0 )
424464 left = 0 ;
@@ -446,7 +486,7 @@ buffer_ass_item(PyBufferObject *self, Py_ssize_t idx, PyObject *other)
446486 return -1 ;
447487 }
448488
449- if (!get_buf (self , & ptr1 , & size ))
489+ if (!get_buf (self , & ptr1 , & size , ANY_BUFFER ))
450490 return -1 ;
451491
452492 if (idx < 0 || idx >= size ) {
@@ -513,7 +553,7 @@ buffer_ass_slice(PyBufferObject *self, Py_ssize_t left, Py_ssize_t right, PyObje
513553 "single-segment buffer object expected" );
514554 return -1 ;
515555 }
516- if (!get_buf (self , & ptr1 , & size ))
556+ if (!get_buf (self , & ptr1 , & size , ANY_BUFFER ))
517557 return -1 ;
518558 if ( (count = (* pb -> bf_getreadbuffer )(other , 0 , & ptr2 )) < 0 )
519559 return -1 ;
@@ -552,28 +592,38 @@ buffer_getreadbuf(PyBufferObject *self, Py_ssize_t idx, void **pp)
552592 "accessing non-existent buffer segment" );
553593 return -1 ;
554594 }
555- if (!get_buf (self , pp , & size ))
595+ if (!get_buf (self , pp , & size , READBUFFER ))
556596 return -1 ;
557597 return size ;
558598}
559599
560600static Py_ssize_t
561601buffer_getwritebuf (PyBufferObject * self , Py_ssize_t idx , void * * pp )
562602{
603+ Py_ssize_t size ;
604+
563605 if ( self -> b_readonly )
564606 {
565607 PyErr_SetString (PyExc_TypeError , "buffer is read-only" );
566608 return -1 ;
567609 }
568- return buffer_getreadbuf (self , idx , pp );
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 , WRITEBUFFER ))
617+ return -1 ;
618+ return size ;
569619}
570620
571621static Py_ssize_t
572622buffer_getsegcount (PyBufferObject * self , Py_ssize_t * lenp )
573623{
574624 void * ptr ;
575625 Py_ssize_t size ;
576- if (!get_buf (self , & ptr , & size ))
626+ if (!get_buf (self , & ptr , & size , ANY_BUFFER ))
577627 return -1 ;
578628 if (lenp )
579629 * lenp = size ;
@@ -590,13 +640,12 @@ buffer_getcharbuf(PyBufferObject *self, Py_ssize_t idx, const char **pp)
590640 "accessing non-existent buffer segment" );
591641 return -1 ;
592642 }
593- if (!get_buf (self , & ptr , & size ))
643+ if (!get_buf (self , & ptr , & size , CHARBUFFER ))
594644 return -1 ;
595645 * pp = (const char * )ptr ;
596646 return size ;
597647}
598648
599-
600649static PySequenceMethods buffer_as_sequence = {
601650 (lenfunc )buffer_length , /*sq_length*/
602651 (binaryfunc )buffer_concat , /*sq_concat*/
@@ -635,7 +684,7 @@ PyTypeObject PyBuffer_Type = {
635684 PyObject_GenericGetAttr , /* tp_getattro */
636685 0 , /* tp_setattro */
637686 & buffer_as_buffer , /* tp_as_buffer */
638- Py_TPFLAGS_DEFAULT , /* tp_flags */
687+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER , /* tp_flags */
639688 buffer_doc , /* tp_doc */
640689 0 , /* tp_traverse */
641690 0 , /* tp_clear */
0 commit comments