[Scummvm-git-logs] scummvm master -> 52cee62a6484656ca25cf961d9d06241188d381b
sev-
noreply at scummvm.org
Sat Jul 2 10:49:25 UTC 2022
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
0d37729ff7 COMMON: Fix reading and writing doubles from streams with older ARM toolchains
52cee62a64 COMMON: Fix reading and writing of doubles when native double is 32-bit
Commit: 0d37729ff7e7e59be7bfaa7df3297c5a702a86b3
https://github.com/scummvm/scummvm/commit/0d37729ff7e7e59be7bfaa7df3297c5a702a86b3
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-07-02T12:49:22+02:00
Commit Message:
COMMON: Fix reading and writing doubles from streams with older ARM toolchains
Changed paths:
common/endian.h
common/scummsys.h
common/serializer.h
common/stream.h
test/common/endian.h
diff --git a/common/endian.h b/common/endian.h
index 9208fd0ce09..f633785d368 100644
--- a/common/endian.h
+++ b/common/endian.h
@@ -583,6 +583,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));
}
diff --git a/common/scummsys.h b/common/scummsys.h
index 78dcf122e98..bfc3e0dc613 100644
--- a/common/scummsys.h
+++ b/common/scummsys.h
@@ -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)
diff --git a/common/serializer.h b/common/serializer.h
index a004148ed97..47cbdabcb15 100644
--- a/common/serializer.h
+++ b/common/serializer.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.
diff --git a/common/stream.h b/common/stream.h
index 874b7fd888e..225a78913c6 100644
--- a/common/stream.h
+++ b/common/stream.h
@@ -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);
}
};
diff --git a/test/common/endian.h b/test/common/endian.h
index 065b6997fc0..9716ebb2ecf 100644
--- a/test/common/endian.h
+++ b/test/common/endian.h
@@ -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);
+ }
+
};
Commit: 52cee62a6484656ca25cf961d9d06241188d381b
https://github.com/scummvm/scummvm/commit/52cee62a6484656ca25cf961d9d06241188d381b
Author: Marcus Comstedt (marcus at mc.pp.se)
Date: 2022-07-02T12:49:22+02:00
Commit Message:
COMMON: Fix reading and writing of doubles when native double is 32-bit
Changed paths:
common/endian.h
diff --git a/common/endian.h b/common/endian.h
index f633785d368..7612fdabe99 100644
--- a/common/endian.h
+++ b/common/endian.h
@@ -640,21 +640,82 @@ union SwapDouble {
};
#endif
-#ifndef __DC__
-STATIC_ASSERT(sizeof(double) == sizeof(uint64), Unexpected_size_of_double);
-#endif
+STATIC_ASSERT(sizeof(double) == sizeof(uint64) || sizeof(double) == sizeof(uint32), Unexpected_size_of_double);
+
+template<size_t n> inline double READ_DOUBLE(const SwapDouble& sw);
+template<size_t n> inline void WRITE_DOUBLE(SwapDouble &sw, double d);
+
+// 64-bit double
+template<> inline double READ_DOUBLE<sizeof(uint64)>(const SwapDouble& sd)
+{
+ return sd.d;
+}
+
+template<> inline void WRITE_DOUBLE<sizeof(uint64)>(SwapDouble &sd, double d)
+{
+ sd.d = d;
+}
+
+// 32-bit double
+template<> inline double READ_DOUBLE<sizeof(uint32)>(const SwapDouble& sd)
+{
+ SwapFloat sf;
+ uint32 e = (sd.u32.high >> 20) & 0x7ff;
+ if (e <= 896) {
+ // Too small for normalized, create a zero with the correct sign
+ // (FIXME: Create denormalized numbers instead when possible?)
+ sf.u32 = (sd.u32.high & 0x80000000U); // sign bit
+ return sf.f;
+ } else if(e >= 1151) {
+ // Overflow, infinity or NaN
+ if (e < 2047) {
+ // Overflow; make sure result is infinity and not NaN
+ sf.u32 = (sd.u32.high & 0x80000000U) | // sign bit
+ (255 << 23); // exponent
+ return sf.f;
+ }
+ e = 255;
+ } else
+ e -= 896;
+ sf.u32 = (sd.u32.high & 0x80000000U) | // sign bit
+ (e << 23) | // exponent
+ ((sd.u32.high & 0xfffff) << 3) | (sd.u32.low >> 29); // mantissa
+ return sf.f;
+}
+
+template<> inline void WRITE_DOUBLE<sizeof(uint32)>(SwapDouble &sd, double d)
+{
+ SwapFloat sf;
+ sf.f = d;
+ uint32 e = (sf.u32 >> 23) & 0xff;
+ if (!e) {
+ // Denormalized or zero, create a zero with the correct sign
+ // (FIXME: Convert denormalized 32-bit to normalized 64-bit?)
+ sd.u32.high = (sf.u32 & 0x80000000U); // sign bit
+ sd.u32.low = 0;
+ return;
+ } else if (e == 255) {
+ // Infinity or NaN
+ e = 2047;
+ } else
+ e += 896;
+ sd.u32.high = (sf.u32 & 0x80000000U) | // sign bit
+ (e << 20) | // exponent
+ ((sf.u32 >> 3) & 0xfffff); // mantissa
+ sd.u32.low = sf.u32 << 29;
+}
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;
+ return READ_DOUBLE<sizeof(double)>(swap);
}
inline void WRITE_LE_FLOAT64(void *ptr, double value) {
SwapDouble swap;
- swap.d = value;
+ WRITE_DOUBLE<sizeof(double)>(swap, value);
uint8 *b = (uint8 *)ptr;
WRITE_LE_UINT32(b, swap.u32.low);
WRITE_LE_UINT32(b + 4, swap.u32.high);
@@ -665,12 +726,12 @@ inline double READ_BE_FLOAT64(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
swap.u32.high = READ_BE_UINT32(b);
swap.u32.low = READ_BE_UINT32(b + 4);
- return swap.d;
+ return READ_DOUBLE<sizeof(double)>(swap);
}
inline void WRITE_BE_FLOAT64(void *ptr, double value) {
SwapDouble swap;
- swap.d = value;
+ WRITE_DOUBLE<sizeof(double)>(swap, value);
uint8 *b = (uint8 *)ptr;
WRITE_BE_UINT32(b, swap.u32.high);
WRITE_BE_UINT32(b + 4, swap.u32.low);
@@ -681,12 +742,12 @@ inline double READ_FPA_FLOAT64(const void *ptr) {
const uint8 *b = (const uint8 *)ptr;
swap.u32.high = READ_LE_UINT32(b);
swap.u32.low = READ_LE_UINT32(b + 4);
- return swap.d;
+ return READ_DOUBLE<sizeof(double)>(swap);
}
inline void WRITE_FPA_FLOAT64(void *ptr, double value) {
SwapDouble swap;
- swap.d = value;
+ WRITE_DOUBLE<sizeof(double)>(swap, value);
uint8 *b = (uint8 *)ptr;
WRITE_LE_UINT32(b, swap.u32.high);
WRITE_LE_UINT32(b + 4, swap.u32.low);
@@ -695,12 +756,12 @@ inline void WRITE_FPA_FLOAT64(void *ptr, double value) {
inline double READ_FLOAT64(const void *ptr) {
SwapDouble swap;
swap.u64 = READ_UINT64(ptr);
- return swap.d;
+ return READ_DOUBLE<sizeof(double)>(swap);
}
inline void WRITE_FLOAT64(void *ptr, double value) {
SwapDouble swap;
- swap.d = value;
+ WRITE_DOUBLE<sizeof(double)>(swap, value);
WRITE_UINT64(ptr, swap.u64);
}
More information about the Scummvm-git-logs
mailing list