blob: 919ba8784630ab59354b51841da7b34b95c77fdb [file] [log] [blame]
Damien George04b91472014-05-03 23:27:38 +01001/*
2 * This file is part of the Micro Python project, http://micropython.org/
3 *
4 * The MIT License (MIT)
5 *
6 * Copyright (c) 2013, 2014 Damien P. George
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 */
26
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020027#include <stdint.h>
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030028#include <stdlib.h>
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030029#include <stddef.h>
Paul Sokolovsky62798832014-06-02 16:04:26 +030030#include <string.h>
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020031#include <assert.h>
32
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020033#include "mpconfig.h"
Paul Sokolovsky59c675a2014-06-21 22:43:22 +030034#include "misc.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020035#include "qstr.h"
36#include "obj.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020037#include "binary.h"
38
39// Helpers to work with binary-encoded data
40
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030041#ifndef alignof
42#define alignof(type) offsetof(struct { char c; type t; }, t)
43#endif
44
Damien George4abff752014-08-30 14:59:21 +010045int mp_binary_get_size(char struct_type, char val_type, mp_uint_t *palign) {
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030046 int size = 0;
47 int align = 1;
48 switch (struct_type) {
49 case '<': case '>':
50 switch (val_type) {
51 case 'b': case 'B':
52 size = 1; break;
53 case 'h': case 'H':
54 size = 2; break;
55 case 'i': case 'I':
56 size = 4; break;
57 case 'l': case 'L':
58 size = 4; break;
59 case 'q': case 'Q':
60 size = 8; break;
Paul Sokolovsky78fde482014-09-06 19:24:52 +030061 case 'P': case 'O': case 'S':
62 size = sizeof(void*); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030063 }
64 break;
65 case '@': {
66 // TODO:
67 // The simplest heuristic for alignment is to align by value
68 // size, but that doesn't work for "bigger than int" types,
69 // for example, long long may very well have long alignment
70 // So, we introduce separate alignment handling, but having
71 // formal support for that is different from actually supporting
72 // particular (or any) ABI.
73 switch (val_type) {
74 case BYTEARRAY_TYPECODE:
75 case 'b': case 'B':
76 align = size = 1; break;
77 case 'h': case 'H':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030078 align = alignof(short);
79 size = sizeof(short); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030080 case 'i': case 'I':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030081 align = alignof(int);
82 size = sizeof(int); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030083 case 'l': case 'L':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030084 align = alignof(long);
85 size = sizeof(long); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030086 case 'q': case 'Q':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030087 align = alignof(long long);
88 size = sizeof(long long); break;
Paul Sokolovsky62798832014-06-02 16:04:26 +030089 case 'P': case 'O': case 'S':
Paul Sokolovskyecca53b2014-08-10 20:16:39 +030090 align = alignof(void*);
91 size = sizeof(void*); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030092 }
93 }
Paul Sokolovskyc2033242014-02-14 20:21:50 +020094 }
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030095 if (palign != NULL) {
96 *palign = align;
97 }
98 return size;
Paul Sokolovskyc2033242014-02-14 20:21:50 +020099}
100
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300101mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
Damien George40f3c022014-07-03 13:25:24 +0100102 mp_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200103 switch (typecode) {
104 case 'b':
105 val = ((int8_t*)p)[index];
106 break;
107 case BYTEARRAY_TYPECODE:
108 case 'B':
109 val = ((uint8_t*)p)[index];
110 break;
111 case 'h':
112 val = ((int16_t*)p)[index];
113 break;
114 case 'H':
115 val = ((uint16_t*)p)[index];
116 break;
117 case 'i':
118 case 'l':
119 return mp_obj_new_int(((int32_t*)p)[index]);
120 case 'I':
121 case 'L':
122 return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
Damien George96056a62014-02-15 23:02:00 +0000123#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200124 case 'q':
125 case 'Q':
126 // TODO: Explode API more to cover signedness
127 return mp_obj_new_int_from_ll(((long long*)p)[index]);
128#endif
Damien Georgefb510b32014-06-01 13:32:54 +0100129#if MICROPY_PY_BUILTINS_FLOAT
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200130 case 'f':
131 return mp_obj_new_float(((float*)p)[index]);
132 case 'd':
133 return mp_obj_new_float(((double*)p)[index]);
134#endif
135 }
136 return MP_OBJ_NEW_SMALL_INT(val);
137}
138
Damien George4abff752014-08-30 14:59:21 +0100139mp_int_t mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p) {
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300140 int delta;
141 if (!big_endian) {
142 delta = -1;
143 p += size - 1;
144 } else {
145 delta = 1;
146 }
147
Damien George40f3c022014-07-03 13:25:24 +0100148 mp_int_t val = 0;
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300149 if (is_signed && *p & 0x80) {
150 val = -1;
151 }
152 for (uint i = 0; i < size; i++) {
153 val <<= 8;
154 val |= *p;
155 p += delta;
156 }
157
158 return val;
159}
160
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300161#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300162mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300163 byte *p = *ptr;
Damien George4abff752014-08-30 14:59:21 +0100164 mp_uint_t align;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300165
166 int size = mp_binary_get_size(struct_type, val_type, &align);
167 if (struct_type == '@') {
168 // Make pointer aligned
Damien George40f3c022014-07-03 13:25:24 +0100169 p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300170 #if MP_ENDIANNESS_LITTLE
171 struct_type = '<';
172 #else
173 struct_type = '>';
174 #endif
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300175 }
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300176 *ptr = p + size;
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300177
Damien George40f3c022014-07-03 13:25:24 +0100178 mp_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300179
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300180 if (val_type == 'O') {
181 return (mp_obj_t)val;
Paul Sokolovsky62798832014-06-02 16:04:26 +0300182 } else if (val_type == 'S') {
183 return mp_obj_new_str((char*)val, strlen((char*)val), false);
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300184 } else if (is_signed(val_type)) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300185 return mp_obj_new_int(val);
186 } else {
187 return mp_obj_new_int_from_uint(val);
188 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300189}
190
Damien George4abff752014-08-30 14:59:21 +0100191void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr) {
Paul Sokolovsky5fa5ca42014-07-05 23:43:00 +0300192 int in_delta, out_delta;
193 if (big_endian) {
194 in_delta = -1;
195 out_delta = 1;
196 val_ptr += val_sz - 1;
197 } else {
198 in_delta = out_delta = 1;
199 }
200
201 for (uint i = val_sz; i > 0; i--) {
202 *p = *val_ptr;
203 p += out_delta;
204 val_ptr += in_delta;
205 }
206}
207
Paul Sokolovsky62044602014-04-19 03:13:15 +0300208void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
209 byte *p = *ptr;
Damien George4abff752014-08-30 14:59:21 +0100210 mp_uint_t align;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300211
212 int size = mp_binary_get_size(struct_type, val_type, &align);
213 if (struct_type == '@') {
214 // Make pointer aligned
Damien George40f3c022014-07-03 13:25:24 +0100215 p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
Paul Sokolovsky62044602014-04-19 03:13:15 +0300216 #if MP_ENDIANNESS_LITTLE
217 struct_type = '<';
218 #else
219 struct_type = '>';
220 #endif
221 }
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300222 *ptr = p + size;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300223
224#if MP_ENDIANNESS_BIG
225#error Not implemented
226#endif
Damien George40f3c022014-07-03 13:25:24 +0100227 mp_int_t val;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300228 byte *in = (byte*)&val;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300229 switch (val_type) {
230 case 'O':
231 in = (byte*)&val_in;
232 break;
233 default:
234 val = mp_obj_get_int(val_in);
235 }
236
Paul Sokolovsky5fa5ca42014-07-05 23:43:00 +0300237 mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
Paul Sokolovsky62044602014-04-19 03:13:15 +0300238}
239
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300240void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
Damien George71e9bfa2014-04-18 23:28:12 +0100241 switch (typecode) {
Damien Georgefb510b32014-06-01 13:32:54 +0100242#if MICROPY_PY_BUILTINS_FLOAT
Damien George71e9bfa2014-04-18 23:28:12 +0100243 case 'f':
244 ((float*)p)[index] = mp_obj_float_get(val_in);
245 break;
246 case 'd':
247 ((double*)p)[index] = mp_obj_float_get(val_in);
248 break;
249#endif
250 default:
251 mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200252 }
Damien George71e9bfa2014-04-18 23:28:12 +0100253}
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200254
Damien George40f3c022014-07-03 13:25:24 +0100255void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200256 switch (typecode) {
257 case 'b':
258 ((int8_t*)p)[index] = val;
259 break;
260 case BYTEARRAY_TYPECODE:
261 case 'B':
262 val = ((uint8_t*)p)[index] = val;
263 break;
264 case 'h':
265 val = ((int16_t*)p)[index] = val;
266 break;
267 case 'H':
268 val = ((uint16_t*)p)[index] = val;
269 break;
270 case 'i':
271 case 'l':
272 ((int32_t*)p)[index] = val;
273 break;
274 case 'I':
275 case 'L':
276 ((uint32_t*)p)[index] = val;
277 break;
278#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
279 case 'q':
280 case 'Q':
281 assert(0);
282 ((long long*)p)[index] = val;
283 break;
284#endif
Damien Georgefb510b32014-06-01 13:32:54 +0100285#if MICROPY_PY_BUILTINS_FLOAT
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200286 case 'f':
Damien George71e9bfa2014-04-18 23:28:12 +0100287 ((float*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200288 break;
289 case 'd':
Damien George71e9bfa2014-04-18 23:28:12 +0100290 ((double*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200291 break;
292#endif
293 }
294}