[Scummvm-git-logs] scummvm branch-2-6 -> 004758862ebfd17f68108c5d39116cbbc64230e6

sev- noreply at scummvm.org
Sat Jul 2 10:50:45 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:
ae84b42c28 COMMON: Fix reading and writing doubles from streams with older ARM toolchains
004758862e COMMON: Fix reading and writing of doubles when native double is 32-bit


Commit: ae84b42c282e857dbc6d249fe9e26a44f45d5734
    https://github.com/scummvm/scummvm/commit/ae84b42c282e857dbc6d249fe9e26a44f45d5734
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2022-07-02T12:50:32+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 0ad9b467ac3..dd8ab24f389 100644
--- a/common/endian.h
+++ b/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));
 }
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: 004758862ebfd17f68108c5d39116cbbc64230e6
    https://github.com/scummvm/scummvm/commit/004758862ebfd17f68108c5d39116cbbc64230e6
Author: Marcus Comstedt (marcus at mc.pp.se)
Date: 2022-07-02T12:50:35+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 dd8ab24f389..ee723c9b585 100644
--- a/common/endian.h
+++ b/common/endian.h
@@ -680,21 +680,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);
@@ -705,12 +766,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);
@@ -721,12 +782,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);
@@ -735,12 +796,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