diff --git a/Dependencies/Utility/Utility/CppMacros.h b/Dependencies/Utility/Utility/CppMacros.h index 9de4334c40f..57aaa75abc8 100644 --- a/Dependencies/Utility/Utility/CppMacros.h +++ b/Dependencies/Utility/Utility/CppMacros.h @@ -43,3 +43,7 @@ #else #define REGISTER register #endif + +#if __cplusplus < 201103L +#define static_assert(expr, msg) +#endif diff --git a/Dependencies/Utility/Utility/endian_compat.h b/Dependencies/Utility/Utility/endian_compat.h new file mode 100644 index 00000000000..56b35c33bef --- /dev/null +++ b/Dependencies/Utility/Utility/endian_compat.h @@ -0,0 +1,246 @@ +/* +** Command & Conquer Generals Zero Hour(tm) +** Copyright 2025 TheSuperHackers +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +*/ + +// This file contains macros to help with endian conversions between different endian systems. +#pragma once + +// VC6 does not support pragma once +#ifndef ENDIAN_COMPAT_H +#define ENDIAN_COMPAT_H + +#include +#include + + +#if defined(__linux__) || defined(__CYGWIN__) +#include + +#elif defined(__APPLE__) +#include + +#define htobe16(x) OSSwapHostToBigInt16(x) +#define htole16(x) OSSwapHostToLittleInt16(x) +#define be16toh(x) OSSwapBigToHostInt16(x) +#define le16toh(x) OSSwapLittleToHostInt16(x) + +#define htobe32(x) OSSwapHostToBigInt32(x) +#define htole32(x) OSSwapHostToLittleInt32(x) +#define be32toh(x) OSSwapBigToHostInt32(x) +#define le32toh(x) OSSwapLittleToHostInt32(x) + +#define htobe64(x) OSSwapHostToBigInt64(x) +#define htole64(x) OSSwapHostToLittleInt64(x) +#define be64toh(x) OSSwapBigToHostInt64(x) +#define le64toh(x) OSSwapLittleToHostInt64(x) + +#elif defined(__OpenBSD__) +#include + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) +#include + +#define be16toh(x) betoh16(x) +#define le16toh(x) letoh16(x) + +#define be32toh(x) betoh32(x) +#define le32toh(x) letoh32(x) + +#define be64toh(x) betoh64(x) +#define le64toh(x) letoh64(x) + +#elif defined(_WIN32) || defined(_WIN64) +#if !(defined(_MSC_VER) && _MSC_VER < 1300) +#include +#define htobe16(x) _byteswap_ushort(x) +#define htole16(x) (x) +#define be16toh(x) _byteswap_ushort(x) +#define le16toh(x) (x) + +#define htobe32(x) _byteswap_ulong(x) +#define htole32(x) (x) +#define be32toh(x) _byteswap_ulong(x) +#define le32toh(x) (x) + +#define htobe64(x) _byteswap_uint64(x) +#define htole64(x) (x) +#define be64toh(x) _byteswap_uint64(x) +#define le64toh(x) (x) +#else +#define bswap16(x) ( (uint16_t)( ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8) ) ) +#define bswap32(x) ( ((x & 0xFF000000) >> 24) | \ + ((x & 0x00FF0000) >> 8) | \ + ((x & 0x0000FF00) << 8) | \ + ((x & 0x000000FF) << 24) ) +#define bswap64(x) ( (((uint64_t)(x) & 0xFF00000000000000) >> 56) | \ + (((uint64_t)(x) & 0x00FF000000000000) >> 40) | \ + (((uint64_t)(x) & 0x0000FF0000000000) >> 24) | \ + (((uint64_t)(x) & 0x000000FF00000000) >> 8) | \ + (((uint64_t)(x) & 0x00000000FF000000) << 8) | \ + (((uint64_t)(x) & 0x0000000000FF0000) << 24) | \ + (((uint64_t)(x) & 0x000000000000FF00) << 40) | \ + (((uint64_t)(x) & 0x00000000000000FF) << 56) ) + +#define htobe16(x) bswap16(x) +#define htole16(x) (x) +#define be16toh(x) bswap16(x) +#define le16toh(x) (x) + +#define htobe32(x) bswap32(x) +#define htole32(x) (x) +#define be32toh(x) bswap32(x) +#define le32toh(x) (x) + +#define htobe64(x) bswap64(x) +#define htole64(x) (x) +#define be64toh(x) bswap64(x) +#define le64toh(x) (x) + +#endif // _MSC_VER + +#else +#error platform not supported +#endif + + +// Endian helper function data types +#if defined(__linux__) || defined(__CYGWIN__) +typedef uint16_t SwapType16; +typedef uint32_t SwapType32; +typedef uint64_t SwapType64; + +#elif defined(__APPLE__) +typedef UInt16 SwapType16; +typedef UInt32 SwapType32; +typedef UInt64 SwapType64; + +#elif defined(__OpenBSD__) +typedef uint16_t SwapType16; +typedef uint32_t SwapType32; +typedef uint64_t SwapType64; + +#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) +typedef uint16_t SwapType16; +typedef uint32_t SwapType32; +typedef uint64_t SwapType64; + +#elif defined(_WIN32) || defined(_WIN64) +typedef uint16_t SwapType16; +typedef uint32_t SwapType32; +typedef uint64_t SwapType64; + +#else +#error platform not supported +#endif + + +// Endian helper functions +static_assert(sizeof(SwapType16) == 2, "expected size does not match"); +static_assert(sizeof(SwapType32) == 4, "expected size does not match"); +static_assert(sizeof(SwapType64) == 8, "expected size does not match"); + +// VC6 compatible overloaded endian functions +#if defined(_MSC_VER) && _MSC_VER < 1300 + +// Big endian to host +inline int16_t betoh(int16_t value) { return be16toh(value); } +inline uint16_t betoh(uint16_t value) { return be16toh(value); } +inline int32_t betoh(int32_t value) { return be32toh(value); } +inline uint32_t betoh(uint32_t value) { return be32toh(value); } +inline int64_t betoh(int64_t value) { return be64toh(value); } +inline uint64_t betoh(uint64_t value) { return be64toh(value); } +// Host to big endian +inline int16_t htobe(int16_t value) { return htobe16(value); } +inline uint16_t htobe(uint16_t value) { return htobe16(value); } +inline int32_t htobe(int32_t value) { return htobe32(value); } +inline uint32_t htobe(uint32_t value) { return htobe32(value); } +inline int64_t htobe(int64_t value) { return htobe64(value); } +inline uint64_t htobe(uint64_t value) { return htobe64(value); } +// Little endian to host +inline int16_t letoh(int16_t value) { return le16toh(value); } +inline uint16_t letoh(uint16_t value) { return le16toh(value); } +inline int32_t letoh(int32_t value) { return le32toh(value); } +inline uint32_t letoh(uint32_t value) { return le32toh(value); } +inline int64_t letoh(int64_t value) { return le64toh(value); } +inline uint64_t letoh(uint64_t value) { return le64toh(value); } +// Host to little endian +inline int16_t htole(int16_t value) { return htole16(value); } +inline uint16_t htole(uint16_t value) { return htole16(value); } +inline int32_t htole(int32_t value) { return htole32(value); } +inline uint32_t htole(uint32_t value) { return htole32(value); } +inline int64_t htole(int64_t value) { return htole64(value); } +inline uint64_t htole(uint64_t value) { return htole64(value); } + +#else + +namespace Endian +{ +template struct htobeHelper; +template struct htoleHelper; +template struct betohHelper; +template struct letohHelper; + +// 2 byte integer, enum +template struct htobeHelper { static inline Type swap(Type value) { return static_cast(htobe16(static_cast(value))); } }; +template struct htoleHelper { static inline Type swap(Type value) { return static_cast(htole16(static_cast(value))); } }; +template struct betohHelper { static inline Type swap(Type value) { return static_cast(be16toh(static_cast(value))); } }; +template struct letohHelper { static inline Type swap(Type value) { return static_cast(le16toh(static_cast(value))); } }; +// 4 byte integer, enum +template struct htobeHelper { static inline Type swap(Type value) { return static_cast(htobe32(static_cast(value))); } }; +template struct htoleHelper { static inline Type swap(Type value) { return static_cast(htole32(static_cast(value))); } }; +template struct betohHelper { static inline Type swap(Type value) { return static_cast(be32toh(static_cast(value))); } }; +template struct letohHelper { static inline Type swap(Type value) { return static_cast(le16toh(static_cast(value))); } }; +// 8 byte integer, enum +template struct htobeHelper { static inline Type swap(Type value) { return static_cast(htobe64(static_cast(value))); } }; +template struct htoleHelper { static inline Type swap(Type value) { return static_cast(htole64(static_cast(value))); } }; +template struct betohHelper { static inline Type swap(Type value) { return static_cast(be64toh(static_cast(value))); } }; +template struct letohHelper { static inline Type swap(Type value) { return static_cast(le16toh(static_cast(value))); } }; +// float +template <> struct htobeHelper { static inline float swap(float value) { SwapType32 v = htobe32(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +template <> struct htoleHelper { static inline float swap(float value) { SwapType32 v = htole32(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +template <> struct betohHelper { static inline float swap(float value) { SwapType32 v = be32toh(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +template <> struct letohHelper { static inline float swap(float value) { SwapType32 v = le16toh(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +// double +template <> struct htobeHelper { static inline double swap(double value) { SwapType64 v = htobe64(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +template <> struct htoleHelper { static inline double swap(double value) { SwapType64 v = htole64(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +template <> struct betohHelper { static inline double swap(double value) { SwapType64 v = be64toh(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +template <> struct letohHelper { static inline double swap(double value) { SwapType64 v = le16toh(*reinterpret_cast(&value)); return *reinterpret_cast(&v); } }; +} // namespace Endian + +// c++ template functions, takes any 2, 4, 8 bytes, including float, double, enum + +// Host to big endian +template inline Type htobe(Type value) { return Endian::htobeHelper::swap(value); } +// Host to little endian +template inline Type htole(Type value) { return Endian::htoleHelper::swap(value); } +// Big endian to host +template inline Type betoh(Type value) { return Endian::betohHelper::swap(value); } +// Little endian to host +template inline Type letoh(Type value) { return Endian::letohHelper::swap(value); } + +// Host to big endian +template inline void htobe_ref(Type &value) { value = Endian::htobeHelper::swap(value); } +// Host to little endian +template inline void htole_ref(Type &value) { value = Endian::htoleHelper::swap(value); } +// Big endian to host +template inline void betoh_ref(Type &value) { value = Endian::betohHelper::swap(value); } +// Little endian to host +template inline void letoh_ref(Type &value) { value = Endian::letohHelper::swap(value); } + +#endif // _MSC_VER < 1300 + +#endif // ENDIAN_COMPAT_H \ No newline at end of file diff --git a/Generals/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp b/Generals/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp index 8da71ff2c44..11ebc499a34 100644 --- a/Generals/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp +++ b/Generals/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp @@ -26,7 +26,6 @@ // Bryan Cleveland, August 2002 ///////////////////////////////////////////////////////////// -#include #include "Common/AudioAffect.h" #include "Common/ArchiveFile.h" #include "Common/ArchiveFileSystem.h" @@ -36,6 +35,7 @@ #include "Common/LocalFileSystem.h" #include "Win32Device/Common/Win32BIGFile.h" #include "Win32Device/Common/Win32BIGFileSystem.h" +#include "Utility/endian_compat.h" #ifdef RTS_INTERNAL // for occasional debugging... @@ -107,7 +107,7 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) { // read in the number of files contained in this BIG file. // change the order of the bytes cause the file size is in reverse byte order for some reason. fp->read(&numLittleFiles, 4); - numLittleFiles = ntohl(numLittleFiles); + numLittleFiles = betoh(numLittleFiles); DEBUG_LOG(("Win32BIGFileSystem::openArchiveFile - %d are contained in archive\n", numLittleFiles)); // for (Int i = 0; i < 2; ++i) { @@ -127,8 +127,8 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) { fp->read(&fileOffset, 4); fp->read(&filesize, 4); - filesize = ntohl(filesize); - fileOffset = ntohl(fileOffset); + filesize = betoh(filesize); + fileOffset = betoh(fileOffset); fileInfo->m_archiveFilename = archiveFileName; fileInfo->m_offset = fileOffset; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp b/GeneralsMD/Code/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp index 318478f20e8..76a6ffb0dfe 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp @@ -36,6 +36,7 @@ #include "StdDevice/Common/StdBIGFile.h" #include "StdDevice/Common/StdBIGFileSystem.h" #include "Common/Registry.h" +#include "Utility/endian_compat.h" static const char *BIGFileIdentifier = "BIGF"; @@ -113,7 +114,7 @@ ArchiveFile * StdBIGFileSystem::openArchiveFile(const Char *filename) { // read in the number of files contained in this BIG file. // change the order of the bytes cause the file size is in reverse byte order for some reason. fp->read(&numLittleFiles, 4); - numLittleFiles = ntohl(numLittleFiles); + numLittleFiles = betoh(numLittleFiles); DEBUG_LOG(("StdBIGFileSystem::openArchiveFile - %d are contained in archive\n", numLittleFiles)); // for (Int i = 0; i < 2; ++i) { @@ -133,8 +134,8 @@ ArchiveFile * StdBIGFileSystem::openArchiveFile(const Char *filename) { fp->read(&fileOffset, 4); fp->read(&filesize, 4); - filesize = ntohl(filesize); - fileOffset = ntohl(fileOffset); + filesize = betoh(filesize); + fileOffset = betoh(fileOffset); fileInfo->m_archiveFilename = archiveFileName; fileInfo->m_offset = fileOffset; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp b/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp index c0281151149..e9c0bc91e2b 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp @@ -26,7 +26,6 @@ // Bryan Cleveland, August 2002 ///////////////////////////////////////////////////////////// -#include #include "Common/AudioAffect.h" #include "Common/ArchiveFile.h" #include "Common/ArchiveFileSystem.h" @@ -37,6 +36,7 @@ #include "Win32Device/Common/Win32BIGFile.h" #include "Win32Device/Common/Win32BIGFileSystem.h" #include "Common/Registry.h" +#include "Utility/endian_compat.h" #ifdef RTS_INTERNAL // for occasional debugging... @@ -120,7 +120,7 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) { // read in the number of files contained in this BIG file. // change the order of the bytes cause the file size is in reverse byte order for some reason. fp->read(&numLittleFiles, 4); - numLittleFiles = ntohl(numLittleFiles); + numLittleFiles = betoh(numLittleFiles); DEBUG_LOG(("Win32BIGFileSystem::openArchiveFile - %d are contained in archive\n", numLittleFiles)); // for (Int i = 0; i < 2; ++i) { @@ -140,8 +140,8 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) { fp->read(&fileOffset, 4); fp->read(&filesize, 4); - filesize = ntohl(filesize); - fileOffset = ntohl(fileOffset); + filesize = betoh(filesize); + fileOffset = betoh(fileOffset); fileInfo->m_archiveFilename = archiveFileName; fileInfo->m_offset = fileOffset;