1 
2 /* Map C struct members to Python object attributes */
3 
4 #include "Python.h"
5 
6 #include "structmember.h"
7 
8 static PyObject *
listmembers(struct memberlist * mlist)9 listmembers(struct memberlist *mlist)
10 {
11     int i, n;
12     PyObject *v;
13     for (n = 0; mlist[n].name != NULL; n++)
14         ;
15     v = PyList_New(n);
16     if (v != NULL) {
17         for (i = 0; i < n; i++)
18             PyList_SetItem(v, i,
19                            PyString_FromString(mlist[i].name));
20         if (PyErr_Occurred()) {
21             Py_DECREF(v);
22             v = NULL;
23         }
24         else {
25             PyList_Sort(v);
26         }
27     }
28     return v;
29 }
30 
31 PyObject *
PyMember_Get(const char * addr,struct memberlist * mlist,const char * name)32 PyMember_Get(const char *addr, struct memberlist *mlist, const char *name)
33 {
34     struct memberlist *l;
35 
36     if (strcmp(name, "__members__") == 0)
37         return listmembers(mlist);
38     for (l = mlist; l->name != NULL; l++) {
39         if (strcmp(l->name, name) == 0) {
40             PyMemberDef copy;
41             copy.name = l->name;
42             copy.type = l->type;
43             copy.offset = l->offset;
44             copy.flags = l->flags;
45             copy.doc = NULL;
46             return PyMember_GetOne(addr, &copy);
47         }
48     }
49     PyErr_SetString(PyExc_AttributeError, name);
50     return NULL;
51 }
52 
53 PyObject *
PyMember_GetOne(const char * addr,PyMemberDef * l)54 PyMember_GetOne(const char *addr, PyMemberDef *l)
55 {
56     PyObject *v;
57     if ((l->flags & READ_RESTRICTED) &&
58         PyEval_GetRestricted()) {
59         PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
60         return NULL;
61     }
62     addr += l->offset;
63     switch (l->type) {
64     case T_BOOL:
65         v = PyBool_FromLong(*(char*)addr);
66         break;
67     case T_BYTE:
68         v = PyInt_FromLong(*(char*)addr);
69         break;
70     case T_UBYTE:
71         v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
72         break;
73     case T_SHORT:
74         v = PyInt_FromLong(*(short*)addr);
75         break;
76     case T_USHORT:
77         v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
78         break;
79     case T_INT:
80         v = PyInt_FromLong(*(int*)addr);
81         break;
82     case T_UINT:
83         v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
84         break;
85     case T_LONG:
86         v = PyInt_FromLong(*(long*)addr);
87         break;
88     case T_ULONG:
89         v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
90         break;
91     case T_PYSSIZET:
92         v = PyInt_FromSsize_t(*(Py_ssize_t*)addr);
93         break;
94     case T_FLOAT:
95         v = PyFloat_FromDouble((double)*(float*)addr);
96         break;
97     case T_DOUBLE:
98         v = PyFloat_FromDouble(*(double*)addr);
99         break;
100     case T_STRING:
101         if (*(char**)addr == NULL) {
102             Py_INCREF(Py_None);
103             v = Py_None;
104         }
105         else
106             v = PyString_FromString(*(char**)addr);
107         break;
108     case T_STRING_INPLACE:
109         v = PyString_FromString((char*)addr);
110         break;
111     case T_CHAR:
112         v = PyString_FromStringAndSize((char*)addr, 1);
113         break;
114     case T_OBJECT:
115         v = *(PyObject **)addr;
116         if (v == NULL)
117             v = Py_None;
118         Py_INCREF(v);
119         break;
120     case T_OBJECT_EX:
121         v = *(PyObject **)addr;
122         if (v == NULL)
123             PyErr_SetString(PyExc_AttributeError, l->name);
124         Py_XINCREF(v);
125         break;
126 #ifdef HAVE_LONG_LONG
127     case T_LONGLONG:
128         v = PyLong_FromLongLong(*(PY_LONG_LONG *)addr);
129         break;
130     case T_ULONGLONG:
131         v = PyLong_FromUnsignedLongLong(*(unsigned PY_LONG_LONG *)addr);
132         break;
133 #endif /* HAVE_LONG_LONG */
134     default:
135         PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
136         v = NULL;
137     }
138     return v;
139 }
140 
141 int
PyMember_Set(char * addr,struct memberlist * mlist,const char * name,PyObject * v)142 PyMember_Set(char *addr, struct memberlist *mlist, const char *name, PyObject *v)
143 {
144     struct memberlist *l;
145 
146     for (l = mlist; l->name != NULL; l++) {
147         if (strcmp(l->name, name) == 0) {
148             PyMemberDef copy;
149             copy.name = l->name;
150             copy.type = l->type;
151             copy.offset = l->offset;
152             copy.flags = l->flags;
153             copy.doc = NULL;
154             return PyMember_SetOne(addr, &copy, v);
155         }
156     }
157 
158     PyErr_SetString(PyExc_AttributeError, name);
159     return -1;
160 }
161 
162 #define WARN(msg)                                       \
163     do {                                                \
164     if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0)      \
165         return -1;                                      \
166     } while (0)
167 
168 int
PyMember_SetOne(char * addr,PyMemberDef * l,PyObject * v)169 PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
170 {
171     PyObject *oldv;
172 
173     addr += l->offset;
174 
175     if ((l->flags & READONLY))
176     {
177         PyErr_SetString(PyExc_TypeError, "readonly attribute");
178         return -1;
179     }
180     if ((l->flags & PY_WRITE_RESTRICTED) && PyEval_GetRestricted()) {
181         PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
182         return -1;
183     }
184     if (v == NULL) {
185         if (l->type == T_OBJECT_EX) {
186             /* Check if the attribute is set. */
187             if (*(PyObject **)addr == NULL) {
188                 PyErr_SetString(PyExc_AttributeError, l->name);
189                 return -1;
190             }
191         }
192         else if (l->type != T_OBJECT) {
193             PyErr_SetString(PyExc_TypeError,
194                             "can't delete numeric/char attribute");
195             return -1;
196         }
197     }
198     switch (l->type) {
199     case T_BOOL:{
200         if (!PyBool_Check(v)) {
201             PyErr_SetString(PyExc_TypeError,
202                             "attribute value type must be bool");
203             return -1;
204         }
205         if (v == Py_True)
206             *(char*)addr = (char) 1;
207         else
208             *(char*)addr = (char) 0;
209         break;
210         }
211     case T_BYTE:{
212         long long_val = PyInt_AsLong(v);
213         if ((long_val == -1) && PyErr_Occurred())
214             return -1;
215         *(char*)addr = (char)long_val;
216         /* XXX: For compatibility, only warn about truncations
217            for now. */
218         if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
219             WARN("Truncation of value to char");
220         break;
221         }
222     case T_UBYTE:{
223         long long_val = PyInt_AsLong(v);
224         if ((long_val == -1) && PyErr_Occurred())
225             return -1;
226         *(unsigned char*)addr = (unsigned char)long_val;
227         if ((long_val > UCHAR_MAX) || (long_val < 0))
228             WARN("Truncation of value to unsigned char");
229         break;
230         }
231     case T_SHORT:{
232         long long_val = PyInt_AsLong(v);
233         if ((long_val == -1) && PyErr_Occurred())
234             return -1;
235         *(short*)addr = (short)long_val;
236         if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
237             WARN("Truncation of value to short");
238         break;
239         }
240     case T_USHORT:{
241         long long_val = PyInt_AsLong(v);
242         if ((long_val == -1) && PyErr_Occurred())
243             return -1;
244         *(unsigned short*)addr = (unsigned short)long_val;
245         if ((long_val > USHRT_MAX) || (long_val < 0))
246             WARN("Truncation of value to unsigned short");
247         break;
248         }
249     case T_INT:{
250         long long_val = PyInt_AsLong(v);
251         if ((long_val == -1) && PyErr_Occurred())
252             return -1;
253         *(int *)addr = (int)long_val;
254         if ((long_val > INT_MAX) || (long_val < INT_MIN))
255             WARN("Truncation of value to int");
256         break;
257         }
258     case T_UINT:{
259         unsigned long ulong_val = PyLong_AsUnsignedLong(v);
260         if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
261             /* XXX: For compatibility, accept negative int values
262                as well. */
263             PyErr_Clear();
264             ulong_val = PyLong_AsLong(v);
265             if ((ulong_val == (unsigned long)-1) &&
266                 PyErr_Occurred())
267                 return -1;
268             *(unsigned int *)addr = (unsigned int)ulong_val;
269             WARN("Writing negative value into unsigned field");
270         } else
271             *(unsigned int *)addr = (unsigned int)ulong_val;
272         if (ulong_val > UINT_MAX)
273             WARN("Truncation of value to unsigned int");
274         break;
275         }
276     case T_LONG:{
277         *(long*)addr = PyLong_AsLong(v);
278         if ((*(long*)addr == -1) && PyErr_Occurred())
279             return -1;
280         break;
281         }
282     case T_ULONG:{
283         *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
284         if ((*(unsigned long*)addr == (unsigned long)-1)
285             && PyErr_Occurred()) {
286             /* XXX: For compatibility, accept negative int values
287                as well. */
288             PyErr_Clear();
289             *(unsigned long*)addr = PyLong_AsLong(v);
290             if ((*(unsigned long*)addr == (unsigned long)-1)
291                 && PyErr_Occurred())
292                 return -1;
293             WARN("Writing negative value into unsigned field");
294         }
295         break;
296         }
297     case T_PYSSIZET:{
298         *(Py_ssize_t*)addr = PyInt_AsSsize_t(v);
299         if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
300             && PyErr_Occurred())
301                         return -1;
302         break;
303         }
304     case T_FLOAT:{
305         double double_val = PyFloat_AsDouble(v);
306         if ((double_val == -1) && PyErr_Occurred())
307             return -1;
308         *(float*)addr = (float)double_val;
309         break;
310         }
311     case T_DOUBLE:
312         *(double*)addr = PyFloat_AsDouble(v);
313         if ((*(double*)addr == -1) && PyErr_Occurred())
314             return -1;
315         break;
316     case T_OBJECT:
317     case T_OBJECT_EX:
318         Py_XINCREF(v);
319         oldv = *(PyObject **)addr;
320         *(PyObject **)addr = v;
321         Py_XDECREF(oldv);
322         break;
323     case T_CHAR:
324         if (PyString_Check(v) && PyString_Size(v) == 1) {
325             *(char*)addr = PyString_AsString(v)[0];
326         }
327         else {
328             PyErr_BadArgument();
329             return -1;
330         }
331         break;
332     case T_STRING:
333     case T_STRING_INPLACE:
334         PyErr_SetString(PyExc_TypeError, "readonly attribute");
335         return -1;
336 #ifdef HAVE_LONG_LONG
337     case T_LONGLONG:{
338         PY_LONG_LONG value;
339         *(PY_LONG_LONG*)addr = value = PyLong_AsLongLong(v);
340         if ((value == -1) && PyErr_Occurred())
341             return -1;
342         break;
343         }
344     case T_ULONGLONG:{
345         unsigned PY_LONG_LONG value;
346         /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
347             doesn't ??? */
348         if (PyLong_Check(v))
349             *(unsigned PY_LONG_LONG*)addr = value = PyLong_AsUnsignedLongLong(v);
350         else
351             *(unsigned PY_LONG_LONG*)addr = value = PyInt_AsLong(v);
352         if ((value == (unsigned PY_LONG_LONG)-1) && PyErr_Occurred())
353             return -1;
354         break;
355         }
356 #endif /* HAVE_LONG_LONG */
357     default:
358         PyErr_Format(PyExc_SystemError,
359                      "bad memberdescr type for %s", l->name);
360         return -1;
361     }
362     return 0;
363 }
364