COMMON: Fix reading and writing doubles from streams with older ARM toolchains
This commit is contained in:
parent
51cc85be11
commit
ae84b42c28
5 changed files with 230 additions and 38 deletions
121
common/endian.h
121
common/endian.h
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue