COMMON: Fix reading and writing doubles from streams with older ARM toolchains

This commit is contained in:
Cameron Cawley 2022-06-18 00:24:36 +01:00 committed by Eugene Sandulenko
parent 51cc85be11
commit ae84b42c28
No known key found for this signature in database
GPG key ID: 014D387312D34F08
5 changed files with 230 additions and 38 deletions

View file

@ -623,6 +623,127 @@ inline void WRITE_BE_UINT24(void *ptr, uint32 value) {
#define WRITE_UINT24(a,b) WRITE_BE_UINT24(a,b)
#endif
union SwapFloat {
float f;
uint32 u32;
};
STATIC_ASSERT(sizeof(float) == sizeof(uint32), Unexpected_size_of_float);
inline float READ_LE_FLOAT32(const void *ptr) {
SwapFloat swap;
swap.u32 = READ_LE_UINT32(ptr);
return swap.f;
}
inline void WRITE_LE_FLOAT32(void *ptr, float value) {
SwapFloat swap;
swap.f = value;
WRITE_LE_UINT32(ptr, swap.u32);
}
inline float READ_BE_FLOAT32(const void *ptr) {
SwapFloat swap;
swap.u32 = READ_BE_UINT32(ptr);
return swap.f;
}
inline void WRITE_BE_FLOAT32(void *ptr, float value) {
SwapFloat swap;
swap.f = value;
WRITE_BE_UINT32(ptr, swap.u32);
}
#ifdef SCUMM_LITTLE_ENDIAN
#define READ_FLOAT32(a) READ_LE_FLOAT32(a)
#define WRITE_FLOAT32(a,b) WRITE_LE_FLOAT32(a,b)
#else
#define READ_FLOAT32(a) READ_BE_FLOAT32(a)
#define WRITE_FLOAT32(a,b) WRITE_BE_FLOAT32(a,b)
#endif
#ifdef SCUMM_FLOAT_WORD_LITTLE_ENDIAN
union SwapDouble {
double d;
uint64 u64;
struct {
uint32 low, high;
} u32;
};
#else
union SwapDouble {
double d;
uint64 u64;
struct {
uint32 high, low;
} u32;
};
#endif
#ifndef __DC__
STATIC_ASSERT(sizeof(double) == sizeof(uint64), Unexpected_size_of_double);
#endif
inline double READ_LE_FLOAT64(const void *ptr) {
SwapDouble swap;
const uint8 *b = (const uint8 *)ptr;
swap.u32.low = READ_LE_UINT32(b);
swap.u32.high = READ_LE_UINT32(b + 4);
return swap.d;
}
inline void WRITE_LE_FLOAT64(void *ptr, double value) {
SwapDouble swap;
swap.d = value;
uint8 *b = (uint8 *)ptr;
WRITE_LE_UINT32(b, swap.u32.low);
WRITE_LE_UINT32(b + 4, swap.u32.high);
}
inline double READ_BE_FLOAT64(const void *ptr) {
SwapDouble swap;
const uint8 *b = (const uint8 *)ptr;
swap.u32.high = READ_BE_UINT32(b);
swap.u32.low = READ_BE_UINT32(b + 4);
return swap.d;
}
inline void WRITE_BE_FLOAT64(void *ptr, double value) {
SwapDouble swap;
swap.d = value;
uint8 *b = (uint8 *)ptr;
WRITE_BE_UINT32(b, swap.u32.high);
WRITE_BE_UINT32(b + 4, swap.u32.low);
}
inline double READ_FPA_FLOAT64(const void *ptr) {
SwapDouble swap;
const uint8 *b = (const uint8 *)ptr;
swap.u32.high = READ_LE_UINT32(b);
swap.u32.low = READ_LE_UINT32(b + 4);
return swap.d;
}
inline void WRITE_FPA_FLOAT64(void *ptr, double value) {
SwapDouble swap;
swap.d = value;
uint8 *b = (uint8 *)ptr;
WRITE_LE_UINT32(b, swap.u32.high);
WRITE_LE_UINT32(b + 4, swap.u32.low);
}
inline double READ_FLOAT64(const void *ptr) {
SwapDouble swap;
swap.u64 = READ_UINT64(ptr);
return swap.d;
}
inline void WRITE_FLOAT64(void *ptr, double value) {
SwapDouble swap;
swap.d = value;
WRITE_UINT64(ptr, swap.u64);
}
inline int16 READ_LE_INT16(const void *ptr) {
return static_cast<int16>(READ_LE_UINT16(ptr));
}

View file

@ -300,6 +300,28 @@
#endif
#endif
#if !defined(SCUMM_FLOAT_WORD_LITTLE_ENDIAN) && !defined(SCUMM_FLOAT_WORD_BIG_ENDIAN)
#if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
#if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define SCUMM_FLOAT_WORD_LITTLE_ENDIAN
#elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
#define SCUMM_FLOAT_WORD_BIG_ENDIAN
#else
#error Unsupported endianness
#endif
#else
#ifdef SCUMM_LITTLE_ENDIAN
#define SCUMM_FLOAT_WORD_LITTLE_ENDIAN
#else
#define SCUMM_FLOAT_WORD_BIG_ENDIAN
#endif
#endif
#endif
//
// Some more system specific settings.
// TODO/FIXME: All of these should be moved to backend specific files (such as portdefs.h)

View file

@ -128,8 +128,9 @@ public:
SYNC_AS(Sint32BE, int32, 4)
SYNC_AS(FloatLE, float, 4)
SYNC_AS(FloatBE, float, 4)
SYNC_AS(DoubleLE, double, 4)
SYNC_AS(DoubleBE, double, 4)
SYNC_AS(DoubleLE, double, 8)
SYNC_AS(DoubleBE, double, 8)
/**
* Returns true if an I/O failure occurred.

View file

@ -565,12 +565,9 @@ public:
* calling err() and eos() ).
*/
FORCEINLINE float readFloatLE() {
uint32 n = readUint32LE();
float f;
memcpy(&f, &n, 4);
return f;
uint8 val[4];
read(val, 4);
return READ_LE_FLOAT32(val);
}
/**
@ -582,12 +579,9 @@ public:
* calling err() and eos() ).
*/
FORCEINLINE float readFloatBE() {
uint32 n = readUint32BE();
float f;
memcpy(&f, &n, 4);
return f;
uint8 val[4];
read(val, 4);
return READ_BE_FLOAT32(val);
}
@ -600,12 +594,9 @@ public:
* calling err() and eos() ).
*/
FORCEINLINE double readDoubleLE() {
uint64 n = readUint64LE();
double d;
memcpy(&d, &n, 8);
return d;
uint8 val[8];
read(val, 8);
return READ_LE_FLOAT64(val);
}
/**
@ -617,12 +608,9 @@ public:
* calling err() and eos() ).
*/
FORCEINLINE double readDoubleBE() {
uint64 n = readUint64BE();
double d;
memcpy(&d, &n, 8);
return d;
uint8 val[8];
read(val, 8);
return READ_BE_FLOAT64(val);
}
/**
@ -840,12 +828,9 @@ public:
* and return it in native endianness.
*/
FORCEINLINE float readFloat() {
uint32 n = readUint32();
float f;
memcpy(&f, &n, 4);
return f;
uint8 val[4];
read(val, 4);
return (_bigEndian) ? READ_BE_FLOAT32(val) : READ_LE_FLOAT32(val);
}
/**
@ -853,12 +838,9 @@ public:
* and return it in native endianness.
*/
FORCEINLINE double readDouble() {
uint64 n = readUint64();
double d;
memcpy(&d, &n, 8);
return d;
uint8 val[8];
read(val, 8);
return (_bigEndian) ? READ_BE_FLOAT64(val) : READ_LE_FLOAT64(val);
}
};

View file

@ -45,4 +45,70 @@ class EndianTestSuite : public CxxTest::TestSuite
uint32 value = READ_LE_UINT16(data);
TS_ASSERT_EQUALS(value, 0x3412UL);
}
void test_READ_BE_FLOAT32() {
const uint8 data[4] = { 0x40, 0x49, 0x0f, 0xdc };
float value = READ_BE_FLOAT32(data);
TS_ASSERT_EQUALS(value, 3.141593f);
}
void test_READ_LE_FLOAT32() {
const uint8 data[4] = { 0xdc, 0x0f, 0x49, 0x40 };
float value = READ_LE_FLOAT32(data);
TS_ASSERT_EQUALS(value, 3.141593f);
}
void test_READ_BE_FLOAT64() {
const uint8 data[8] = { 0x40, 0x09, 0x21, 0xfb, 0x82, 0xc2, 0xbd, 0x7f };
double value = READ_BE_FLOAT64(data);
TS_ASSERT_EQUALS(value, 3.141593);
}
void test_READ_LE_FLOAT64() {
const uint8 data[8] = { 0x7f, 0xbd, 0xc2, 0x82, 0xfb, 0x21, 0x09, 0x40 };
double value = READ_LE_FLOAT64(data);
TS_ASSERT_EQUALS(value, 3.141593);
}
void test_READ_FPA_FLOAT64() {
const uint8 data[8] = { 0xfb, 0x21, 0x09, 0x40, 0x7f, 0xbd, 0xc2, 0x82 };
double value = READ_FPA_FLOAT64(data);
TS_ASSERT_EQUALS(value, 3.141593);
}
void test_WRITE_BE_FLOAT32() {
const uint8 data[4] = { 0x40, 0x49, 0x0f, 0xdc };
uint8 out[4];
WRITE_BE_FLOAT32(out, 3.141593f);
TS_ASSERT_EQUALS(memcmp(data, out, 4), 0);
}
void test_WRITE_LE_FLOAT32() {
const uint8 data[4] = { 0xdc, 0x0f, 0x49, 0x40 };
uint8 out[4];
WRITE_LE_FLOAT32(out, 3.141593f);
TS_ASSERT_EQUALS(memcmp(data, out, 4), 0);
}
void test_WRITE_BE_FLOAT64() {
const uint8 data[8] = { 0x40, 0x09, 0x21, 0xfb, 0x82, 0xc2, 0xbd, 0x7f };
uint8 out[8];
WRITE_BE_FLOAT64(out, 3.141593);
TS_ASSERT_EQUALS(memcmp(data, out, 8), 0);
}
void test_WRITE_LE_FLOAT64() {
const uint8 data[8] = { 0x7f, 0xbd, 0xc2, 0x82, 0xfb, 0x21, 0x09, 0x40 };
uint8 out[8];
WRITE_LE_FLOAT64(out, 3.141593);
TS_ASSERT_EQUALS(memcmp(data, out, 8), 0);
}
void test_WRITE_FPA_FLOAT64() {
const uint8 data[8] = { 0xfb, 0x21, 0x09, 0x40, 0x7f, 0xbd, 0xc2, 0x82 };
uint8 out[8];
WRITE_FPA_FLOAT64(out, 3.141593);
TS_ASSERT_EQUALS(memcmp(data, out, 8), 0);
}
};