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