blob: 3f1d7f286729f3a8ceaabf9e46f1fca764546126 [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 Sokolovsky62798832014-06-02 16:04:26 +030029#include <string.h>
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020030#include <assert.h>
31
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020032#include "mpconfig.h"
Paul Sokolovsky59c675a2014-06-21 22:43:22 +030033#include "misc.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020034#include "qstr.h"
35#include "obj.h"
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020036#include "binary.h"
37
38// Helpers to work with binary-encoded data
39
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030040int mp_binary_get_size(char struct_type, char val_type, uint *palign) {
41 int size = 0;
42 int align = 1;
43 switch (struct_type) {
44 case '<': case '>':
45 switch (val_type) {
46 case 'b': case 'B':
47 size = 1; break;
48 case 'h': case 'H':
49 size = 2; break;
50 case 'i': case 'I':
51 size = 4; break;
52 case 'l': case 'L':
53 size = 4; break;
54 case 'q': case 'Q':
55 size = 8; break;
56 }
57 break;
58 case '@': {
59 // TODO:
60 // The simplest heuristic for alignment is to align by value
61 // size, but that doesn't work for "bigger than int" types,
62 // for example, long long may very well have long alignment
63 // So, we introduce separate alignment handling, but having
64 // formal support for that is different from actually supporting
65 // particular (or any) ABI.
66 switch (val_type) {
67 case BYTEARRAY_TYPECODE:
68 case 'b': case 'B':
69 align = size = 1; break;
70 case 'h': case 'H':
71 align = size = sizeof(short); break;
72 case 'i': case 'I':
73 align = size = sizeof(int); break;
74 case 'l': case 'L':
75 align = size = sizeof(long); break;
76 case 'q': case 'Q':
77 // TODO: This is for x86
78 align = sizeof(int); size = sizeof(long long); break;
Paul Sokolovsky62798832014-06-02 16:04:26 +030079 case 'P': case 'O': case 'S':
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +030080 align = size = sizeof(void*); break;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030081 }
82 }
Paul Sokolovskyc2033242014-02-14 20:21:50 +020083 }
Paul Sokolovsky1355cf42014-04-19 01:25:49 +030084 if (palign != NULL) {
85 *palign = align;
86 }
87 return size;
Paul Sokolovskyc2033242014-02-14 20:21:50 +020088}
89
Paul Sokolovskyef9124f2014-04-11 03:46:09 +030090mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) {
Damien George40f3c022014-07-03 13:25:24 +010091 mp_int_t val = 0;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +020092 switch (typecode) {
93 case 'b':
94 val = ((int8_t*)p)[index];
95 break;
96 case BYTEARRAY_TYPECODE:
97 case 'B':
98 val = ((uint8_t*)p)[index];
99 break;
100 case 'h':
101 val = ((int16_t*)p)[index];
102 break;
103 case 'H':
104 val = ((uint16_t*)p)[index];
105 break;
106 case 'i':
107 case 'l':
108 return mp_obj_new_int(((int32_t*)p)[index]);
109 case 'I':
110 case 'L':
111 return mp_obj_new_int_from_uint(((uint32_t*)p)[index]);
Damien George96056a62014-02-15 23:02:00 +0000112#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200113 case 'q':
114 case 'Q':
115 // TODO: Explode API more to cover signedness
116 return mp_obj_new_int_from_ll(((long long*)p)[index]);
117#endif
Damien Georgefb510b32014-06-01 13:32:54 +0100118#if MICROPY_PY_BUILTINS_FLOAT
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200119 case 'f':
120 return mp_obj_new_float(((float*)p)[index]);
121 case 'd':
122 return mp_obj_new_float(((double*)p)[index]);
123#endif
124 }
125 return MP_OBJ_NEW_SMALL_INT(val);
126}
127
Damien George40f3c022014-07-03 13:25:24 +0100128mp_int_t mp_binary_get_int(uint size, bool is_signed, bool big_endian, byte *p) {
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300129 int delta;
130 if (!big_endian) {
131 delta = -1;
132 p += size - 1;
133 } else {
134 delta = 1;
135 }
136
Damien George40f3c022014-07-03 13:25:24 +0100137 mp_int_t val = 0;
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300138 if (is_signed && *p & 0x80) {
139 val = -1;
140 }
141 for (uint i = 0; i < size; i++) {
142 val <<= 8;
143 val |= *p;
144 p += delta;
145 }
146
147 return val;
148}
149
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300150#define is_signed(typecode) (typecode > 'Z')
Paul Sokolovsky0c43cf92014-04-11 03:47:21 +0300151mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300152 byte *p = *ptr;
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300153 uint align;
154
155 int size = mp_binary_get_size(struct_type, val_type, &align);
156 if (struct_type == '@') {
157 // Make pointer aligned
Damien George40f3c022014-07-03 13:25:24 +0100158 p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
Paul Sokolovsky1355cf42014-04-19 01:25:49 +0300159 #if MP_ENDIANNESS_LITTLE
160 struct_type = '<';
161 #else
162 struct_type = '>';
163 #endif
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300164 }
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300165 *ptr = p + size;
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300166
Damien George40f3c022014-07-03 13:25:24 +0100167 mp_int_t val = mp_binary_get_int(size, is_signed(val_type), (struct_type == '>'), p);
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300168
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300169 if (val_type == 'O') {
170 return (mp_obj_t)val;
Paul Sokolovsky62798832014-06-02 16:04:26 +0300171 } else if (val_type == 'S') {
172 return mp_obj_new_str((char*)val, strlen((char*)val), false);
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300173 } else if (is_signed(val_type)) {
Paul Sokolovsky6582d642014-04-10 22:19:32 +0300174 return mp_obj_new_int(val);
175 } else {
176 return mp_obj_new_int_from_uint(val);
177 }
Paul Sokolovskye9db8402014-04-10 03:45:38 +0300178}
179
Paul Sokolovsky5fa5ca42014-07-05 23:43:00 +0300180void mp_binary_set_int(uint val_sz, bool big_endian, byte *p, byte *val_ptr) {
181 int in_delta, out_delta;
182 if (big_endian) {
183 in_delta = -1;
184 out_delta = 1;
185 val_ptr += val_sz - 1;
186 } else {
187 in_delta = out_delta = 1;
188 }
189
190 for (uint i = val_sz; i > 0; i--) {
191 *p = *val_ptr;
192 p += out_delta;
193 val_ptr += in_delta;
194 }
195}
196
Paul Sokolovsky62044602014-04-19 03:13:15 +0300197void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr) {
198 byte *p = *ptr;
199 uint align;
200
201 int size = mp_binary_get_size(struct_type, val_type, &align);
202 if (struct_type == '@') {
203 // Make pointer aligned
Damien George40f3c022014-07-03 13:25:24 +0100204 p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
Paul Sokolovsky62044602014-04-19 03:13:15 +0300205 #if MP_ENDIANNESS_LITTLE
206 struct_type = '<';
207 #else
208 struct_type = '>';
209 #endif
210 }
Paul Sokolovsky7a2f1662014-06-25 22:25:53 +0300211 *ptr = p + size;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300212
213#if MP_ENDIANNESS_BIG
214#error Not implemented
215#endif
Damien George40f3c022014-07-03 13:25:24 +0100216 mp_int_t val;
Paul Sokolovsky62044602014-04-19 03:13:15 +0300217 byte *in = (byte*)&val;
Paul Sokolovsky0f836ef2014-04-20 05:19:10 +0300218 switch (val_type) {
219 case 'O':
220 in = (byte*)&val_in;
221 break;
222 default:
223 val = mp_obj_get_int(val_in);
224 }
225
Paul Sokolovsky5fa5ca42014-07-05 23:43:00 +0300226 mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
Paul Sokolovsky62044602014-04-19 03:13:15 +0300227}
228
Paul Sokolovskyef9124f2014-04-11 03:46:09 +0300229void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in) {
Damien George71e9bfa2014-04-18 23:28:12 +0100230 switch (typecode) {
Damien Georgefb510b32014-06-01 13:32:54 +0100231#if MICROPY_PY_BUILTINS_FLOAT
Damien George71e9bfa2014-04-18 23:28:12 +0100232 case 'f':
233 ((float*)p)[index] = mp_obj_float_get(val_in);
234 break;
235 case 'd':
236 ((double*)p)[index] = mp_obj_float_get(val_in);
237 break;
238#endif
239 default:
240 mp_binary_set_val_array_from_int(typecode, p, index, mp_obj_get_int(val_in));
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200241 }
Damien George71e9bfa2014-04-18 23:28:12 +0100242}
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200243
Damien George40f3c022014-07-03 13:25:24 +0100244void mp_binary_set_val_array_from_int(char typecode, void *p, int index, mp_int_t val) {
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200245 switch (typecode) {
246 case 'b':
247 ((int8_t*)p)[index] = val;
248 break;
249 case BYTEARRAY_TYPECODE:
250 case 'B':
251 val = ((uint8_t*)p)[index] = val;
252 break;
253 case 'h':
254 val = ((int16_t*)p)[index] = val;
255 break;
256 case 'H':
257 val = ((uint16_t*)p)[index] = val;
258 break;
259 case 'i':
260 case 'l':
261 ((int32_t*)p)[index] = val;
262 break;
263 case 'I':
264 case 'L':
265 ((uint32_t*)p)[index] = val;
266 break;
267#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
268 case 'q':
269 case 'Q':
270 assert(0);
271 ((long long*)p)[index] = val;
272 break;
273#endif
Damien Georgefb510b32014-06-01 13:32:54 +0100274#if MICROPY_PY_BUILTINS_FLOAT
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200275 case 'f':
Damien George71e9bfa2014-04-18 23:28:12 +0100276 ((float*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200277 break;
278 case 'd':
Damien George71e9bfa2014-04-18 23:28:12 +0100279 ((double*)p)[index] = val;
Paul Sokolovsky8bc35162014-02-14 17:16:35 +0200280 break;
281#endif
282 }
283}