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