1 //--------------------------------------------------------------------------
2 // Name:        src/wxpybuffer.h
3 // Purpose:     A simple class to hold a pointer and a size.  See
4 //              wxpybuffer.sip for code that converts from a Python buffer
5 //              object as a MappedType.
6 //
7 // Author:      Robin Dunn
8 //
9 // Created:     26-Apr-2012
10 // Copyright:   (c) 2012-2018 by Total Control Software
11 // Licence:     wxWindows license
12 //--------------------------------------------------------------------------
13 
14 #ifndef WXPYBUFFER_H
15 #define WXPYBUFFER_H
16 
17 // TODO: When support for Python2 is dropped then look into changing this
18 // class such that it holds on to the Py_buffer view object for the lifetime of
19 // the wxPyBuffer object. This could help with cases where the buffer is
20 // attempted to be accessed when the source object has already been gc'd.
21 
22 class wxPyBuffer
23 {
24 public:
wxPyBuffer()25     wxPyBuffer() : m_ptr(NULL), m_len(0) {}
26 
27     // Initialize this object's pointer and length from a PyObject supporting
28     // the Python buffer protocol.  Raises a TypeError if the object can not
29     // be used as a buffer.
create(PyObject * obj)30     bool create(PyObject* obj) {
31         #if PY_MAJOR_VERSION < 3
32             // Old buffer protocol
33             int rv = PyObject_AsReadBuffer(obj, (const void**)&m_ptr, &m_len);
34             return rv != -1;
35         #else
36             // New buffer protocol
37             Py_buffer view;
38             if (PyObject_GetBuffer(obj, &view, PyBUF_SIMPLE) != 0)
39                 return false;
40             m_ptr = view.buf;
41             m_len = view.len;
42             PyBuffer_Release(&view);
43             return true;
44         #endif
45     }
46 
47 
48     // Ensure that the buffer's size is the expected size.  Raises a
49     // Python ValueError exception and returns false if not.
checkSize(Py_ssize_t expectedSize)50     bool checkSize(Py_ssize_t expectedSize) {
51         if (m_len < expectedSize) {
52             wxPyErr_SetString(PyExc_ValueError, "Invalid data buffer size.");
53             return false;
54         }
55         return true;
56     }
57 
58     // Make a simple C copy of the data buffer.  Malloc is used because
59     // the wxAPIs this is used with will later free() the pointer.  Raises
60     // a Python exception if there is an allocation error.
copy()61     void* copy() {
62         void* ptr = malloc(m_len);
63         if (ptr == NULL) {
64             wxPyBLOCK_THREADS(PyErr_NoMemory());
65             return NULL;
66         }
67         memcpy(ptr, m_ptr, m_len);
68         return ptr;
69     }
70 
71     void*       m_ptr;
72     Py_ssize_t  m_len;
73 };
74 
75 #endif
76 //--------------------------------------------------------------------------
77