Cleanup endian code
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
112
src/state.c
112
src/state.c
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user