• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /* Map C struct members to Python object attributes */
3 
4 #include "Python.h"
5 #include "structmember.h"         // PyMemberDef
6 
7 PyObject *
PyMember_GetOne(const char * obj_addr,PyMemberDef * l)8 PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
9 {
10     PyObject *v;
11 
12     const char* addr = obj_addr + l->offset;
13     switch (l->type) {
14     case T_BOOL:
15         v = PyBool_FromLong(*(char*)addr);
16         break;
17     case T_BYTE:
18         v = PyLong_FromLong(*(char*)addr);
19         break;
20     case T_UBYTE:
21         v = PyLong_FromUnsignedLong(*(unsigned char*)addr);
22         break;
23     case T_SHORT:
24         v = PyLong_FromLong(*(short*)addr);
25         break;
26     case T_USHORT:
27         v = PyLong_FromUnsignedLong(*(unsigned short*)addr);
28         break;
29     case T_INT:
30         v = PyLong_FromLong(*(int*)addr);
31         break;
32     case T_UINT:
33         v = PyLong_FromUnsignedLong(*(unsigned int*)addr);
34         break;
35     case T_LONG:
36         v = PyLong_FromLong(*(long*)addr);
37         break;
38     case T_ULONG:
39         v = PyLong_FromUnsignedLong(*(unsigned long*)addr);
40         break;
41     case T_PYSSIZET:
42         v = PyLong_FromSsize_t(*(Py_ssize_t*)addr);
43         break;
44     case T_FLOAT:
45         v = PyFloat_FromDouble((double)*(float*)addr);
46         break;
47     case T_DOUBLE:
48         v = PyFloat_FromDouble(*(double*)addr);
49         break;
50     case T_STRING:
51         if (*(char**)addr == NULL) {
52             Py_INCREF(Py_None);
53             v = Py_None;
54         }
55         else
56             v = PyUnicode_FromString(*(char**)addr);
57         break;
58     case T_STRING_INPLACE:
59         v = PyUnicode_FromString((char*)addr);
60         break;
61     case T_CHAR:
62         v = PyUnicode_FromStringAndSize((char*)addr, 1);
63         break;
64     case T_OBJECT:
65         v = *(PyObject **)addr;
66         if (v == NULL)
67             v = Py_None;
68         Py_INCREF(v);
69         break;
70     case T_OBJECT_EX:
71         v = *(PyObject **)addr;
72         if (v == NULL) {
73             PyObject *obj = (PyObject *)obj_addr;
74             PyTypeObject *tp = Py_TYPE(obj);
75             PyErr_Format(PyExc_AttributeError,
76                          "'%.200s' object has no attribute '%s'",
77                          tp->tp_name, l->name);
78        }
79         Py_XINCREF(v);
80         break;
81     case T_LONGLONG:
82         v = PyLong_FromLongLong(*(long long *)addr);
83         break;
84     case T_ULONGLONG:
85         v = PyLong_FromUnsignedLongLong(*(unsigned long long *)addr);
86         break;
87     case T_NONE:
88         v = Py_None;
89         Py_INCREF(v);
90         break;
91     default:
92         PyErr_SetString(PyExc_SystemError, "bad memberdescr type");
93         v = NULL;
94     }
95     return v;
96 }
97 
98 #define WARN(msg)                                               \
99     do {                                                        \
100     if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0)         \
101         return -1;                                              \
102     } while (0)
103 
104 int
PyMember_SetOne(char * addr,PyMemberDef * l,PyObject * v)105 PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
106 {
107     PyObject *oldv;
108 
109     addr += l->offset;
110 
111     if ((l->flags & READONLY))
112     {
113         PyErr_SetString(PyExc_AttributeError, "readonly attribute");
114         return -1;
115     }
116     if (v == NULL) {
117         if (l->type == T_OBJECT_EX) {
118             /* Check if the attribute is set. */
119             if (*(PyObject **)addr == NULL) {
120                 PyErr_SetString(PyExc_AttributeError, l->name);
121                 return -1;
122             }
123         }
124         else if (l->type != T_OBJECT) {
125             PyErr_SetString(PyExc_TypeError,
126                             "can't delete numeric/char attribute");
127             return -1;
128         }
129     }
130     switch (l->type) {
131     case T_BOOL:{
132         if (!PyBool_Check(v)) {
133             PyErr_SetString(PyExc_TypeError,
134                             "attribute value type must be bool");
135             return -1;
136         }
137         if (v == Py_True)
138             *(char*)addr = (char) 1;
139         else
140             *(char*)addr = (char) 0;
141         break;
142         }
143     case T_BYTE:{
144         long long_val = PyLong_AsLong(v);
145         if ((long_val == -1) && PyErr_Occurred())
146             return -1;
147         *(char*)addr = (char)long_val;
148         /* XXX: For compatibility, only warn about truncations
149            for now. */
150         if ((long_val > CHAR_MAX) || (long_val < CHAR_MIN))
151             WARN("Truncation of value to char");
152         break;
153         }
154     case T_UBYTE:{
155         long long_val = PyLong_AsLong(v);
156         if ((long_val == -1) && PyErr_Occurred())
157             return -1;
158         *(unsigned char*)addr = (unsigned char)long_val;
159         if ((long_val > UCHAR_MAX) || (long_val < 0))
160             WARN("Truncation of value to unsigned char");
161         break;
162         }
163     case T_SHORT:{
164         long long_val = PyLong_AsLong(v);
165         if ((long_val == -1) && PyErr_Occurred())
166             return -1;
167         *(short*)addr = (short)long_val;
168         if ((long_val > SHRT_MAX) || (long_val < SHRT_MIN))
169             WARN("Truncation of value to short");
170         break;
171         }
172     case T_USHORT:{
173         long long_val = PyLong_AsLong(v);
174         if ((long_val == -1) && PyErr_Occurred())
175             return -1;
176         *(unsigned short*)addr = (unsigned short)long_val;
177         if ((long_val > USHRT_MAX) || (long_val < 0))
178             WARN("Truncation of value to unsigned short");
179         break;
180         }
181     case T_INT:{
182         long long_val = PyLong_AsLong(v);
183         if ((long_val == -1) && PyErr_Occurred())
184             return -1;
185         *(int *)addr = (int)long_val;
186         if ((long_val > INT_MAX) || (long_val < INT_MIN))
187             WARN("Truncation of value to int");
188         break;
189         }
190     case T_UINT:{
191         unsigned long ulong_val = PyLong_AsUnsignedLong(v);
192         if ((ulong_val == (unsigned long)-1) && PyErr_Occurred()) {
193             /* XXX: For compatibility, accept negative int values
194                as well. */
195             PyErr_Clear();
196             ulong_val = PyLong_AsLong(v);
197             if ((ulong_val == (unsigned long)-1) &&
198                 PyErr_Occurred())
199                 return -1;
200             *(unsigned int *)addr = (unsigned int)ulong_val;
201             WARN("Writing negative value into unsigned field");
202         } else
203             *(unsigned int *)addr = (unsigned int)ulong_val;
204         if (ulong_val > UINT_MAX)
205             WARN("Truncation of value to unsigned int");
206         break;
207         }
208     case T_LONG:{
209         *(long*)addr = PyLong_AsLong(v);
210         if ((*(long*)addr == -1) && PyErr_Occurred())
211             return -1;
212         break;
213         }
214     case T_ULONG:{
215         *(unsigned long*)addr = PyLong_AsUnsignedLong(v);
216         if ((*(unsigned long*)addr == (unsigned long)-1)
217             && PyErr_Occurred()) {
218             /* XXX: For compatibility, accept negative int values
219                as well. */
220             PyErr_Clear();
221             *(unsigned long*)addr = PyLong_AsLong(v);
222             if ((*(unsigned long*)addr == (unsigned long)-1)
223                 && PyErr_Occurred())
224                 return -1;
225             WARN("Writing negative value into unsigned field");
226         }
227         break;
228         }
229     case T_PYSSIZET:{
230         *(Py_ssize_t*)addr = PyLong_AsSsize_t(v);
231         if ((*(Py_ssize_t*)addr == (Py_ssize_t)-1)
232             && PyErr_Occurred())
233                         return -1;
234         break;
235         }
236     case T_FLOAT:{
237         double double_val = PyFloat_AsDouble(v);
238         if ((double_val == -1) && PyErr_Occurred())
239             return -1;
240         *(float*)addr = (float)double_val;
241         break;
242         }
243     case T_DOUBLE:
244         *(double*)addr = PyFloat_AsDouble(v);
245         if ((*(double*)addr == -1) && PyErr_Occurred())
246             return -1;
247         break;
248     case T_OBJECT:
249     case T_OBJECT_EX:
250         Py_XINCREF(v);
251         oldv = *(PyObject **)addr;
252         *(PyObject **)addr = v;
253         Py_XDECREF(oldv);
254         break;
255     case T_CHAR: {
256         const char *string;
257         Py_ssize_t len;
258 
259         string = PyUnicode_AsUTF8AndSize(v, &len);
260         if (string == NULL || len != 1) {
261             PyErr_BadArgument();
262             return -1;
263         }
264         *(char*)addr = string[0];
265         break;
266         }
267     case T_STRING:
268     case T_STRING_INPLACE:
269         PyErr_SetString(PyExc_TypeError, "readonly attribute");
270         return -1;
271     case T_LONGLONG:{
272         long long value;
273         *(long long*)addr = value = PyLong_AsLongLong(v);
274         if ((value == -1) && PyErr_Occurred())
275             return -1;
276         break;
277         }
278     case T_ULONGLONG:{
279         unsigned long long value;
280         /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
281             doesn't ??? */
282         if (PyLong_Check(v))
283             *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v);
284         else
285             *(unsigned long long*)addr = value = PyLong_AsLong(v);
286         if ((value == (unsigned long long)-1) && PyErr_Occurred())
287             return -1;
288         break;
289         }
290     default:
291         PyErr_Format(PyExc_SystemError,
292                      "bad memberdescr type for %s", l->name);
293         return -1;
294     }
295     return 0;
296 }
297