Cleanup endian code
This commit is contained in:
@@ -23,113 +23,12 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <streams/memory_stream.h>
|
||||||
|
|
||||||
#include "fceu-memory.h"
|
#include "fceu-memory.h"
|
||||||
#include "fceu-types.h"
|
#include "fceu-types.h"
|
||||||
#include "fceu-endian.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)
|
uint32_t FCEU_de32lsb(const uint8_t *morp)
|
||||||
{
|
{
|
||||||
#ifndef MSB_FIRST
|
#ifndef MSB_FIRST
|
||||||
|
|||||||
@@ -2,20 +2,7 @@
|
|||||||
#define _FCEU_ENDIAN_H
|
#define _FCEU_ENDIAN_H
|
||||||
|
|
||||||
#include "fceu-memory.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 *);
|
uint32_t FCEU_de32lsb(const uint8_t *);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
110
src/state.c
110
src/state.c
@@ -28,6 +28,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
|
#include <streams/memory_stream.h>
|
||||||
|
|
||||||
#include "fceu-types.h"
|
#include "fceu-types.h"
|
||||||
#include "x6502.h"
|
#include "x6502.h"
|
||||||
@@ -71,6 +72,111 @@ static INLINE uint32_t sf_stride(uint32_t s)
|
|||||||
return s & SIZE_MASK;
|
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
|
/* 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
|
* when MSB_FIRST is defined - on LE hosts the on-disk LE format
|
||||||
* matches the in-memory layout and no swap is needed. */
|
* 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
|
else
|
||||||
FlipByteOrderStrided((uint8_t *)v, size, stride);
|
FlipByteOrderStrided((uint8_t *)v, size, stride);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
extern SFORMAT FCEUPPU_STATEINFO[];
|
extern SFORMAT FCEUPPU_STATEINFO[];
|
||||||
extern SFORMAT FCEUSND_STATEINFO[];
|
extern SFORMAT FCEUSND_STATEINFO[];
|
||||||
@@ -193,8 +300,7 @@ static SFORMAT *CheckS(SFORMAT *sf, uint32_t tsize, char *desc)
|
|||||||
static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size)
|
static int ReadStateChunk(memstream_t *mem, SFORMAT *sf, int size)
|
||||||
{
|
{
|
||||||
SFORMAT *tmp;
|
SFORMAT *tmp;
|
||||||
uint64_t temp;
|
uint64_t temp = memstream_pos(mem);
|
||||||
temp = memstream_pos(mem);
|
|
||||||
|
|
||||||
while (memstream_pos(mem) < (temp + size))
|
while (memstream_pos(mem) < (temp + size))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user