Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2014-2017 Paul Sokolovsky
7 : : * Copyright (c) 2014-2019 Damien P. George
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : : * of this software and associated documentation files (the "Software"), to deal
11 : : * in the Software without restriction, including without limitation the rights
12 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : : * copies of the Software, and to permit persons to whom the Software is
14 : : * furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included in
17 : : * all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 : : * THE SOFTWARE.
26 : : */
27 : :
28 : : #include <stdint.h>
29 : : #include <stdlib.h>
30 : : #include <stddef.h>
31 : : #include <string.h>
32 : : #include <assert.h>
33 : :
34 : : #include "py/binary.h"
35 : : #include "py/smallint.h"
36 : : #include "py/objint.h"
37 : : #include "py/runtime.h"
38 : :
39 : : // Helpers to work with binary-encoded data
40 : :
41 : : #ifndef alignof
42 : : #define alignof(type) offsetof(struct { char c; type t; }, t)
43 : : #endif
44 : :
45 : 20608 : size_t mp_binary_get_size(char struct_type, char val_type, size_t *palign) {
46 : 20608 : size_t size = 0;
47 : 20608 : int align = 1;
48 [ + + - ]: 20608 : switch (struct_type) {
49 : 1224 : case '<':
50 : : case '>':
51 [ + + + + : 1224 : switch (val_type) {
+ + + -
+ ]
52 : : case 'b':
53 : : case 'B':
54 : 292 : size = 1;
55 : 292 : break;
56 : : case 'h':
57 : : case 'H':
58 : : size = 2;
59 : : break;
60 : : case 'i':
61 : : case 'I':
62 : 276 : size = 4;
63 : 276 : break;
64 : : case 'l':
65 : : case 'L':
66 : 16 : size = 4;
67 : 16 : break;
68 : : case 'q':
69 : : case 'Q':
70 : 264 : size = 8;
71 : 264 : break;
72 : : case 'P':
73 : : case 'O':
74 : : case 'S':
75 : 32 : size = sizeof(void *);
76 : 32 : break;
77 : : case 'f':
78 : 44 : size = sizeof(float);
79 : 44 : break;
80 : : case 'd':
81 : 48 : size = sizeof(double);
82 : 48 : break;
83 : : }
84 : : break;
85 : 19384 : case '@': {
86 : : // TODO:
87 : : // The simplest heuristic for alignment is to align by value
88 : : // size, but that doesn't work for "bigger than int" types,
89 : : // for example, long long may very well have long alignment
90 : : // So, we introduce separate alignment handling, but having
91 : : // formal support for that is different from actually supporting
92 : : // particular (or any) ABI.
93 [ + + + + : 19384 : switch (val_type) {
+ + ]
94 : : case BYTEARRAY_TYPECODE:
95 : : case 'b':
96 : : case 'B':
97 : 16412 : align = size = 1;
98 : 16412 : break;
99 : : case 'h':
100 : : case 'H':
101 : 616 : align = alignof(short);
102 : 616 : size = sizeof(short);
103 : 616 : break;
104 : : case 'i':
105 : : case 'I':
106 : 716 : align = alignof(int);
107 : 716 : size = sizeof(int);
108 : 716 : break;
109 : : case 'l':
110 : : case 'L':
111 : : align = alignof(long);
112 : : size = sizeof(long);
113 : : break;
114 : : case 'q':
115 : : case 'Q':
116 : : align = alignof(long long);
117 : : size = sizeof(long long);
118 : : break;
119 : : case 'P':
120 : : case 'O':
121 : : case 'S':
122 : : align = alignof(void *);
123 : : size = sizeof(void *);
124 : : break;
125 : : case 'f':
126 : 236 : align = alignof(float);
127 : 236 : size = sizeof(float);
128 : 236 : break;
129 : : case 'd':
130 : : align = alignof(double);
131 : : size = sizeof(double);
132 : : break;
133 : : }
134 : : }
135 : : }
136 : :
137 : 18952 : if (size == 0) {
138 : 40 : mp_raise_ValueError(MP_ERROR_TEXT("bad typecode"));
139 : : }
140 : :
141 [ + + ]: 20568 : if (palign != NULL) {
142 : 1458 : *palign = align;
143 : : }
144 : 20568 : return size;
145 : : }
146 : :
147 : 10552106 : mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {
148 : 10552106 : mp_int_t val = 0;
149 [ + + + + : 10552106 : switch (typecode) {
+ + + + +
+ + + + +
- ]
150 : 32 : case 'b':
151 : 32 : val = ((signed char *)p)[index];
152 : 32 : break;
153 : 10541506 : case BYTEARRAY_TYPECODE:
154 : : case 'B':
155 : 10541506 : val = ((unsigned char *)p)[index];
156 : 10541506 : break;
157 : 10116 : case 'h':
158 : 10116 : val = ((short *)p)[index];
159 : 10116 : break;
160 : 32 : case 'H':
161 : 32 : val = ((unsigned short *)p)[index];
162 : 32 : break;
163 : 112 : case 'i':
164 : 112 : return mp_obj_new_int(((int *)p)[index]);
165 : 156 : case 'I':
166 : 156 : return mp_obj_new_int_from_uint(((unsigned int *)p)[index]);
167 : 16 : case 'l':
168 : 16 : return mp_obj_new_int(((long *)p)[index]);
169 : 12 : case 'L':
170 : 12 : return mp_obj_new_int_from_uint(((unsigned long *)p)[index]);
171 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
172 : 28 : case 'q':
173 : 28 : return mp_obj_new_int_from_ll(((long long *)p)[index]);
174 : 20 : case 'Q':
175 : 20 : return mp_obj_new_int_from_ull(((unsigned long long *)p)[index]);
176 : : #endif
177 : : #if MICROPY_PY_BUILTINS_FLOAT
178 : 36 : case 'f':
179 : 36 : return mp_obj_new_float_from_f(((float *)p)[index]);
180 : 32 : case 'd':
181 : 32 : return mp_obj_new_float_from_d(((double *)p)[index]);
182 : : #endif
183 : : // Extension to CPython: array of objects
184 : 4 : case 'O':
185 : 4 : return ((mp_obj_t *)p)[index];
186 : : // Extension to CPython: array of pointers
187 : 4 : case 'P':
188 : 4 : return mp_obj_new_int((mp_int_t)(uintptr_t)((void **)p)[index]);
189 : : }
190 : 10551686 : return MP_OBJ_NEW_SMALL_INT(val);
191 : : }
192 : :
193 : : // The long long type is guaranteed to hold at least 64 bits, and size is at
194 : : // most 8 (for q and Q), so we will always be able to parse the given data
195 : : // and fit it into a long long.
196 : 458 : long long mp_binary_get_int(size_t size, bool is_signed, bool big_endian, const byte *src) {
197 : 458 : int delta;
198 [ + + ]: 458 : if (!big_endian) {
199 : 336 : delta = -1;
200 : 336 : src += size - 1;
201 : : } else {
202 : : delta = 1;
203 : : }
204 : :
205 : 458 : unsigned long long val = 0;
206 [ + + + + ]: 458 : if (is_signed && *src & 0x80) {
207 : 84 : val = -1;
208 : : }
209 [ + + ]: 2142 : for (uint i = 0; i < size; i++) {
210 : 1684 : val <<= 8;
211 : 1684 : val |= *src;
212 : 1684 : src += delta;
213 : : }
214 : :
215 : 458 : return val;
216 : : }
217 : :
218 : : #define is_signed(typecode) (typecode > 'Z')
219 : 428 : mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte **ptr) {
220 : 428 : byte *p = *ptr;
221 : 428 : size_t align;
222 : :
223 : 428 : size_t size = mp_binary_get_size(struct_type, val_type, &align);
224 [ + + ]: 428 : if (struct_type == '@') {
225 : : // Align p relative to p_base
226 : 44 : p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);
227 : : #if MP_ENDIANNESS_LITTLE
228 : 44 : struct_type = '<';
229 : : #else
230 : : struct_type = '>';
231 : : #endif
232 : : }
233 : 428 : *ptr = p + size;
234 : :
235 : 428 : long long val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
236 : :
237 [ + + ]: 428 : if (val_type == 'O') {
238 : 4 : return (mp_obj_t)(mp_uint_t)val;
239 [ + + ]: 424 : } else if (val_type == 'S') {
240 : 4 : const char *s_val = (const char *)(uintptr_t)(mp_uint_t)val;
241 : 4 : return mp_obj_new_str(s_val, strlen(s_val));
242 : : #if MICROPY_PY_BUILTINS_FLOAT
243 [ + + ]: 420 : } else if (val_type == 'f') {
244 : 18 : union {
245 : : uint32_t i;
246 : : float f;
247 : 18 : } fpu = {val};
248 : 18 : return mp_obj_new_float_from_f(fpu.f);
249 [ + + ]: 402 : } else if (val_type == 'd') {
250 : 20 : union {
251 : : uint64_t i;
252 : : double f;
253 : 20 : } fpu = {val};
254 : 20 : return mp_obj_new_float_from_d(fpu.f);
255 : : #endif
256 [ + + ]: 382 : } else if (is_signed(val_type)) {
257 [ + + ]: 176 : if ((long long)MP_SMALL_INT_MIN <= val && val <= (long long)MP_SMALL_INT_MAX) {
258 : 172 : return mp_obj_new_int((mp_int_t)val);
259 : : } else {
260 : 4 : return mp_obj_new_int_from_ll(val);
261 : : }
262 : : } else {
263 [ + + ]: 206 : if ((unsigned long long)val <= (unsigned long long)MP_SMALL_INT_MAX) {
264 : 190 : return mp_obj_new_int_from_uint((mp_uint_t)val);
265 : : } else {
266 : 16 : return mp_obj_new_int_from_ull(val);
267 : : }
268 : : }
269 : : }
270 : :
271 : 472 : void mp_binary_set_int(size_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
272 [ + + ]: 472 : if (MP_ENDIANNESS_LITTLE && !big_endian) {
273 : 312 : memcpy(dest, &val, val_sz);
274 : 160 : } else if (MP_ENDIANNESS_BIG && big_endian) {
275 : : // only copy the least-significant val_sz bytes
276 : : memcpy(dest, (byte *)&val + sizeof(mp_uint_t) - val_sz, val_sz);
277 : : } else {
278 : 160 : const byte *src;
279 : 160 : if (MP_ENDIANNESS_LITTLE) {
280 : 160 : src = (const byte *)&val + val_sz;
281 : : } else {
282 : : src = (const byte *)&val + sizeof(mp_uint_t);
283 : : }
284 [ + + ]: 856 : while (val_sz--) {
285 : 696 : *dest++ = *--src;
286 : : }
287 : : }
288 : 472 : }
289 : :
290 : 474 : void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p_base, byte **ptr) {
291 : 474 : byte *p = *ptr;
292 : 474 : size_t align;
293 : :
294 : 474 : size_t size = mp_binary_get_size(struct_type, val_type, &align);
295 [ + + ]: 474 : if (struct_type == '@') {
296 : : // Align p relative to p_base
297 : 54 : p = p_base + (uintptr_t)MP_ALIGN(p - p_base, align);
298 : 54 : if (MP_ENDIANNESS_LITTLE) {
299 : 54 : struct_type = '<';
300 : : } else {
301 : : struct_type = '>';
302 : : }
303 : : }
304 : 474 : *ptr = p + size;
305 : :
306 : 474 : mp_uint_t val;
307 [ + + + + ]: 474 : switch (val_type) {
308 : 4 : case 'O':
309 : 4 : val = (mp_uint_t)val_in;
310 : 4 : break;
311 : : #if MICROPY_PY_BUILTINS_FLOAT
312 : : case 'f': {
313 : 18 : union {
314 : : uint32_t i;
315 : : float f;
316 : : } fp_sp;
317 : 18 : fp_sp.f = mp_obj_get_float_to_f(val_in);
318 : 18 : val = fp_sp.i;
319 : 18 : break;
320 : : }
321 : : case 'd': {
322 : 20 : union {
323 : : uint64_t i64;
324 : : uint32_t i32[2];
325 : : double f;
326 : : } fp_dp;
327 : 20 : fp_dp.f = mp_obj_get_float_to_d(val_in);
328 : 20 : if (MP_BYTES_PER_OBJ_WORD == 8) {
329 : 20 : val = fp_dp.i64;
330 : : } else {
331 : : int be = struct_type == '>';
332 : : mp_binary_set_int(sizeof(uint32_t), be, p, fp_dp.i32[MP_ENDIANNESS_BIG ^ be]);
333 : : p += sizeof(uint32_t);
334 : : val = fp_dp.i32[MP_ENDIANNESS_LITTLE ^ be];
335 : : }
336 : 20 : break;
337 : : }
338 : : #endif
339 : : default:
340 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
341 [ + + + - ]: 432 : if (mp_obj_is_exact_type(val_in, &mp_type_int)) {
342 : 32 : mp_obj_int_to_bytes_impl(val_in, struct_type == '>', size, p);
343 : 32 : return;
344 : : }
345 : : #endif
346 : :
347 : 400 : val = mp_obj_get_int(val_in);
348 : : // zero/sign extend if needed
349 : 400 : if (MP_BYTES_PER_OBJ_WORD < 8 && size > sizeof(val)) {
350 : : int c = (mp_int_t)val < 0 ? 0xff : 0x00;
351 : : memset(p, c, size);
352 : : if (struct_type == '>') {
353 : : p += size - sizeof(val);
354 : : }
355 : : }
356 : 400 : break;
357 : : }
358 : :
359 : 442 : mp_binary_set_int(MIN((size_t)size, sizeof(val)), struct_type == '>', p, val);
360 : : }
361 : :
362 : 7157677 : void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_in) {
363 [ + + + + ]: 7157677 : switch (typecode) {
364 : : #if MICROPY_PY_BUILTINS_FLOAT
365 : 48 : case 'f':
366 : 48 : ((float *)p)[index] = mp_obj_get_float_to_f(val_in);
367 : 48 : break;
368 : 24 : case 'd':
369 : 24 : ((double *)p)[index] = mp_obj_get_float_to_d(val_in);
370 : 24 : break;
371 : : #endif
372 : : // Extension to CPython: array of objects
373 : 4 : case 'O':
374 : 4 : ((mp_obj_t *)p)[index] = val_in;
375 : 4 : break;
376 : : default:
377 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
378 [ + + + - ]: 7157601 : if (mp_obj_is_exact_type(val_in, &mp_type_int)) {
379 : 16 : size_t size = mp_binary_get_size('@', typecode, NULL);
380 : 16 : mp_obj_int_to_bytes_impl(val_in, MP_ENDIANNESS_BIG,
381 : 16 : size, (uint8_t *)p + index * size);
382 : 16 : return;
383 : : }
384 : : #endif
385 : 7157585 : mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
386 : : }
387 : : }
388 : :
389 : 7403522 : void mp_binary_set_val_array_from_int(char typecode, void *p, size_t index, mp_int_t val) {
390 [ + + + + : 7403522 : switch (typecode) {
+ + + + +
+ + + +
- ]
391 : 292 : case 'b':
392 : 292 : ((signed char *)p)[index] = val;
393 : 292 : break;
394 : 7402396 : case BYTEARRAY_TYPECODE:
395 : : case 'B':
396 : 7402396 : ((unsigned char *)p)[index] = val;
397 : 7402396 : break;
398 : 234 : case 'h':
399 : 234 : ((short *)p)[index] = val;
400 : 234 : break;
401 : 64 : case 'H':
402 : 64 : ((unsigned short *)p)[index] = val;
403 : 64 : break;
404 : 140 : case 'i':
405 : 140 : ((int *)p)[index] = val;
406 : 140 : break;
407 : 188 : case 'I':
408 : 188 : ((unsigned int *)p)[index] = val;
409 : 188 : break;
410 : 52 : case 'l':
411 : 52 : ((long *)p)[index] = val;
412 : 52 : break;
413 : 52 : case 'L':
414 : 52 : ((unsigned long *)p)[index] = val;
415 : 52 : break;
416 : : #if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
417 : 48 : case 'q':
418 : 48 : ((long long *)p)[index] = val;
419 : 48 : break;
420 : 48 : case 'Q':
421 : 48 : ((unsigned long long *)p)[index] = val;
422 : 48 : break;
423 : : #endif
424 : : #if MICROPY_PY_BUILTINS_FLOAT
425 : 2 : case 'f':
426 : 2 : ((float *)p)[index] = (float)val;
427 : 2 : break;
428 : 2 : case 'd':
429 : 2 : ((double *)p)[index] = (double)val;
430 : 2 : break;
431 : : #endif
432 : : // Extension to CPython: array of pointers
433 : 4 : case 'P':
434 : 4 : ((void **)p)[index] = (void *)(uintptr_t)val;
435 : 4 : break;
436 : : }
437 : 7403522 : }
|