blob: 1ddf4569b98f1f8b5ca3a5e72d2e3ffc0395f673 [file] [log] [blame]
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02001#include <stdint.h>
2#include <assert.h>
3
4#include "misc.h"
5#include "mpconfig.h"
6#include "qstr.h"
7#include "obj.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +02008#include "binary.h"
9
10// Helpers to work with binary-encoded data
11
Paul Sokolovskyc2033242014-02-14 20:21:50 +020012int mp_binary_get_size(char typecode) {
13 // This assumes that unsigned and signed types are of the same type,
14 // which is invariant for [u]intN_t.
15 switch (typecode) {
16 case BYTEARRAY_TYPECODE:
17 case 'b':
18 case 'B':
19 return sizeof(int8_t);
20 case 'h':
21 case 'H':
22 return sizeof(int16_t);
23 case 'i':
24 case 'I':
25 return sizeof(int32_t);
26 case 'l':
27 case 'L':
28 return sizeof(int32_t);
29 case 'q':
30 case 'Q':
31 return sizeof(long long);
32#if MICROPY_ENABLE_FLOAT
33 case 'f':
34 return sizeof(float);
35 case 'd':
36 return sizeof(double);
37#endif
38 }
39 return -1;
40}
41
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030042mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
Paul Sokolovsky76f8ced2014-02-15 00:28:41 +020043 machine_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020044 switch (typecode) {
45 case 'b':
46 val = ((int8_t*)p)[index];
47 break;
48 case BYTEARRAY_TYPECODE:
49 case 'B':
50 val = ((uint8_t*)p)[index];
51 break;
52 case 'h':
53 val = ((int16_t*)p)[index];
54 break;
55 case 'H':
56 val = ((uint16_t*)p)[index];
57 break;
58 case 'i':
59 case 'l':
60 return mp_obj_new_int(((int32_t*)p)[index]);
61 case 'I':
62 case 'L':
63 return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
Damien George96056a62014-02-15 23:02:00 +000064#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020065 case 'q':
66 case 'Q':
67 // TODO: Explode API more to cover signedness
68 return mp_obj_new_int_from_ll(((long long*)p)[index]);
69#endif
70#if MICROPY_ENABLE_FLOAT
71 case 'f':
72 return mp_obj_new_float(((float*)p)[index]);
73 case 'd':
74 return mp_obj_new_float(((double*)p)[index]);
75#endif
76 }
77 return MP_OBJ_NEW_SMALL_INT(val);
78}
79
Paul Sokolovsky6582d642014-04-10 22:19:32 +030080#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +030081mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +030082 byte *p = *ptr;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +030083 uint size = 0;
84 switch (struct_type) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +030085 case '<': case '>':
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +030086 switch (val_type) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +030087 case 'b': case 'B':
88 size = 1; break;
89 case 'h': case 'H':
90 size = 2; break;
91 case 'i': case 'I':
92 size = 4; break;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +030093 case 'l': case 'L':
94 size = 4; break;
Paul Sokolovsky6582d642014-04-10 22:19:32 +030095 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +030096 break;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +030097 case '@': {
98 // TODO:
99 // The simplest heuristic for alignment is to align by value
100 // size, but that doesn't work for "bigger than int" types,
101 // for example, long long may very well have long alignment
102 // So, we introduce separate alignment handling, but having
103 // formal support for that is different from actually supporting
104 // particular (or any) ABI.
105 uint align = 0;
106 switch (val_type) {
107 case 'b': case 'B':
108 align = size = 1; break;
109 case 'h': case 'H':
110 align = size = sizeof(short); break;
111 case 'i': case 'I':
112 align = size = sizeof(int); break;
113 case 'l': case 'L':
114 align = size = sizeof(long); break;
115 }
116 // Make pointer aligned
117 p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1));
118 #if MP_ENDIANNESS_LITTLE
119 struct_type = '<';
120 #else
121 struct_type = '>';
122 #endif
123 break;
124 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300125 }
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300126
127 int delta;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300128 if (struct_type == '<') {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300129 delta = -1;
130 p += size - 1;
131 } else {
132 delta = 1;
133 }
134
135 machine_int_t val = 0;
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300136 if (is_signed(val_type) && *p & 0x80) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300137 val = -1;
138 }
139 for (uint i = 0; i < size; i++) {
140 val <<= 8;
141 val |= *p;
142 p += delta;
143 }
144
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300145 *ptr += size;
146 if (is_signed(val_type)) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300147 return mp_obj_new_int(val);
148 } else {
149 return mp_obj_new_int_from_uint(val);
150 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300151}
152
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300153void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200154 machine_int_t val = 0;
155 if (MP_OBJ_IS_INT(val_in)) {
156 val = mp_obj_int_get(val_in);
157 }
158
159 switch (typecode) {
160 case 'b':
161 ((int8_t*)p)[index] = val;
162 break;
163 case BYTEARRAY_TYPECODE:
164 case 'B':
165 val = ((uint8_t*)p)[index] = val;
166 break;
167 case 'h':
168 val = ((int16_t*)p)[index] = val;
169 break;
170 case 'H':
171 val = ((uint16_t*)p)[index] = val;
172 break;
173 case 'i':
174 case 'l':
175 ((int32_t*)p)[index] = val;
176 break;
177 case 'I':
178 case 'L':
179 ((uint32_t*)p)[index] = val;
180 break;
181#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
182 case 'q':
183 case 'Q':
184 assert(0);
185 ((long long*)p)[index] = val;
186 break;
187#endif
188#if MICROPY_ENABLE_FLOAT
189 case 'f':
190 ((float*)p)[index] = mp_obj_float_get(val_in);
191 break;
192 case 'd':
193 ((double*)p)[index] = mp_obj_float_get(val_in);
194 break;
195#endif
196 }
197}