Skip to content
This repository was archived by the owner on Sep 16, 2024. It is now read-only.

ustruct: Pull in ustruct module from the Micropython.org tree #66

Merged
merged 1 commit into from
Sep 21, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 44 additions & 46 deletions py/modstruct.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
Expand Down Expand Up @@ -82,47 +82,38 @@ STATIC mp_uint_t get_fmt_num(const char **p) {
return val;
}

STATIC uint calcsize_items(const char *fmt) {
uint cnt = 0;
while (*fmt) {
int num = 1;
if (unichar_isdigit(*fmt)) {
num = get_fmt_num(&fmt);
if (*fmt == 's') {
num = 1;
}
}
cnt += num;
fmt++;
}
return cnt;
}

STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char *fmt = mp_obj_str_get_str(fmt_in);
STATIC size_t calc_size_items(const char *fmt, size_t *total_sz) {
char fmt_type = get_fmt_type(&fmt);
mp_uint_t size;
size_t total_cnt = 0;
size_t size;
for (size = 0; *fmt; fmt++) {
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
cnt = get_fmt_num(&fmt);
}

if (*fmt == 's') {
total_cnt += 1;
size += cnt;
} else {
total_cnt += cnt;
mp_uint_t align;
size_t sz = mp_binary_get_size(fmt_type, *fmt, &align);
if (sz == 0) {
mp_raise_ValueError("unsupported format");
}
while (cnt--) {
// Apply alignment
size = (size + align - 1) & ~(align - 1);
size += sz;
}
}
}
*total_sz = size;
return total_cnt;
}

STATIC mp_obj_t struct_calcsize(mp_obj_t fmt_in) {
const char *fmt = mp_obj_str_get_str(fmt_in);
size_t size;
calc_size_items(fmt, &size);
return MP_OBJ_NEW_SMALL_INT(size);
}
MP_DEFINE_CONST_FUN_OBJ_1(struct_calcsize_obj, struct_calcsize);
Expand All @@ -133,8 +124,9 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
// Since we implement unpack and unpack_from using the same function
// we relax the "exact" requirement, and only implement "big enough".
const char *fmt = mp_obj_str_get_str(args[0]);
size_t total_sz;
size_t num_items = calc_size_items(fmt, &total_sz);
char fmt_type = get_fmt_type(&fmt);
uint num_items = calcsize_items(fmt);
mp_obj_tuple_t *res = MP_OBJ_TO_PTR(mp_obj_new_tuple(num_items, NULL));
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
Expand All @@ -155,21 +147,23 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
p += offset;
}

for (uint i = 0; i < num_items;) {
mp_uint_t sz = 1;
// Check that the input buffer is big enough to unpack all the values
if (p + total_sz > end_p) {
mp_raise_ValueError("buffer too small");
}

for (size_t i = 0; i < num_items;) {
mp_uint_t cnt = 1;
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
}
if (p + sz > end_p) {
mp_raise_ValueError("buffer too small");
cnt = get_fmt_num(&fmt);
}
mp_obj_t item;
if (*fmt == 's') {
item = mp_obj_new_bytes(p, sz);
p += sz;
item = mp_obj_new_bytes(p, cnt);
p += cnt;
res->items[i++] = item;
} else {
while (sz--) {
while (cnt--) {
item = mp_binary_get_val(fmt_type, *fmt, &p);
res->items[i++] = item;
}
Expand All @@ -180,36 +174,35 @@ STATIC mp_obj_t struct_unpack_from(size_t n_args, const mp_obj_t *args) {
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_unpack_from_obj, 2, 3, struct_unpack_from);

STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, byte* end_p, size_t n_args, const mp_obj_t *args) {
// This function assumes there is enough room in p to store all the values
STATIC void struct_pack_into_internal(mp_obj_t fmt_in, byte *p, size_t n_args, const mp_obj_t *args) {
const char *fmt = mp_obj_str_get_str(fmt_in);
char fmt_type = get_fmt_type(&fmt);

size_t i;
for (i = 0; i < n_args;) {
mp_uint_t sz = 1;
mp_uint_t cnt = 1;
if (*fmt == '\0') {
// more arguments given than used by format string; CPython raises struct.error here
break;
}
if (unichar_isdigit(*fmt)) {
sz = get_fmt_num(&fmt);
}
if (p + sz > end_p) {
mp_raise_ValueError("buffer too small");
cnt = get_fmt_num(&fmt);
}

if (*fmt == 's') {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[i++], &bufinfo, MP_BUFFER_READ);
mp_uint_t to_copy = sz;
mp_uint_t to_copy = cnt;
if (bufinfo.len < to_copy) {
to_copy = bufinfo.len;
}
memcpy(p, bufinfo.buf, to_copy);
memset(p + to_copy, 0, sz - to_copy);
p += sz;
memset(p + to_copy, 0, cnt - to_copy);
p += cnt;
} else {
while (sz--) {
// If we run out of args then we just finish; CPython would raise struct.error
while (cnt-- && i < n_args) {
mp_binary_set_val(fmt_type, *fmt, args[i++], &p);
}
}
Expand All @@ -224,8 +217,7 @@ STATIC mp_obj_t struct_pack(size_t n_args, const mp_obj_t *args) {
vstr_init_len(&vstr, size);
byte *p = (byte*)vstr.buf;
memset(p, 0, size);
byte *end_p = &p[size];
struct_pack_into_internal(args[0], p, end_p, n_args - 1, &args[1]);
struct_pack_into_internal(args[0], p, n_args - 1, &args[1]);
return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_obj, 1, MP_OBJ_FUN_ARGS_MAX, struct_pack);
Expand All @@ -245,7 +237,13 @@ STATIC mp_obj_t struct_pack_into(size_t n_args, const mp_obj_t *args) {
byte *end_p = &p[bufinfo.len];
p += offset;

struct_pack_into_internal(args[0], p, end_p, n_args - 3, &args[3]);
// Check that the output buffer is big enough to hold all the values
mp_int_t sz = MP_OBJ_SMALL_INT_VALUE(struct_calcsize(args[0]));
if (p + sz > end_p) {
mp_raise_ValueError("buffer too small");
}

struct_pack_into_internal(args[0], p, n_args - 3, &args[3]);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(struct_pack_into_obj, 3, MP_OBJ_FUN_ARGS_MAX, struct_pack_into);
Expand Down