From 3a84a6fd0ba20dd4877c06b1d58741172148395f Mon Sep 17 00:00:00 2001 From: "U-DESKTOP-SPFP6AQ\\twistedtechre" Date: Wed, 6 May 2026 05:07:52 +0200 Subject: [PATCH] Cleanup endian code --- src/fceu-endian.c | 105 +------------------------------------------ src/fceu-endian.h | 13 ------ src/state.c | 112 ++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 111 insertions(+), 119 deletions(-) diff --git a/src/fceu-endian.c b/src/fceu-endian.c index b3cc137..bb34d88 100644 --- a/src/fceu-endian.c +++ b/src/fceu-endian.c @@ -23,113 +23,12 @@ #include +#include + #include "fceu-memory.h" #include "fceu-types.h" #include "fceu-endian.h" -void FlipByteOrder(uint8_t *src, uint32_t count) -{ - uint8_t *start = src; - uint8_t *end; - - if ((count & 1) || !count) - return; /* This shouldn't happen. */ - - end = src + count - 1; - /* Iterate while start < end, not 'count' times: the original loop - * over-iterated and effectively performed a no-op on every even count. - * That broke savestate portability across LE<->BE for every - * FCEUSTATE_RLSB-marked field. */ - while (start < end) - { - uint8_t tmp; - - tmp = *end; - *end = *start; - *start = tmp; - end--; - start++; - } -} - -void FlipByteOrderStrided(uint8_t *src, uint32_t count, uint32_t stride) -{ - uint32_t off; - - if (stride <= 1 || !count) - return; - if (count % stride) - return; /* malformed - bail rather than half-swap */ - - /* For arrays of multi-byte primitives we byte-swap each element - * independently. The previous code (FlipByteOrder) reversed the - * entire buffer end-to-end, which is correct for a single - * primitive but wrong for an array - it would swap element 0 - * with element N-1 and reverse their bytes too, scrambling the - * data. With per-element strides, [a0 a1 b0 b1] becomes - * [a1 a0 b1 b0] (correct), not [b1 b0 a1 a0] (legacy bug). */ - for (off = 0; off < count; off += stride) - { - uint8_t *s = src + off; - uint8_t *e = s + stride - 1; - while (s < e) - { - uint8_t tmp = *e; - *e = *s; - *s = tmp; - e--; - s++; - } - } -} - -int write32le_mem(uint32_t b, memstream_t *mem) -{ - uint8_t s[4]; -#ifndef MSB_FIRST - /* On LE hosts the in-memory representation already matches the - * on-disk LE format. Copy the four bytes directly, letting the - * compiler emit a single 32-bit store. */ - memcpy(s, &b, 4); -#else - s[0]=b; - s[1]=b>>8; - s[2]=b>>16; - s[3]=b>>24; -#endif - return((memstream_write(mem, s, 4)<4)?0:4); -} - -int read32le_mem(uint32_t *Bufo, memstream_t *mem) -{ - uint32_t buf; - if(memstream_read(mem, &buf, 4)<4) - return 0; -#ifdef MSB_FIRST - *Bufo = ((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); -#else - /* LE: bytes already in place. Use memcpy rather than the previous - * '*(uint32_t*)Bufo = buf;' which aliased through a uint32_t* into - * what's nominally a uint32_t already - functionally equivalent - * but cleaner. */ - *Bufo = buf; -#endif - return 1; -} - -void FCEU_en32lsb(uint8_t *buf, uint32_t morp) -{ -#ifndef MSB_FIRST - /* LE in-memory layout matches the desired LE on-disk layout. */ - memcpy(buf, &morp, 4); -#else - buf[0] = morp; - buf[1] = morp >> 8; - buf[2] = morp >> 16; - buf[3] = morp >> 24; -#endif -} - uint32_t FCEU_de32lsb(const uint8_t *morp) { #ifndef MSB_FIRST diff --git a/src/fceu-endian.h b/src/fceu-endian.h index f846596..72249eb 100644 --- a/src/fceu-endian.h +++ b/src/fceu-endian.h @@ -2,20 +2,7 @@ #define _FCEU_ENDIAN_H #include "fceu-memory.h" -#include -int write32le_mem(uint32_t b, memstream_t *mem); -int read32le_mem(uint32_t *Bufo, memstream_t *mem); - -void FlipByteOrder(uint8_t *src, uint32_t count); - -/* Byte-swap each `stride`-byte element in `src` in place. Used for - * savestate fields that contain arrays of multi-byte primitives, - * where we want each element swapped independently (not the whole - * buffer reversed end-to-end as FlipByteOrder does). */ -void FlipByteOrderStrided(uint8_t *src, uint32_t count, uint32_t stride); - -void FCEU_en32lsb(uint8_t *, uint32_t); uint32_t FCEU_de32lsb(const uint8_t *); #endif diff --git a/src/state.c b/src/state.c index 1255e09..6007e53 100644 --- a/src/state.c +++ b/src/state.c @@ -28,6 +28,7 @@ #endif #include +#include #include "fceu-types.h" #include "x6502.h" @@ -71,6 +72,111 @@ static INLINE uint32_t sf_stride(uint32_t s) return s & SIZE_MASK; } +static void FCEU_en32lsb(uint8_t *buf, uint32_t morp) +{ +#ifndef MSB_FIRST + /* LE in-memory layout matches the desired LE on-disk layout. */ + memcpy(buf, &morp, 4); +#else + buf[0] = morp; + buf[1] = morp >> 8; + buf[2] = morp >> 16; + buf[3] = morp >> 24; +#endif +} + +static int write32le_mem(uint32_t b, memstream_t *mem) +{ + uint8_t s[4]; +#ifndef MSB_FIRST + /* On LE hosts the in-memory representation already matches the + * on-disk LE format. Copy the four bytes directly, letting the + * compiler emit a single 32-bit store. */ + memcpy(s, &b, 4); +#else + s[0]=b; + s[1]=b>>8; + s[2]=b>>16; + s[3]=b>>24; +#endif + return((memstream_write(mem, s, 4)<4)?0:4); +} + + +static int read32le_mem(uint32_t *Bufo, memstream_t *mem) +{ + uint32_t buf; + if(memstream_read(mem, &buf, 4)<4) + return 0; +#ifdef MSB_FIRST + *Bufo = ((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24); +#else + /* LE: bytes already in place. Use memcpy rather than the previous + * '*(uint32_t*)Bufo = buf;' which aliased through a uint32_t* into + * what's nominally a uint32_t already - functionally equivalent + * but cleaner. */ + *Bufo = buf; +#endif + return 1; +} + +#ifdef MSB_FIRST +static void FlipByteOrder(uint8_t *src, uint32_t count) +{ + uint8_t *start = src; + uint8_t *end; + + if ((count & 1) || !count) + return; /* This shouldn't happen. */ + + end = src + count - 1; + /* Iterate while start < end, not 'count' times: the original loop + * over-iterated and effectively performed a no-op on every even count. + * That broke savestate portability across LE<->BE for every + * FCEUSTATE_RLSB-marked field. */ + while (start < end) + { + uint8_t tmp; + + tmp = *end; + *end = *start; + *start = tmp; + end--; + start++; + } +} + +static void FlipByteOrderStrided(uint8_t *src, uint32_t count, uint32_t stride) +{ + uint32_t off; + + if (stride <= 1 || !count) + return; + if (count % stride) + return; /* malformed - bail rather than half-swap */ + + /* For arrays of multi-byte primitives we byte-swap each element + * independently. The previous code (FlipByteOrder) reversed the + * entire buffer end-to-end, which is correct for a single + * primitive but wrong for an array - it would swap element 0 + * with element N-1 and reverse their bytes too, scrambling the + * data. With per-element strides, [a0 a1 b0 b1] becomes + * [a1 a0 b1 b0] (correct), not [b1 b0 a1 a0] (legacy bug). */ + for (off = 0; off < count; off += stride) + { + uint8_t *s = src + off; + uint8_t *e = s + stride - 1; + while (s < e) + { + uint8_t tmp = *e; + *e = *s; + *s = tmp; + e--; + s++; + } + } +} + /* Byte-swap an SFORMAT entry's value buffer in place. Only called * when MSB_FIRST is defined - on LE hosts the on-disk LE format * matches the in-memory layout and no swap is needed. */ @@ -83,6 +189,7 @@ static INLINE void sf_flip(void *v, uint32_t s) else FlipByteOrderStrided((uint8_t *)v, size, stride); } +#endif extern SFORMAT FCEUPPU_STATEINFO[]; extern SFORMAT FCEUSND_STATEINFO[]; @@ -193,10 +300,9 @@ static SFORMAT *CheckS(SFORMAT *sf, uint32_t tsize, char *desc) static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size) { SFORMAT *tmp; - uint64_t temp; - temp = memstream_pos(mem); + uint64_t temp = memstream_pos(mem); - while(memstream_pos(mem) < (temp + size)) + while (memstream_pos(mem) < (temp + size)) { uint32_t tsize; char toa[4];