1 //--------------------------------------------------------------------------
2 
wxPyGetMethod(PyObject * py,char * name)3 static PyObject* wxPyGetMethod(PyObject* py, char* name)
4 {
5     if (!PyObject_HasAttrString(py, name))
6         return NULL;
7     PyObject* o = PyObject_GetAttrString(py, name);
8     if (!PyMethod_Check(o) && !PyCFunction_Check(o)) {
9         Py_DECREF(o);
10         return NULL;
11     }
12     return o;
13 }
14 
15 #define wxPyBlock_t_default PyGILState_UNLOCKED
16 
17 
18 // This class can wrap a Python file-like object and allow it to be used
19 // as a wxInputStream.
20 class wxPyOutputStream : public wxOutputStream
21 {
22 public:
23 
24     // Make sure there is at least a write method
Check(PyObject * fileObj)25     static bool Check(PyObject* fileObj)
26     {
27         PyObject* method = wxPyGetMethod(fileObj, "write");
28         bool rval = method != NULL;
29         Py_XDECREF(method);
30         return rval;
31     }
32 
wxPyOutputStream(PyObject * fileObj,bool block=true)33     wxPyOutputStream(PyObject* fileObj, bool block=true)
34     {
35         m_block = block;
36         wxPyThreadBlocker blocker(m_block);
37 
38         m_write = wxPyGetMethod(fileObj, "write");
39         m_seek = wxPyGetMethod(fileObj, "seek");
40         m_tell = wxPyGetMethod(fileObj, "tell");
41     }
42 
~wxPyOutputStream()43     virtual ~wxPyOutputStream()
44     {
45         wxPyThreadBlocker blocker(m_block);
46         Py_XDECREF(m_write);
47         Py_XDECREF(m_seek);
48         Py_XDECREF(m_tell);
49     }
50 
wxPyOutputStream(const wxPyOutputStream & other)51     wxPyOutputStream(const wxPyOutputStream& other)
52     {
53         wxPyThreadBlocker blocker;
54         m_write  = other.m_write;
55         m_seek  = other.m_seek;
56         m_tell  = other.m_tell;
57         m_block = other.m_block;
58         Py_INCREF(m_write);
59         Py_INCREF(m_seek);
60         Py_INCREF(m_tell);
61     }
62 
63 protected:
64 
65     // implement base class virtuals
66 
GetLength() const67     wxFileOffset GetLength() const
68     {
69         wxPyOutputStream* self = (wxPyOutputStream*)this; // cast off const
70         if (m_seek && m_tell) {
71             wxFileOffset temp = self->OnSysTell();
72             wxFileOffset ret = self->OnSysSeek(0, wxFromEnd);
73             self->OnSysSeek(temp, wxFromStart);
74             return ret;
75         }
76         else
77             return wxInvalidOffset;
78     }
79 
OnSysRead(void * buffer,size_t bufsize)80     size_t OnSysRead(void *buffer, size_t bufsize)
81     {
82         m_lasterror = wxSTREAM_READ_ERROR;
83         return 0;
84     }
85 
OnSysWrite(const void * buffer,size_t bufsize)86     size_t OnSysWrite(const void *buffer, size_t bufsize)
87     {
88         if (bufsize == 0)
89             return 0;
90 
91         wxPyThreadBlocker blocker;
92         PyObject* arglist = PyTuple_New(1);
93         PyTuple_SET_ITEM(arglist, 0, PyBytes_FromStringAndSize((char*)buffer, bufsize));
94 
95         PyObject* result = PyEval_CallObject(m_write, arglist);
96         Py_DECREF(arglist);
97 
98         if (result != NULL)
99             Py_DECREF(result);
100         else
101             m_lasterror = wxSTREAM_WRITE_ERROR;
102         return bufsize;
103     }
104 
OnSysSeek(wxFileOffset off,wxSeekMode mode)105     wxFileOffset OnSysSeek(wxFileOffset off, wxSeekMode mode)
106     {
107         wxPyThreadBlocker blocker;
108         PyObject* arglist = PyTuple_New(2);
109 
110         if (sizeof(wxFileOffset) > sizeof(long))
111             // wxFileOffset is a 64-bit value...
112             PyTuple_SET_ITEM(arglist, 0, PyLong_FromLongLong(off));
113         else
114             PyTuple_SET_ITEM(arglist, 0, wxPyInt_FromLong(off));
115 
116         PyTuple_SET_ITEM(arglist, 1, wxPyInt_FromLong(mode));
117 
118 
119         PyObject* result = PyEval_CallObject(m_seek, arglist);
120         Py_DECREF(arglist);
121         Py_XDECREF(result);
122         return OnSysTell();
123     }
124 
OnSysTell() const125     wxFileOffset OnSysTell() const
126     {
127         wxPyThreadBlocker blocker;
128         PyObject* arglist = Py_BuildValue("()");
129         PyObject* result = PyEval_CallObject(m_tell, arglist);
130         Py_DECREF(arglist);
131         wxFileOffset o = 0;
132         if (result != NULL) {
133             if (PyLong_Check(result))
134                 o = PyLong_AsLongLong(result);
135             else
136                 o = wxPyInt_AsLong(result);
137             Py_DECREF(result);
138         };
139         return o;
140     }
141 
IsSeekable() const142     bool IsSeekable() const
143     {
144         return (m_seek != NULL);
145     }
146 
147 private:
148     PyObject* m_write;
149     PyObject* m_seek;
150     PyObject* m_tell;
151     bool      m_block;
152 };
153 
154 //--------------------------------------------------------------------------
155