1
2/* Map C struct members to Python object attributes */
3
4#include "Python.h"
5#include "structmember.h" // PyMemberDef
6
7PyObject *
8PyMember_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
104int
105PyMember_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