blob: c7e318811d82b8895d40e5fffa01535055ef4f08 [file] [log] [blame]
Guido van Rossumf70e43a1991-02-19 12:39:46 +00001
Guido van Rossum3f5da241990-12-20 15:06:42 +00002/* Map C struct members to Python object attributes */
3
Guido van Rossum79f25d91997-04-29 20:08:16 +00004#include "Python.h"
Victor Stinner4a21e572020-04-15 02:35:41 +02005#include "structmember.h" // PyMemberDef
Guido van Rossum3f5da241990-12-20 15:06:42 +00006
Guido van Rossum6f799372001-09-20 20:46:19 +00007PyObject *
Miss Islington (bot)efda9052021-07-16 17:01:53 -07008PyMember_GetOne(const char *obj_addr, PyMemberDef *l)
Guido van Rossum6f799372001-09-20 20:46:19 +00009{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000010 PyObject *v;
Guido van Rossuma8add0e2007-05-14 22:03:55 +000011
Miss Islington (bot)efda9052021-07-16 17:01:53 -070012 const char* addr = obj_addr + l->offset;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000013 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;
Miss Islington (bot)efda9052021-07-16 17:01:53 -070072 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 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000079 Py_XINCREF(v);
80 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000081 case T_LONGLONG:
Benjamin Petersonaf580df2016-09-06 10:46:49 -070082 v = PyLong_FromLongLong(*(long long *)addr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000083 break;
84 case T_ULONGLONG:
Benjamin Petersonaf580df2016-09-06 10:46:49 -070085 v = PyLong_FromUnsignedLongLong(*(unsigned long long *)addr);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 break;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 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;
Guido van Rossum6f799372001-09-20 20:46:19 +000096}
97
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098#define WARN(msg) \
99 do { \
100 if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 1) < 0) \
101 return -1; \
Guido van Rossum806c2462007-08-06 23:33:07 +0000102 } while (0)
103
Guido van Rossum6f799372001-09-20 20:46:19 +0000104int
105PyMember_SetOne(char *addr, PyMemberDef *l, PyObject *v)
106{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000107 PyObject *oldv;
Guido van Rossum6f799372001-09-20 20:46:19 +0000108
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000109 addr += l->offset;
Benjamin Petersond12362a2009-12-30 19:44:54 +0000110
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000111 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: {
Serhiy Storchaka85b0f5b2016-11-20 10:16:47 +0200256 const char *string;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 Py_ssize_t len;
Alexandre Vassalottia85998a2008-05-03 18:24:43 +0000258
Serhiy Storchaka06515832016-11-20 09:13:07 +0200259 string = PyUnicode_AsUTF8AndSize(v, &len);
Christian Heimes5557a9c2012-09-11 17:30:53 +0200260 if (string == NULL || len != 1) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000261 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;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 case T_LONGLONG:{
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700272 long long value;
273 *(long long*)addr = value = PyLong_AsLongLong(v);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 if ((value == -1) && PyErr_Occurred())
275 return -1;
276 break;
277 }
278 case T_ULONGLONG:{
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700279 unsigned long long value;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 /* ??? PyLong_AsLongLong accepts an int, but PyLong_AsUnsignedLongLong
281 doesn't ??? */
282 if (PyLong_Check(v))
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700283 *(unsigned long long*)addr = value = PyLong_AsUnsignedLongLong(v);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000284 else
Benjamin Petersonaf580df2016-09-06 10:46:49 -0700285 *(unsigned long long*)addr = value = PyLong_AsLong(v);
286 if ((value == (unsigned long long)-1) && PyErr_Occurred())
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000287 return -1;
288 break;
289 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000290 default:
291 PyErr_Format(PyExc_SystemError,
292 "bad memberdescr type for %s", l->name);
293 return -1;
294 }
295 return 0;
Guido van Rossum6f799372001-09-20 20:46:19 +0000296}