blob: 702a9cceb3d089c112a551dea3213ad1588d7888 [file] [log] [blame]
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02001#include <stdint.h>
Paul Sokolovsky1355cf42014-04-19 01:25:49 +03002#include <stdlib.h>
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02003#include <assert.h>
4
5#include "misc.h"
6#include "mpconfig.h"
7#include "qstr.h"
8#include "obj.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02009#include "binary.h"
10
11// Helpers to work with binary-encoded data
12
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030013int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
14 int size = 0;
15 int align = 1;
16 switch (struct_type) {
17 case '<': case '>':
18 switch (val_type) {
19 case 'b': case 'B':
20 size = 1; break;
21 case 'h': case 'H':
22 size = 2; break;
23 case 'i': case 'I':
24 size = 4; break;
25 case 'l': case 'L':
26 size = 4; break;
27 case 'q': case 'Q':
28 size = 8; break;
29 }
30 break;
31 case '@': {
32 // TODO:
33 // The simplest heuristic for alignment is to align by value
34 // size, but that doesn't work for "bigger than int" types,
35 // for example, long long may very well have long alignment
36 // So, we introduce separate alignment handling, but having
37 // formal support for that is different from actually supporting
38 // particular (or any) ABI.
39 switch (val_type) {
40 case BYTEARRAY_TYPECODE:
41 case 'b': case 'B':
42 align = size = 1; break;
43 case 'h': case 'H':
44 align = size = sizeof(short); break;
45 case 'i': case 'I':
46 align = size = sizeof(int); break;
47 case 'l': case 'L':
48 align = size = sizeof(long); break;
49 case 'q': case 'Q':
50 // TODO: This is for x86
51 align = sizeof(int); size = sizeof(long long); break;
52 }
53 }
Paul Sokolovskyc2033242014-02-14 20:21:50 +020054 }
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030055 if (palign != NULL) {
56 *palign = align;
57 }
58 return size;
Paul Sokolovskyc2033242014-02-14 20:21:50 +020059}
60
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030061mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
Paul Sokolovsky76f8ced2014-02-15 00:28:41 +020062 machine_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020063 switch (typecode) {
64 case 'b':
65 val = ((int8_t*)p)[index];
66 break;
67 case BYTEARRAY_TYPECODE:
68 case 'B':
69 val = ((uint8_t*)p)[index];
70 break;
71 case 'h':
72 val = ((int16_t*)p)[index];
73 break;
74 case 'H':
75 val = ((uint16_t*)p)[index];
76 break;
77 case 'i':
78 case 'l':
79 return mp_obj_new_int(((int32_t*)p)[index]);
80 case 'I':
81 case 'L':
82 return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
Damien George96056a62014-02-15 23:02:00 +000083#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020084 case 'q':
85 case 'Q':
86 // TODO: Explode API more to cover signedness
87 return mp_obj_new_int_from_ll(((long long*)p)[index]);
88#endif
89#if MICROPY_ENABLE_FLOAT
90 case 'f':
91 return mp_obj_new_float(((float*)p)[index]);
92 case 'd':
93 return mp_obj_new_float(((double*)p)[index]);
94#endif
95 }
96 return MP_OBJ_NEW_SMALL_INT(val);
97}
98
Paul Sokolovsky6582d642014-04-10 22:19:32 +030099#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300100mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300101 byte *p = *ptr;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300102 uint align;
103
104 int size = mp_binary_get_size(struct_type, val_type, &align);
105 if (struct_type == '@') {
106 // Make pointer aligned
107 p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
108 #if MP_ENDIANNESS_LITTLE
109 struct_type = '<';
110 #else
111 struct_type = '>';
112 #endif
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300113 }
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300114
115 int delta;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300116 if (struct_type == '<') {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300117 delta = -1;
118 p += size - 1;
119 } else {
120 delta = 1;
121 }
122
123 machine_int_t val = 0;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300124 if (is_signed(val_type) && *p & 0x80) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300125 val = -1;
126 }
127 for (uint i = 0; i < size; i++) {
128 val <<= 8;
129 val |= *p;
130 p += delta;
131 }
132
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300133 *ptr += size;
134 if (is_signed(val_type)) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300135 return mp_obj_new_int(val);
136 } else {
137 return mp_obj_new_int_from_uint(val);
138 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300139}
140
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300141void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
Damien George71e9bfa2014-04-18 23:28:12 +0100142 switch (typecode) {
143#if MICROPY_ENABLE_FLOAT
144 case 'f':
145 ((float*)p)[index] = mp_obj_float_get(val_in);
146 break;
147 case 'd':
148 ((double*)p)[index] = mp_obj_float_get(val_in);
149 break;
150#endif
151 default:
152 mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200153 }
Damien George71e9bfa2014-04-18 23:28:12 +0100154}
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200155
Damien George71e9bfa2014-04-18 23:28:12 +0100156void mp_binary_set_val_array_from_int(char typecode, void *p, int index, machine_int_t val) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200157 switch (typecode) {
158 case 'b':
159 ((int8_t*)p)[index] = val;
160 break;
161 case BYTEARRAY_TYPECODE:
162 case 'B':
163 val = ((uint8_t*)p)[index] = val;
164 break;
165 case 'h':
166 val = ((int16_t*)p)[index] = val;
167 break;
168 case 'H':
169 val = ((uint16_t*)p)[index] = val;
170 break;
171 case 'i':
172 case 'l':
173 ((int32_t*)p)[index] = val;
174 break;
175 case 'I':
176 case 'L':
177 ((uint32_t*)p)[index] = val;
178 break;
179#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
180 case 'q':
181 case 'Q':
182 assert(0);
183 ((long long*)p)[index] = val;
184 break;
185#endif
186#if MICROPY_ENABLE_FLOAT
187 case 'f':
Damien George71e9bfa2014-04-18 23:28:12 +0100188 ((float*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200189 break;
190 case 'd':
Damien George71e9bfa2014-04-18 23:28:12 +0100191 ((double*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200192 break;
193#endif
194 }
195}