diff --git a/py/binary.c b/py/binary.c index 982c238365..1ddf4569b9 100644 --- a/py/binary.c +++ b/py/binary.c @@ -78,25 +78,54 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index) { } #define is_signed(typecode) (typecode > 'Z') -mp_obj_t mp_binary_get_val_unaligned(char typecode, byte **ptr) { - char type = '<'; +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) { byte *p = *ptr; - uint size = 0, align = 0; - switch (type) { + uint size = 0; + switch (struct_type) { case '<': case '>': - switch (typecode) { + switch (val_type) { case 'b': case 'B': size = 1; break; case 'h': case 'H': size = 2; break; case 'i': case 'I': size = 4; break; + case 'l': case 'L': + size = 4; break; + } + break; + case '@': { + // TODO: + // The simplest heuristic for alignment is to align by value + // size, but that doesn't work for "bigger than int" types, + // for example, long long may very well have long alignment + // So, we introduce separate alignment handling, but having + // formal support for that is different from actually supporting + // particular (or any) ABI. + uint align = 0; + switch (val_type) { + case 'b': case 'B': + align = size = 1; break; + case 'h': case 'H': + align = size = sizeof(short); break; + case 'i': case 'I': + align = size = sizeof(int); break; + case 'l': case 'L': + align = size = sizeof(long); break; } + // Make pointer aligned + p = (byte*)(((machine_uint_t)p + align - 1) & ~(align - 1)); + #if MP_ENDIANNESS_LITTLE + struct_type = '<'; + #else + struct_type = '>'; + #endif break; + } } int delta; - if (type == '<') { + if (struct_type == '<') { delta = -1; p += size - 1; } else { @@ -104,7 +133,7 @@ mp_obj_t mp_binary_get_val_unaligned(char typecode, byte **ptr) { } machine_int_t val = 0; - if (is_signed(typecode) && *p & 0x80) { + if (is_signed(val_type) && *p & 0x80) { val = -1; } for (uint i = 0; i < size; i++) { @@ -113,8 +142,8 @@ mp_obj_t mp_binary_get_val_unaligned(char typecode, byte **ptr) { p += delta; } - *ptr += size + align; - if (is_signed(typecode)) { + *ptr += size; + if (is_signed(val_type)) { return mp_obj_new_int(val); } else { return mp_obj_new_int_from_uint(val); diff --git a/py/binary.h b/py/binary.h index 772a1a6729..e9fb38f13f 100644 --- a/py/binary.h +++ b/py/binary.h @@ -3,6 +3,6 @@ #define BYTEARRAY_TYPECODE 0 int mp_binary_get_size(char typecode); -mp_obj_t mp_binary_get_val(char typecode, void *p, int index); -mp_obj_t mp_binary_get_val_unaligned(char typecode, byte **ptr); -void mp_binary_set_val(char typecode, void *p, int index, mp_obj_t val_in); +mp_obj_t mp_binary_get_val_array(char typecode, void *p, int index); +mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr); +void mp_binary_set_val_array(char typecode, void *p, int index, mp_obj_t val_in); diff --git a/py/modstruct.c b/py/modstruct.c index 328ced9131..3b9679a4c2 100644 --- a/py/modstruct.c +++ b/py/modstruct.c @@ -37,7 +37,7 @@ STATIC uint calcsize_items(const char *fmt) { STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) { const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); - assert(fmt_type == '<' || fmt_type == '>'); (void)fmt_type; + (void)fmt_type; machine_uint_t size; for (size = 0; *fmt; fmt++) { int sz = mp_binary_get_size(*fmt); @@ -53,7 +53,6 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) { // TODO: "The buffer must contain exactly the amount of data required by the format (len(bytes) must equal calcsize(fmt))." const char *fmt = mp_obj_str_get_str(fmt_in); char fmt_type = get_fmt_type(&fmt); - assert(fmt_type == '<' || fmt_type == '>'); (void)fmt_type; uint size = calcsize_items(fmt); mp_obj_tuple_t *res = mp_obj_new_tuple(size, NULL); buffer_info_t bufinfo; @@ -61,7 +60,7 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) { byte *p = bufinfo.buf; for (uint i = 0; i < size; i++) { - mp_obj_t item = mp_binary_get_val_unaligned(*fmt++, &p); + mp_obj_t item = mp_binary_get_val(fmt_type, *fmt++, &p); res->items[i] = item; } return res; diff --git a/tests/basics/struct1.py b/tests/basics/struct1.py index db0d823f68..a32979bff9 100644 --- a/tests/basics/struct1.py +++ b/tests/basics/struct1.py @@ -3,3 +3,6 @@ print(struct.calcsize("bI")) print(struct.unpack(">bI", b"\x80\0\0\x01\0")) + +# 32-bit little-endian specific +#print(struct.unpack("bI", b"\x80\xaa\x55\xaa\0\0\x01\0"))