File openapv-fix-md5-hash-mismatch-on-big-endian.patch of Package openapv

From 2d70d279ed34fe8b26c1a25310e7e630687c3f09 Mon Sep 17 00:00:00 2001
From: Anemptyship <hanbin1931@gmail.com>
Date: Fri, 9 Jan 2026 09:20:32 +0000
Subject: [PATCH 1/3] Fix MD5 hash mismatch on big-endian systems (s390x)

- Make md5_trans() endian-safe by explicitly decoding bytes to u32 words
- Use compile-time check to preserve zero-copy performance on little-endian
- Fix md5_finish() to write length and digest in little-endian byte order
- Add md5_update_16() for safe 16-bit pixel data processing

Signed-off-by: Anemptyship <hanbin1931@gmail.com>
---
 src/oapv_util.c | 251 +++++++++++++++++++++++++-----------------------
 1 file changed, 133 insertions(+), 118 deletions(-)

diff --git a/src/oapv_util.c b/src/oapv_util.c
index f6a0cec..913dd34 100644
--- a/src/oapv_util.c
+++ b/src/oapv_util.c
@@ -40,97 +40,110 @@
 #define HH(x, y, z) (x ^ y ^ z)
 #define II(x, y, z) (y ^ (x | ~z))
 
-static void md5_trans(u32 *buf, u32 *msg)
+static void md5_trans(u32 *buf, const u8 *msg)
 {
     register u32 a, b, c, d;
 
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
+    const u32 *blk = (const u32 *)msg;
+#else
+    u32 x[16];
+    int i;
+
+    for (i = 0; i < 16; i++) {
+        x[i] = ((u32)msg[i*4+0]) | (((u32)msg[i*4+1]) << 8) | 
+               (((u32)msg[i*4+2]) << 16) | (((u32)msg[i*4+3]) << 24);
+    }
+    const u32 *blk = x;
+#endif
+
     a = buf[0];
     b = buf[1];
     c = buf[2];
     d = buf[3];
 
-    MD5FUNC(FF, a, b, c, d, msg[0], 7, 0xd76aa478);  /* 1 */
-    MD5FUNC(FF, d, a, b, c, msg[1], 12, 0xe8c7b756); /* 2 */
-    MD5FUNC(FF, c, d, a, b, msg[2], 17, 0x242070db); /* 3 */
-    MD5FUNC(FF, b, c, d, a, msg[3], 22, 0xc1bdceee); /* 4 */
+    MD5FUNC(FF, a, b, c, d, blk[0], 7, 0xd76aa478);  /* 1 */
+    MD5FUNC(FF, d, a, b, c, blk[1], 12, 0xe8c7b756); /* 2 */
+    MD5FUNC(FF, c, d, a, b, blk[2], 17, 0x242070db); /* 3 */
+    MD5FUNC(FF, b, c, d, a, blk[3], 22, 0xc1bdceee); /* 4 */
 
-    MD5FUNC(FF, a, b, c, d, msg[4], 7, 0xf57c0faf);  /* 5 */
-    MD5FUNC(FF, d, a, b, c, msg[5], 12, 0x4787c62a); /* 6 */
-    MD5FUNC(FF, c, d, a, b, msg[6], 17, 0xa8304613); /* 7 */
-    MD5FUNC(FF, b, c, d, a, msg[7], 22, 0xfd469501); /* 8 */
+    MD5FUNC(FF, a, b, c, d, blk[4], 7, 0xf57c0faf);  /* 5 */
+    MD5FUNC(FF, d, a, b, c, blk[5], 12, 0x4787c62a); /* 6 */
+    MD5FUNC(FF, c, d, a, b, blk[6], 17, 0xa8304613); /* 7 */
+    MD5FUNC(FF, b, c, d, a, blk[7], 22, 0xfd469501); /* 8 */
 
-    MD5FUNC(FF, a, b, c, d, msg[8], 7, 0x698098d8);   /* 9 */
-    MD5FUNC(FF, d, a, b, c, msg[9], 12, 0x8b44f7af);  /* 10 */
-    MD5FUNC(FF, c, d, a, b, msg[10], 17, 0xffff5bb1); /* 11 */
-    MD5FUNC(FF, b, c, d, a, msg[11], 22, 0x895cd7be); /* 12 */
+    MD5FUNC(FF, a, b, c, d, blk[8], 7, 0x698098d8);   /* 9 */
+    MD5FUNC(FF, d, a, b, c, blk[9], 12, 0x8b44f7af);  /* 10 */
+    MD5FUNC(FF, c, d, a, b, blk[10], 17, 0xffff5bb1); /* 11 */
+    MD5FUNC(FF, b, c, d, a, blk[11], 22, 0x895cd7be); /* 12 */
 
-    MD5FUNC(FF, a, b, c, d, msg[12], 7, 0x6b901122);  /* 13 */
-    MD5FUNC(FF, d, a, b, c, msg[13], 12, 0xfd987193); /* 14 */
-    MD5FUNC(FF, c, d, a, b, msg[14], 17, 0xa679438e); /* 15 */
-    MD5FUNC(FF, b, c, d, a, msg[15], 22, 0x49b40821); /* 16 */
+    MD5FUNC(FF, a, b, c, d, blk[12], 7, 0x6b901122);  /* 13 */
+    MD5FUNC(FF, d, a, b, c, blk[13], 12, 0xfd987193); /* 14 */
+    MD5FUNC(FF, c, d, a, b, blk[14], 17, 0xa679438e); /* 15 */
+    MD5FUNC(FF, b, c, d, a, blk[15], 22, 0x49b40821); /* 16 */
 
     /* Round 2 */
-    MD5FUNC(GG, a, b, c, d, msg[1], 5, 0xf61e2562);   /* 17 */
-    MD5FUNC(GG, d, a, b, c, msg[6], 9, 0xc040b340);   /* 18 */
-    MD5FUNC(GG, c, d, a, b, msg[11], 14, 0x265e5a51); /* 19 */
-    MD5FUNC(GG, b, c, d, a, msg[0], 20, 0xe9b6c7aa);  /* 20 */
-
-    MD5FUNC(GG, a, b, c, d, msg[5], 5, 0xd62f105d);   /* 21 */
-    MD5FUNC(GG, d, a, b, c, msg[10], 9, 0x2441453);   /* 22 */
-    MD5FUNC(GG, c, d, a, b, msg[15], 14, 0xd8a1e681); /* 23 */
-    MD5FUNC(GG, b, c, d, a, msg[4], 20, 0xe7d3fbc8);  /* 24 */
-
-    MD5FUNC(GG, a, b, c, d, msg[9], 5, 0x21e1cde6);  /* 25 */
-    MD5FUNC(GG, d, a, b, c, msg[14], 9, 0xc33707d6); /* 26 */
-    MD5FUNC(GG, c, d, a, b, msg[3], 14, 0xf4d50d87); /* 27 */
-    MD5FUNC(GG, b, c, d, a, msg[8], 20, 0x455a14ed); /* 28 */
-
-    MD5FUNC(GG, a, b, c, d, msg[13], 5, 0xa9e3e905);  /* 29 */
-    MD5FUNC(GG, d, a, b, c, msg[2], 9, 0xfcefa3f8);   /* 30 */
-    MD5FUNC(GG, c, d, a, b, msg[7], 14, 0x676f02d9);  /* 31 */
-    MD5FUNC(GG, b, c, d, a, msg[12], 20, 0x8d2a4c8a); /* 32 */
+    MD5FUNC(GG, a, b, c, d, blk[1], 5, 0xf61e2562);   /* 17 */
+    MD5FUNC(GG, d, a, b, c, blk[6], 9, 0xc040b340);   /* 18 */
+    MD5FUNC(GG, c, d, a, b, blk[11], 14, 0x265e5a51); /* 19 */
+    MD5FUNC(GG, b, c, d, a, blk[0], 20, 0xe9b6c7aa);  /* 20 */
+
+    MD5FUNC(GG, a, b, c, d, blk[5], 5, 0xd62f105d);   /* 21 */
+    MD5FUNC(GG, d, a, b, c, blk[10], 9, 0x2441453);   /* 22 */
+    MD5FUNC(GG, c, d, a, b, blk[15], 14, 0xd8a1e681); /* 23 */
+    MD5FUNC(GG, b, c, d, a, blk[4], 20, 0xe7d3fbc8);  /* 24 */
+
+    MD5FUNC(GG, a, b, c, d, blk[9], 5, 0x21e1cde6);  /* 25 */
+    MD5FUNC(GG, d, a, b, c, blk[14], 9, 0xc33707d6); /* 26 */
+    MD5FUNC(GG, c, d, a, b, blk[3], 14, 0xf4d50d87); /* 27 */
+    MD5FUNC(GG, b, c, d, a, blk[8], 20, 0x455a14ed); /* 28 */
+
+    MD5FUNC(GG, a, b, c, d, blk[13], 5, 0xa9e3e905);  /* 29 */
+    MD5FUNC(GG, d, a, b, c, blk[2], 9, 0xfcefa3f8);   /* 30 */
+    MD5FUNC(GG, c, d, a, b, blk[7], 14, 0x676f02d9);  /* 31 */
+    MD5FUNC(GG, b, c, d, a, blk[12], 20, 0x8d2a4c8a); /* 32 */
 
     /* Round 3 */
-    MD5FUNC(HH, a, b, c, d, msg[5], 4, 0xfffa3942);   /* 33 */
-    MD5FUNC(HH, d, a, b, c, msg[8], 11, 0x8771f681);  /* 34 */
-    MD5FUNC(HH, c, d, a, b, msg[11], 16, 0x6d9d6122); /* 35 */
-    MD5FUNC(HH, b, c, d, a, msg[14], 23, 0xfde5380c); /* 36 */
-
-    MD5FUNC(HH, a, b, c, d, msg[1], 4, 0xa4beea44);   /* 37 */
-    MD5FUNC(HH, d, a, b, c, msg[4], 11, 0x4bdecfa9);  /* 38 */
-    MD5FUNC(HH, c, d, a, b, msg[7], 16, 0xf6bb4b60);  /* 39 */
-    MD5FUNC(HH, b, c, d, a, msg[10], 23, 0xbebfbc70); /* 40 */
-
-    MD5FUNC(HH, a, b, c, d, msg[13], 4, 0x289b7ec6); /* 41 */
-    MD5FUNC(HH, d, a, b, c, msg[0], 11, 0xeaa127fa); /* 42 */
-    MD5FUNC(HH, c, d, a, b, msg[3], 16, 0xd4ef3085); /* 43 */
-    MD5FUNC(HH, b, c, d, a, msg[6], 23, 0x4881d05);  /* 44 */
-
-    MD5FUNC(HH, a, b, c, d, msg[9], 4, 0xd9d4d039);   /* 45 */
-    MD5FUNC(HH, d, a, b, c, msg[12], 11, 0xe6db99e5); /* 46 */
-    MD5FUNC(HH, c, d, a, b, msg[15], 16, 0x1fa27cf8); /* 47 */
-    MD5FUNC(HH, b, c, d, a, msg[2], 23, 0xc4ac5665);  /* 48 */
+    MD5FUNC(HH, a, b, c, d, blk[5], 4, 0xfffa3942);   /* 33 */
+    MD5FUNC(HH, d, a, b, c, blk[8], 11, 0x8771f681);  /* 34 */
+    MD5FUNC(HH, c, d, a, b, blk[11], 16, 0x6d9d6122); /* 35 */
+    MD5FUNC(HH, b, c, d, a, blk[14], 23, 0xfde5380c); /* 36 */
+
+    MD5FUNC(HH, a, b, c, d, blk[1], 4, 0xa4beea44);   /* 37 */
+    MD5FUNC(HH, d, a, b, c, blk[4], 11, 0x4bdecfa9);  /* 38 */
+    MD5FUNC(HH, c, d, a, b, blk[7], 16, 0xf6bb4b60);  /* 39 */
+    MD5FUNC(HH, b, c, d, a, blk[10], 23, 0xbebfbc70); /* 40 */
+
+    MD5FUNC(HH, a, b, c, d, blk[13], 4, 0x289b7ec6); /* 41 */
+    MD5FUNC(HH, d, a, b, c, blk[0], 11, 0xeaa127fa); /* 42 */
+    MD5FUNC(HH, c, d, a, b, blk[3], 16, 0xd4ef3085); /* 43 */
+    MD5FUNC(HH, b, c, d, a, blk[6], 23, 0x4881d05);  /* 44 */
+
+    MD5FUNC(HH, a, b, c, d, blk[9], 4, 0xd9d4d039);   /* 45 */
+    MD5FUNC(HH, d, a, b, c, blk[12], 11, 0xe6db99e5); /* 46 */
+    MD5FUNC(HH, c, d, a, b, blk[15], 16, 0x1fa27cf8); /* 47 */
+    MD5FUNC(HH, b, c, d, a, blk[2], 23, 0xc4ac5665);  /* 48 */
 
     /* Round 4 */
-    MD5FUNC(II, a, b, c, d, msg[0], 6, 0xf4292244);   /* 49 */
-    MD5FUNC(II, d, a, b, c, msg[7], 10, 0x432aff97);  /* 50 */
-    MD5FUNC(II, c, d, a, b, msg[14], 15, 0xab9423a7); /* 51 */
-    MD5FUNC(II, b, c, d, a, msg[5], 21, 0xfc93a039);  /* 52 */
-
-    MD5FUNC(II, a, b, c, d, msg[12], 6, 0x655b59c3);  /* 53 */
-    MD5FUNC(II, d, a, b, c, msg[3], 10, 0x8f0ccc92);  /* 54 */
-    MD5FUNC(II, c, d, a, b, msg[10], 15, 0xffeff47d); /* 55 */
-    MD5FUNC(II, b, c, d, a, msg[1], 21, 0x85845dd1);  /* 56 */
-
-    MD5FUNC(II, a, b, c, d, msg[8], 6, 0x6fa87e4f);   /* 57 */
-    MD5FUNC(II, d, a, b, c, msg[15], 10, 0xfe2ce6e0); /* 58 */
-    MD5FUNC(II, c, d, a, b, msg[6], 15, 0xa3014314);  /* 59 */
-    MD5FUNC(II, b, c, d, a, msg[13], 21, 0x4e0811a1); /* 60 */
-
-    MD5FUNC(II, a, b, c, d, msg[4], 6, 0xf7537e82);   /* 61 */
-    MD5FUNC(II, d, a, b, c, msg[11], 10, 0xbd3af235); /* 62 */
-    MD5FUNC(II, c, d, a, b, msg[2], 15, 0x2ad7d2bb);  /* 63 */
-    MD5FUNC(II, b, c, d, a, msg[9], 21, 0xeb86d391);  /* 64 */
+    MD5FUNC(II, a, b, c, d, blk[0], 6, 0xf4292244);   /* 49 */
+    MD5FUNC(II, d, a, b, c, blk[7], 10, 0x432aff97);  /* 50 */
+    MD5FUNC(II, c, d, a, b, blk[14], 15, 0xab9423a7); /* 51 */
+    MD5FUNC(II, b, c, d, a, blk[5], 21, 0xfc93a039);  /* 52 */
+
+    MD5FUNC(II, a, b, c, d, blk[12], 6, 0x655b59c3);  /* 53 */
+    MD5FUNC(II, d, a, b, c, blk[3], 10, 0x8f0ccc92);  /* 54 */
+    MD5FUNC(II, c, d, a, b, blk[10], 15, 0xffeff47d); /* 55 */
+    MD5FUNC(II, b, c, d, a, blk[1], 21, 0x85845dd1);  /* 56 */
+
+    MD5FUNC(II, a, b, c, d, blk[8], 6, 0x6fa87e4f);   /* 57 */
+    MD5FUNC(II, d, a, b, c, blk[15], 10, 0xfe2ce6e0); /* 58 */
+    MD5FUNC(II, c, d, a, b, blk[6], 15, 0xa3014314);  /* 59 */
+    MD5FUNC(II, b, c, d, a, blk[13], 21, 0x4e0811a1); /* 60 */
+
+    MD5FUNC(II, a, b, c, d, blk[4], 6, 0xf7537e82);   /* 61 */
+    MD5FUNC(II, d, a, b, c, blk[11], 10, 0xbd3af235); /* 62 */
+    MD5FUNC(II, c, d, a, b, blk[2], 15, 0x2ad7d2bb);  /* 63 */
+    MD5FUNC(II, b, c, d, a, blk[9], 21, 0xeb86d391);  /* 64 */
 
     buf[0] += a;
     buf[1] += b;
@@ -168,10 +181,10 @@ static void md5_update(oapv_md5_t *md5, void *buf_t, u32 len)
 
     if(len >= part_len) {
         oapv_mcpy(md5->msg + idx, buf, part_len);
-        md5_trans(md5->h, (u32 *)md5->msg);
+        md5_trans(md5->h, md5->msg);
 
         for(i = part_len; i + 63 < len; i += 64) {
-            md5_trans(md5->h, (u32 *)(buf + i));
+            md5_trans(md5->h, buf + i);
         }
         idx = 0;
     }
@@ -186,43 +199,23 @@ static void md5_update(oapv_md5_t *md5, void *buf_t, u32 len)
 
 static void md5_update_16(oapv_md5_t *md5, void *buf_t, u32 len)
 {
-    u16 *buf;
-    u32  i, idx, part_len, j;
-    u8   t[512];
-
-    buf = (u16 *)buf_t;
-    idx = (u32)((md5->bits[0] >> 3) & 0x3f);
-
-    len = len * 2;
-    for(j = 0; j < len; j += 2) {
-        t[j] = (u8)(*(buf));
-        t[j + 1] = *(buf) >> 8;
-        buf++;
-    }
-
-    md5->bits[0] += (len << 3);
-    if(md5->bits[0] < (len << 3)) {
-        (md5->bits[1])++;
-    }
-
-    md5->bits[1] += (len >> 29);
-    part_len = 64 - idx;
-
-    if(len >= part_len) {
-        oapv_mcpy(md5->msg + idx, t, part_len);
-        md5_trans(md5->h, (u32 *)md5->msg);
-
-        for(i = part_len; i + 63 < len; i += 64) {
-            md5_trans(md5->h, (u32 *)(t + i));
+    u16 *buf = (u16 *)buf_t;
+    u8   t[1024];
+    u32  i, j, chunk_len;
+
+    i = 0;
+    while(i < len) {
+        chunk_len = len - i;
+        if(chunk_len > 512)
+            chunk_len = 512;
+
+        for(j = 0; j < chunk_len; j++) {
+            t[j * 2]     = (u8)(buf[i + j]);
+            t[j * 2 + 1] = (u8)(buf[i + j] >> 8);
         }
-        idx = 0;
-    }
-    else {
-        i = 0;
-    }
 
-    if(len - i > 0) {
-        oapv_mcpy(md5->msg + idx, t + i, len - i);
+        md5_update(md5, t, chunk_len * 2);
+        i += chunk_len;
     }
 }
 
@@ -238,18 +231,33 @@ static void md5_finish(oapv_md5_t *md5, u8 digest[16])
 
     if(cnt < 8) {
         oapv_mset(pos, 0, cnt);
-        md5_trans(md5->h, (u32 *)md5->msg);
+        md5_trans(md5->h, md5->msg);
         oapv_mset(md5->msg, 0, 56);
     }
     else {
         oapv_mset(pos, 0, cnt - 8);
     }
 
-    oapv_mcpy((md5->msg + 14 * sizeof(u32)), &md5->bits[0], sizeof(u32));
-    oapv_mcpy((md5->msg + 15 * sizeof(u32)), &md5->bits[1], sizeof(u32));
-
-    md5_trans(md5->h, (u32 *)md5->msg);
-    oapv_mcpy(digest, md5->h, 16);
+    /* Append length in bits - Little Endian */
+    md5->msg[56] = (u8)(md5->bits[0]);
+    md5->msg[57] = (u8)(md5->bits[0] >> 8);
+    md5->msg[58] = (u8)(md5->bits[0] >> 16);
+    md5->msg[59] = (u8)(md5->bits[0] >> 24);
+    md5->msg[60] = (u8)(md5->bits[1]);
+    md5->msg[61] = (u8)(md5->bits[1] >> 8);
+    md5->msg[62] = (u8)(md5->bits[1] >> 16);
+    md5->msg[63] = (u8)(md5->bits[1] >> 24);
+
+    md5_trans(md5->h, md5->msg);
+    
+    /* Store state in digest - Little Endian */
+    for (int i=0; i<4; i++) {
+        digest[i*4+0] = (u8)(md5->h[i]);
+        digest[i*4+1] = (u8)(md5->h[i] >> 8);
+        digest[i*4+2] = (u8)(md5->h[i] >> 16);
+        digest[i*4+3] = (u8)(md5->h[i] >> 24);
+    }
+    
     oapv_mset(md5, 0, sizeof(oapv_md5_t));
 }
 
@@ -263,6 +271,8 @@ void oapv_imgb_set_md5(oapv_imgb_t *imgb)
 
     oapv_md5_t md5[N_C];
     int        i, j;
+    int        b_depth = OAPV_CS_GET_BYTE_DEPTH(imgb->cs);
+
     oapv_assert(imgb != NULL);
     memset(imgb->hash, 0, sizeof(imgb->hash));
 
@@ -270,7 +280,12 @@ void oapv_imgb_set_md5(oapv_imgb_t *imgb)
         md5_init(&md5[i]);
 
         for(j = 0; j < imgb->ah[i]; j++) {
-            md5_update(&md5[i], ((u8 *)imgb->a[i]) + j * imgb->s[i], imgb->aw[i] * 2);
+            if(b_depth >= 2) {
+                md5_update_16(&md5[i], ((u8 *)imgb->a[i]) + j * imgb->s[i], imgb->aw[i]);
+            }
+            else {
+                md5_update(&md5[i], ((u8 *)imgb->a[i]) + j * imgb->s[i], imgb->aw[i]);
+            }
         }
 
         md5_finish(&md5[i], imgb->hash[i]);

From aa7c55a5e829664a75c96f7db1686b7bd8f69938 Mon Sep 17 00:00:00 2001
From: Anemptyship <hanbin1931@gmail.com>
Date: Sun, 18 Jan 2026 04:42:11 +0000
Subject: [PATCH 2/3] Refactor: internalize endianness macros and simplify MD5
 implementation

- oapv_port.h: Introduce cross-platform endianness swap and conversion macros (OAPV_SWAP*, OAPV_LE32_TO_CPU).

- oapv_util.c: Replace manual byte swapping with new macros in MD5 transform to improve readability and maintainability.

- Standardize endianness handling across the codebase.

Signed-off-by: Anemptyship <hanbin1931@gmail.com>
---
 src/oapv_port.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 src/oapv_util.c | 11 +++++------
 2 files changed, 51 insertions(+), 6 deletions(-)

diff --git a/src/oapv_port.h b/src/oapv_port.h
index a084bc1..3edeb2c 100644
--- a/src/oapv_port.h
+++ b/src/oapv_port.h
@@ -203,5 +203,51 @@ static __inline void oapv_mset_16b(s16 *dst, s16 v, int cnt)
 /* CPU information */
 int oapv_get_num_cpu_cores(void);
 
+/* Endianness handling */
+#if defined(__GNUC__) || defined(__clang__)
+#define OAPV_SWAP16(x) __builtin_bswap16(x)
+#define OAPV_SWAP32(x) __builtin_bswap32(x)
+#define OAPV_SWAP64(x) __builtin_bswap64(x)
+#elif defined(_MSC_VER)
+#define OAPV_SWAP16(x) _byteswap_ushort(x)
+#define OAPV_SWAP32(x) _byteswap_ulong(x)
+#define OAPV_SWAP64(x) _byteswap_uint64(x)
+#else
+#define OAPV_SWAP16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
+#define OAPV_SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
+                        (((x) & 0x0000ff00) << 8)  | (((x) & 0x000000ff) << 24))
+#define OAPV_SWAP64(x) ((((x) & 0xff00000000000000ull) >> 56) | \
+                        (((x) & 0x00ff000000000000ull) >> 40) | \
+                        (((x) & 0x0000ff0000000000ull) >> 24) | \
+                        (((x) & 0x000000ff00000000ull) >> 8)  | \
+                        (((x) & 0x00000000ff000000ull) << 8)  | \
+                        (((x) & 0x0000000000ff0000ull) << 24) | \
+                        (((x) & 0x000000000000ff00ull) << 40) | \
+                        (((x) & 0x00000000000000ffull) << 56))
+#endif
+
+#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
+#define OAPV_BIG_ENDIAN 1
+#define OAPV_CPU_TO_LE32(x) OAPV_SWAP32(x)
+#define OAPV_CPU_TO_LE64(x) OAPV_SWAP64(x)
+#define OAPV_LE32_TO_CPU(x) OAPV_SWAP32(x)
+#define OAPV_LE64_TO_CPU(x) OAPV_SWAP64(x)
+#define OAPV_CPU_TO_BE32(x) (x)
+#define OAPV_CPU_TO_BE64(x) (x)
+#define OAPV_BE32_TO_CPU(x) (x)
+#define OAPV_BE64_TO_CPU(x) (x)
+#else
+// Little Endian (Default for x86/ARM)
+#define OAPV_LITTLE_ENDIAN 1
+#define OAPV_CPU_TO_LE32(x) (x)
+#define OAPV_CPU_TO_LE64(x) (x)
+#define OAPV_LE32_TO_CPU(x) (x)
+#define OAPV_LE64_TO_CPU(x) (x)
+#define OAPV_CPU_TO_BE32(x) OAPV_SWAP32(x)
+#define OAPV_CPU_TO_BE64(x) OAPV_SWAP64(x)
+#define OAPV_BE32_TO_CPU(x) OAPV_SWAP32(x)
+#define OAPV_BE64_TO_CPU(x) OAPV_SWAP64(x)
+#endif
+
 #endif /* _OAPV_PORT_H_ */
 
diff --git a/src/oapv_util.c b/src/oapv_util.c
index 913dd34..b369112 100644
--- a/src/oapv_util.c
+++ b/src/oapv_util.c
@@ -44,17 +44,16 @@ static void md5_trans(u32 *buf, const u8 *msg)
 {
     register u32 a, b, c, d;
 
-#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-    const u32 *blk = (const u32 *)msg;
-#else
+#if OAPV_BIG_ENDIAN
     u32 x[16];
     int i;
-
+    const u32 *ptr = (const u32 *)msg;
     for (i = 0; i < 16; i++) {
-        x[i] = ((u32)msg[i*4+0]) | (((u32)msg[i*4+1]) << 8) | 
-               (((u32)msg[i*4+2]) << 16) | (((u32)msg[i*4+3]) << 24);
+         x[i] = OAPV_LE32_TO_CPU(ptr[i]);
     }
     const u32 *blk = x;
+#else // Little Endian
+    const u32 *blk = (const u32 *)msg;
 #endif
 
     a = buf[0];

From 6f48c5dcbed9eee0cb5d30bd1f753954a00ed26c Mon Sep 17 00:00:00 2001
From: Anemptyship <hanbin1931@gmail.com>
Date: Sun, 18 Jan 2026 04:56:30 +0000
Subject: [PATCH 3/3] CI: Support s390x build

- Add cross-compilation job for s390x using QEMU

- Increase test timeouts in CMakeLists.txt for emulated environment

Signed-off-by: Anemptyship <hanbin1931@gmail.com>
---
 .github/workflows/build.yml | 46 +++++++++++++++++++++++++++++++++++++
 CMakeLists.txt              | 26 ++++++++++-----------
 2 files changed, 59 insertions(+), 13 deletions(-)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index fdeffc1..06396fa 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -5,6 +5,7 @@ on:
     branches: [ "main" ]
   pull_request:
     branches: [ "main" ]
+  workflow_dispatch:
 
 jobs:
   build-linux-amd64:
@@ -68,6 +69,25 @@ jobs:
           cmake -S ${{github.workspace}} -B ${{github.workspace}}/build-arm -DCMAKE_TOOLCHAIN_FILE=${{github.workspace}}/arm64_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
           cmake --build ${{github.workspace}}/build-arm
 
+  build-linux-s390x:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v6
+
+      - name: Set up CMake
+        uses: jwlawson/actions-setup-cmake@v2
+
+      - name: Install s390x toolchain
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y gcc-s390x-linux-gnu g++-s390x-linux-gnu binutils-s390x-linux-gnu libc6-s390x-cross
+
+      - name: Build (crosscompile) PC Linux s390x
+        run: |
+          cmake -S ${{github.workspace}} -B ${{github.workspace}}/build-s390x -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=s390x -DCMAKE_C_COMPILER=s390x-linux-gnu-gcc -DCMAKE_CXX_COMPILER=s390x-linux-gnu-g++ -DCMAKE_BUILD_TYPE=Release
+          cmake --build ${{github.workspace}}/build-s390x
+
   build-darwin-arm64:
     runs-on: macos-latest
     steps:
@@ -124,3 +144,29 @@ jobs:
         with:
           name: LastTest.log
           path: ${{github.workspace}}/build/Testing/Temporary/LastTest.log
+
+  test-linux-s390x:
+    runs-on: ubuntu-latest
+    env:
+      QEMU_LD_PREFIX: /usr/s390x-linux-gnu
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v6
+
+      - name: Set up CMake
+        uses: jwlawson/actions-setup-cmake@v2
+
+      - name: Install s390x toolchain and emulator
+        run: |
+          sudo apt-get update
+          sudo apt-get install -y gcc-s390x-linux-gnu g++-s390x-linux-gnu binutils-s390x-linux-gnu libc6-s390x-cross qemu-user qemu-user-static
+
+      - name: Build (crosscompile) PC Linux s390x for tests
+        run: |
+          cmake -S ${{github.workspace}} -B ${{github.workspace}}/build-s390x -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_SYSTEM_PROCESSOR=s390x -DCMAKE_C_COMPILER=s390x-linux-gnu-gcc -DCMAKE_CXX_COMPILER=s390x-linux-gnu-g++ -DCMAKE_BUILD_TYPE=Release -DCMAKE_CROSSCOMPILING_EMULATOR="qemu-s390x;-L;/usr/s390x-linux-gnu"
+          cmake --build ${{github.workspace}}/build-s390x
+
+      - name: Run tests for s390x
+        run: |
+          cd build-s390x
+          ctest --output-on-failure --timeout 15
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1c568e1..a6315ca 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -272,7 +272,7 @@ set_tests_properties(encode PROPERTIES
 # Test - decode
 add_test(NAME decode COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i out.oapv)
 set_tests_properties(decode PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     DEPENDS encode
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 125"
@@ -282,7 +282,7 @@ set_tests_properties(decode PROPERTIES
 # Test - decode qp_A.apv
 add_test(NAME decode_qp_A COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/qp_A.apv -v 3 --hash)
 set_tests_properties(decode_qp_A PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -291,7 +291,7 @@ set_tests_properties(decode_qp_A PROPERTIES
 # Test - decode qp_B.apv
 add_test(NAME decode_qp_B COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/qp_B.apv -v 3 --hash)
 set_tests_properties(decode_qp_B PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -300,7 +300,7 @@ set_tests_properties(decode_qp_B PROPERTIES
 # Test - decode qp_C.apv
 add_test(NAME decode_qp_C COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/qp_C.apv -v 3 --hash)
 set_tests_properties(decode_qp_C PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -309,7 +309,7 @@ set_tests_properties(decode_qp_C PROPERTIES
 # Test - decode qp_D.apv
 add_test(NAME decode_qp_D COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/qp_D.apv -v 3 --hash)
 set_tests_properties(decode_qp_D PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -318,7 +318,7 @@ set_tests_properties(decode_qp_D PROPERTIES
 # Test - decode qp_E.apv
 add_test(NAME decode_qp_E COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/qp_E.apv -v 3 --hash)
 set_tests_properties(decode_qp_E PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -327,7 +327,7 @@ set_tests_properties(decode_qp_E PROPERTIES
 # Test - decode syn_A.apv
 add_test(NAME decode_syn_A COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/syn_A.apv -v 3 --hash)
 set_tests_properties(decode_syn_A PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -336,7 +336,7 @@ set_tests_properties(decode_syn_A PROPERTIES
 # Test - decode syn_B.apv
 add_test(NAME decode_syn_B COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/syn_B.apv -v 3 --hash)
 set_tests_properties(decode_syn_B PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -345,7 +345,7 @@ set_tests_properties(decode_syn_B PROPERTIES
 # Test - decode tile_A.apv
 add_test(NAME decode_tile_A COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/tile_A.apv -v 3 --hash)
 set_tests_properties(decode_tile_A PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -354,7 +354,7 @@ set_tests_properties(decode_tile_A PROPERTIES
 # Test - decode tile_B.apv
 add_test(NAME decode_tile_B COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/tile_B.apv -v 3 --hash)
 set_tests_properties(decode_tile_B PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -363,7 +363,7 @@ set_tests_properties(decode_tile_B PROPERTIES
 # Test - decode tile_C.apv
 add_test(NAME decode_tile_C COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/tile_C.apv -v 3 --hash)
 set_tests_properties(decode_tile_C PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -372,7 +372,7 @@ set_tests_properties(decode_tile_C PROPERTIES
 # Test - decode tile_D.apv
 add_test(NAME decode_tile_D COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/tile_D.apv -v 3 --hash)
 set_tests_properties(decode_tile_D PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"
@@ -381,7 +381,7 @@ set_tests_properties(decode_tile_D PROPERTIES
 # Test - decode tile_E.apv
 add_test(NAME decode_tile_E COMMAND ${CMAKE_CURRENT_BINARY_DIR}/bin/oapv_app_dec -i ${CMAKE_CURRENT_SOURCE_DIR}/test/bitstream/tile_E.apv -v 3 --hash)
 set_tests_properties(decode_tile_E PROPERTIES
-    TIMEOUT 10
+    TIMEOUT 20
     FAIL_REGULAR_EXPRESSION "Decoded frame count               = 0"
     PASS_REGULAR_EXPRESSION "Decoded frame count               = 3"
     PASS_REGULAR_EXPRESSION ".*hash:match.*"