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 | |
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 |
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 | |