From 9336ee320a85527942d9ca2ddb95221d90582da0 Mon Sep 17 00:00:00 2001
From: Damien George <damien.p.george@gmail.com>
Date: Mon, 6 Oct 2014 15:05:35 +0000
Subject: [PATCH] py: Make mp_binary_set_val work on big endian machine.

---
 extmod/moductypes.c |  2 +-
 py/binary.c         | 58 ++++++++++++++++++++++-----------------------
 py/binary.h         |  4 ++--
 py/modstruct.c      |  4 ++--
 4 files changed, 33 insertions(+), 35 deletions(-)

diff --git a/extmod/moductypes.c b/extmod/moductypes.c
index 3e35ed682..bc1824765 100644
--- a/extmod/moductypes.c
+++ b/extmod/moductypes.c
@@ -401,7 +401,7 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set
                     set_aligned_basic(val_type & 6, self->addr + offset, val);
                 } else {
                     mp_binary_set_int(GET_SCALAR_SIZE(val_type & 7), self->flags == LAYOUT_BIG_ENDIAN,
-                        self->addr + offset, (byte*)&val);
+                        self->addr + offset, val);
                 }
                 return set_val; // just !MP_OBJ_NULL
             }
diff --git a/py/binary.c b/py/binary.c
index 1201ec34f..fed69f9d1 100644
--- a/py/binary.c
+++ b/py/binary.c
@@ -140,23 +140,23 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, mp_uint_t index) {
 // The long long type is guaranteed to hold at least 64 bits, and size is at
 // most 8 (for q and Q), so we will always be able to parse the given data
 // and fit it into a long long.
-long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p) {
+long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src) {
     int delta;
     if (!big_endian) {
         delta = -1;
-        p += size - 1;
+        src += size - 1;
     } else {
         delta = 1;
     }
 
     long long val = 0;
-    if (is_signed && *p & 0x80) {
+    if (is_signed && *src & 0x80) {
         val = -1;
     }
     for (uint i = 0; i < size; i++) {
         val <<= 8;
-        val |= *p;
-        p += delta;
+        val |= *src;
+        src += delta;
     }
 
     return val;
@@ -201,20 +201,22 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr) {
     }
 }
 
-void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr) {
-    int in_delta, out_delta;
-    if (big_endian) {
-        in_delta = -1;
-        out_delta = 1;
-        val_ptr += val_sz - 1;
+void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val) {
+    if (MP_ENDIANNESS_LITTLE && !big_endian) {
+        memcpy(dest, &val, val_sz);
+    } else if (MP_ENDIANNESS_BIG && big_endian) {
+        // only copy the least-significant val_sz bytes
+        memcpy(dest, (byte*)&val + sizeof(mp_uint_t) - val_sz, val_sz);
     } else {
-        in_delta = out_delta = 1;
-    }
-
-    for (uint i = val_sz; i > 0; i--) {
-        *p = *val_ptr;
-        p += out_delta;
-        val_ptr += in_delta;
+        const byte *src;
+        if (MP_ENDIANNESS_LITTLE) {
+            src = (const byte*)&val + val_sz;
+        } else {
+            src = (const byte*)&val + sizeof(mp_uint_t);
+        }
+        while (val_sz--) {
+            *dest++ = *--src;
+        }
     }
 }
 
@@ -226,28 +228,24 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **
     if (struct_type == '@') {
         // Make pointer aligned
         p = (byte*)(((mp_uint_t)p + align - 1) & ~((mp_uint_t)align - 1));
-        #if MP_ENDIANNESS_LITTLE
-        struct_type = '<';
-        #else
-        struct_type = '>';
-        #endif
+        if (MP_ENDIANNESS_LITTLE) {
+            struct_type = '<';
+        } else {
+            struct_type = '>';
+        }
     }
     *ptr = p + size;
 
-#if MP_ENDIANNESS_BIG
-#error Not implemented
-#endif
-    mp_int_t val;
-    byte *in = (byte*)&val;
+    mp_uint_t val;
     switch (val_type) {
         case 'O':
-            in = (byte*)&val_in;
+            val = (mp_uint_t)val_in;
             break;
         default:
             val = mp_obj_get_int(val_in);
     }
 
-    mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, in);
+    mp_binary_set_int(MIN(size, sizeof(val)), struct_type == '>', p, val);
 }
 
 void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t val_in) {
diff --git a/py/binary.h b/py/binary.h
index 2a63ba992..dc9d3f680 100644
--- a/py/binary.h
+++ b/py/binary.h
@@ -34,5 +34,5 @@ void mp_binary_set_val_array(char typecode, void *p, mp_uint_t index, mp_obj_t v
 void mp_binary_set_val_array_from_int(char typecode, void *p, mp_uint_t index, mp_int_t val);
 mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte **ptr);
 void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte **ptr);
-long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, byte *p);
-void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *p, byte *val_ptr);
+long long mp_binary_get_int(mp_uint_t size, bool is_signed, bool big_endian, const byte *src);
+void mp_binary_set_int(mp_uint_t val_sz, bool big_endian, byte *dest, mp_uint_t val);
diff --git a/py/modstruct.c b/py/modstruct.c
index 8122a9668..8c0cafda0 100644
--- a/py/modstruct.c
+++ b/py/modstruct.c
@@ -160,7 +160,7 @@ STATIC mp_obj_t struct_unpack(mp_obj_t fmt_in, mp_obj_t data_in) {
 }
 MP_DEFINE_CONST_FUN_OBJ_2(struct_unpack_obj, struct_unpack);
 
-STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
+STATIC mp_obj_t struct_pack(mp_uint_t n_args, const mp_obj_t *args) {
     // TODO: "The arguments must match the values required by the format exactly."
     const char *fmt = mp_obj_str_get_str(args[0]);
     char fmt_type = get_fmt_type(&fmt);
@@ -169,7 +169,7 @@ STATIC mp_obj_t struct_pack(uint n_args, mp_obj_t *args) {
     mp_obj_t res = mp_obj_str_builder_start(&mp_type_bytes, size, &p);
     memset(p, 0, size);
 
-    for (uint i = 1; i < n_args; i++) {
+    for (mp_uint_t i = 1; i < n_args; i++) {
         mp_uint_t sz = 1;
         if (unichar_isdigit(*fmt)) {
             sz = get_fmt_num(&fmt);
-- 
GitLab