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