Skip to content

Commit 6582d64

Browse files
committed
modstruct: Refactor to support both LE and BE packed structs.
1 parent 2b9419b commit 6582d64

File tree

4 files changed

+45
-45
lines changed

4 files changed

+45
-45
lines changed

py/binary.c

Lines changed: 39 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -77,50 +77,48 @@ mp_obj_t mp_binary_get_val(char typecode, void *p, int index) {
7777
return MP_OBJ_NEW_SMALL_INT(val);
7878
}
7979

80-
mp_obj_t mp_binary_get_val_unaligned_le(char typecode, byte **ptr) {
81-
machine_int_t val = 0;
80+
#define is_signed(typecode) (typecode > 'Z')
81+
mp_obj_t mp_binary_get_val_unaligned(char typecode, byte **ptr) {
82+
char type = '<';
8283
byte *p = *ptr;
83-
switch (typecode) {
84-
case 'b':
85-
val = (int8_t)*p++;
86-
break;
87-
case BYTEARRAY_TYPECODE:
88-
case 'B':
89-
val = *p++;
90-
break;
91-
case 'h':
92-
val = (int16_t)((p[1] << 8) | p[0]);
93-
break;
94-
case 'H':
95-
val = (p[1] << 8) | p[0];
84+
uint size = 0, align = 0;
85+
switch (type) {
86+
case '<': case '>':
87+
switch (typecode) {
88+
case 'b': case 'B':
89+
size = 1; break;
90+
case 'h': case 'H':
91+
size = 2; break;
92+
case 'i': case 'I':
93+
size = 4; break;
94+
}
9695
break;
97-
case 'i':
98-
case 'l':
99-
val = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
100-
*ptr = p + 4;
101-
return mp_obj_new_int(val);
102-
case 'I':
103-
case 'L':
104-
val = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0];
105-
*ptr = p + 4;
106-
return mp_obj_new_int_from_uint(val);
107-
#if 0 //TODO
108-
#if MICROPY_LONGINT_IMPL != MICROPY_LONGINT_IMPL_NONE
109-
case 'q':
110-
case 'Q':
111-
// TODO: Explode API more to cover signedness
112-
return mp_obj_new_int_from_ll(((long long*)p)[index]);
113-
#endif
114-
#if MICROPY_ENABLE_FLOAT
115-
case 'f':
116-
return mp_obj_new_float(((float*)p)[index]);
117-
case 'd':
118-
return mp_obj_new_float(((double*)p)[index]);
119-
#endif
120-
#endif
12196
}
122-
*ptr = p;
123-
return MP_OBJ_NEW_SMALL_INT(val);
97+
98+
int delta;
99+
if (type == '<') {
100+
delta = -1;
101+
p += size - 1;
102+
} else {
103+
delta = 1;
104+
}
105+
106+
machine_int_t val = 0;
107+
if (is_signed(typecode) && *p & 0x80) {
108+
val = -1;
109+
}
110+
for (uint i = 0; i < size; i++) {
111+
val <<= 8;
112+
val |= *p;
113+
p += delta;
114+
}
115+
116+
*ptr += size + align;
117+
if (is_signed(typecode)) {
118+
return mp_obj_new_int(val);
119+
} else {
120+
return mp_obj_new_int_from_uint(val);
121+
}
124122
}
125123

126124
void mp_binary_set_val(char typecode, void *p, int index, mp_obj_t val_in) {

py/binary.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44

55
int mp_binary_get_size(char typecode);
66
mp_obj_t mp_binary_get_val(char typecode, void *p, int index);
7-
mp_obj_t mp_binary_get_val_unaligned_le(char typecode, byte **ptr);
7+
mp_obj_t mp_binary_get_val_unaligned(char typecode, byte **ptr);
88
void mp_binary_set_val(char typecode, void *p, int index, mp_obj_t val_in);

py/modstruct.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ STATIC uint calcsize_items(const char *fmt) {
3737
STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
3838
const char *fmt = mp_obj_str_get_str(fmt_in);
3939
char fmt_type = get_fmt_type(&fmt);
40-
assert(fmt_type == '<'); (void)fmt_type;
40+
assert(fmt_type == '<' || fmt_type == '>'); (void)fmt_type;
4141
machine_uint_t size;
4242
for (size = 0; *fmt; fmt++) {
4343
int sz = mp_binary_get_size(*fmt);
@@ -53,15 +53,15 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) {
5353
// TODO: "The buffer must contain exactly the amount of data required by the format (len(bytes) must equal calcsize(fmt))."
5454
const char *fmt = mp_obj_str_get_str(fmt_in);
5555
char fmt_type = get_fmt_type(&fmt);
56-
assert(fmt_type == '<'); (void)fmt_type;
56+
assert(fmt_type == '<' || fmt_type == '>'); (void)fmt_type;
5757
uint size = calcsize_items(fmt);
5858
mp_obj_tuple_t *res = mp_obj_new_tuple(size, NULL);
5959
buffer_info_t bufinfo;
6060
mp_get_buffer_raise(data_in, &bufinfo);
6161
byte *p = bufinfo.buf;
6262

6363
for (uint i = 0; i < size; i++) {
64-
mp_obj_t item = mp_binary_get_val_unaligned_le(*fmt++, &p);
64+
mp_obj_t item = mp_binary_get_val_unaligned(*fmt++, &p);
6565
res->items[i] = item;
6666
}
6767
return res;

tests/basics/struct1.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
import struct
22
print(struct.calcsize("<bI"))
33
print(struct.unpack("<bI", b"\x80\0\0\x01\0"))
4+
print(struct.calcsize(">bI"))
5+
print(struct.unpack(">bI", b"\x80\0\0\x01\0"))

0 commit comments

Comments
 (0)