Cleanup endian code

This commit is contained in:
U-DESKTOP-SPFP6AQ\twistedtechre
2026-05-06 05:07:52 +02:00
parent a3467f6af9
commit 3a84a6fd0b
3 changed files with 111 additions and 119 deletions

View File

@@ -23,113 +23,12 @@
#include <string.h>
#include <streams/memory_stream.h>
#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

View File

@@ -2,20 +2,7 @@
#define _FCEU_ENDIAN_H
#include "fceu-memory.h"
#include <streams/memory_stream.h>
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

View File

@@ -28,6 +28,7 @@
#endif
#include <compat/strl.h>
#include <streams/memory_stream.h>
#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];