Skip to content

Commit de0f8f7

Browse files
committed
[GEN][ZH] Add endian compat for BIGFileSystems (#798)
1 parent 2713267 commit de0f8f7

File tree

5 files changed

+192
-11
lines changed

5 files changed

+192
-11
lines changed

Dependencies/Utility/Utility/CppMacros.h

+4
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,7 @@
4343
#else
4444
#define REGISTER register
4545
#endif
46+
47+
#if __cplusplus < 201103L
48+
#define static_assert(...)
49+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
** Command & Conquer Generals Zero Hour(tm)
3+
** Copyright 2025 TheSuperHackers
4+
**
5+
** This program is free software: you can redistribute it and/or modify
6+
** it under the terms of the GNU General Public License as published by
7+
** the Free Software Foundation, either version 3 of the License, or
8+
** (at your option) any later version.
9+
**
10+
** This program is distributed in the hope that it will be useful,
11+
** but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
** GNU General Public License for more details.
14+
**
15+
** You should have received a copy of the GNU General Public License
16+
** along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
19+
// This file contains macros to help with endian conversions between different endian systems.
20+
#pragma once
21+
22+
#include <Utility/CppMacros.h>
23+
24+
25+
#if defined(__linux__) || defined(__CYGWIN__)
26+
#include <endian.h>
27+
28+
#elif defined(__APPLE__)
29+
#include <libkern/OSByteOrder.h>
30+
31+
#define htobe16(x) OSSwapHostToBigInt16(x)
32+
#define htole16(x) OSSwapHostToLittleInt16(x)
33+
#define be16toh(x) OSSwapBigToHostInt16(x)
34+
#define le16toh(x) OSSwapLittleToHostInt16(x)
35+
36+
#define htobe32(x) OSSwapHostToBigInt32(x)
37+
#define htole32(x) OSSwapHostToLittleInt32(x)
38+
#define be32toh(x) OSSwapBigToHostInt32(x)
39+
#define le32toh(x) OSSwapLittleToHostInt32(x)
40+
41+
#define htobe64(x) OSSwapHostToBigInt64(x)
42+
#define htole64(x) OSSwapHostToLittleInt64(x)
43+
#define be64toh(x) OSSwapBigToHostInt64(x)
44+
#define le64toh(x) OSSwapLittleToHostInt64(x)
45+
46+
#elif defined(__OpenBSD__)
47+
#include <sys/endian.h>
48+
49+
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
50+
#include <sys/endian.h>
51+
52+
#define be16toh(x) betoh16(x)
53+
#define le16toh(x) letoh16(x)
54+
55+
#define be32toh(x) betoh32(x)
56+
#define le32toh(x) letoh32(x)
57+
58+
#define be64toh(x) betoh64(x)
59+
#define le64toh(x) letoh64(x)
60+
61+
#elif defined(_WIN32) || defined(_WIN64)
62+
#if defined (_MSC_VER)
63+
#include <intrin.h>
64+
#else
65+
#include <stdlib.h>
66+
#endif // _MSC_VER
67+
68+
#define htobe16(x) _byteswap_ushort(x)
69+
#define htole16(x) (x)
70+
#define be16toh(x) _byteswap_ushort(x)
71+
#define le16toh(x) (x)
72+
73+
#define htobe32(x) _byteswap_ulong(x)
74+
#define htole32(x) (x)
75+
#define be32toh(x) _byteswap_ulong(x)
76+
#define le32toh(x) (x)
77+
78+
#define htobe64(x) _byteswap_uint64(x)
79+
#define htole64(x) (x)
80+
#define be64toh(x) _byteswap_uint64(x)
81+
#define le64toh(x) (x)
82+
83+
#else
84+
#error platform not supported
85+
#endif
86+
87+
88+
//Endian helper function data types
89+
#if defined(__linux__) || defined(__CYGWIN__)
90+
typedef uint16_t SwapType16;
91+
typedef uint32_t SwapType32;
92+
typedef uint64_t SwapType64;
93+
94+
#elif defined(__APPLE__)
95+
typedef UInt16 SwapType16;
96+
typedef UInt32 SwapType32;
97+
typedef UInt64 SwapType64;
98+
99+
#elif defined(__OpenBSD__)
100+
typedef uint16_t SwapType16;
101+
typedef uint32_t SwapType32;
102+
typedef uint64_t SwapType64;
103+
104+
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
105+
typedef uint16_t SwapType16;
106+
typedef uint32_t SwapType32;
107+
typedef uint64_t SwapType64;
108+
109+
#elif defined(_WIN32) || defined(_WIN64)
110+
typedef unsigned short SwapType16;
111+
typedef unsigned long SwapType32;
112+
typedef unsigned long long SwapType64;
113+
114+
#else
115+
#error platform not supported
116+
#endif
117+
118+
119+
//Endian helper functions
120+
static_assert(sizeof(SwapType16) == 2, "expected size does not match");
121+
static_assert(sizeof(SwapType32) == 4, "expected size does not match");
122+
static_assert(sizeof(SwapType64) == 8, "expected size does not match");
123+
124+
namespace Endian
125+
{
126+
template <typename Type, size_t Size = sizeof(Type)> struct htobeHelper;
127+
template <typename Type, size_t Size = sizeof(Type)> struct htoleHelper;
128+
template <typename Type, size_t Size = sizeof(Type)> struct betohHelper;
129+
template <typename Type, size_t Size = sizeof(Type)> struct letohHelper;
130+
131+
// 2 byte integer, enum
132+
template <typename Type> struct htobeHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(htobe16(static_cast<SwapType16>(value))); } };
133+
template <typename Type> struct htoleHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(htole16(static_cast<SwapType16>(value))); } };
134+
template <typename Type> struct betohHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(be16toh(static_cast<SwapType16>(value))); } };
135+
template <typename Type> struct letohHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType16>(value))); } };
136+
// 4 byte integer, enum
137+
template <typename Type> struct htobeHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(htobe32(static_cast<SwapType32>(value))); } };
138+
template <typename Type> struct htoleHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(htole32(static_cast<SwapType32>(value))); } };
139+
template <typename Type> struct betohHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(be32toh(static_cast<SwapType32>(value))); } };
140+
template <typename Type> struct letohHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType32>(value))); } };
141+
// 8 byte integer, enum
142+
template <typename Type> struct htobeHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(htobe64(static_cast<SwapType64>(value))); } };
143+
template <typename Type> struct htoleHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(htole64(static_cast<SwapType64>(value))); } };
144+
template <typename Type> struct betohHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(be64toh(static_cast<SwapType64>(value))); } };
145+
template <typename Type> struct letohHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType64>(value))); } };
146+
// float
147+
template <> struct htobeHelper<float, 4> { static inline float swap(float value) { SwapType32 v = htobe32(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
148+
template <> struct htoleHelper<float, 4> { static inline float swap(float value) { SwapType32 v = htole32(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
149+
template <> struct betohHelper<float, 4> { static inline float swap(float value) { SwapType32 v = be32toh(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
150+
template <> struct letohHelper<float, 4> { static inline float swap(float value) { SwapType32 v = le16toh(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
151+
// double
152+
template <> struct htobeHelper<double, 8> { static inline double swap(double value) { SwapType64 v = htobe64(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
153+
template <> struct htoleHelper<double, 8> { static inline double swap(double value) { SwapType64 v = htole64(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
154+
template <> struct betohHelper<double, 8> { static inline double swap(double value) { SwapType64 v = be64toh(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
155+
template <> struct letohHelper<double, 8> { static inline double swap(double value) { SwapType64 v = le16toh(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
156+
} // namespace Detail
157+
158+
// c++ template functions, takes any 2, 4, 8 bytes, including float, double, enum
159+
160+
// Host to big endian
161+
template<typename Type> inline Type htobe(Type value) { return Endian::htobeHelper<Type>::swap(value); }
162+
// Host to little endian
163+
template<typename Type> inline Type htole(Type value) { return Endian::htoleHelper<Type>::swap(value); }
164+
// Big endian to host
165+
template<typename Type> inline Type betoh(Type value) { return Endian::betohHelper<Type>::swap(value); }
166+
// Little endian to host
167+
template<typename Type> inline Type letoh(Type value) { return Endian::letohHelper<Type>::swap(value); }
168+
169+
// Host to big endian
170+
template<typename Type> inline void htobe_ref(Type &value) { value = Endian::htobeHelper<Type>::swap(value); }
171+
// Host to little endian
172+
template<typename Type> inline void htole_ref(Type &value) { value = Endian::htoleHelper<Type>::swap(value); }
173+
// Big endian to host
174+
template<typename Type> inline void betoh_ref(Type &value) { value = Endian::betohHelper<Type>::swap(value); }
175+
// Little endian to host
176+
template<typename Type> inline void letoh_ref(Type &value) { value = Endian::letohHelper<Type>::swap(value); }

Generals/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
// Bryan Cleveland, August 2002
2727
/////////////////////////////////////////////////////////////
2828

29-
#include <winsock2.h>
3029
#include "Common/AudioAffect.h"
3130
#include "Common/ArchiveFile.h"
3231
#include "Common/ArchiveFileSystem.h"
@@ -36,6 +35,7 @@
3635
#include "Common/LocalFileSystem.h"
3736
#include "Win32Device/Common/Win32BIGFile.h"
3837
#include "Win32Device/Common/Win32BIGFileSystem.h"
38+
#include "Utility/endian_compat.h"
3939

4040
#ifdef RTS_INTERNAL
4141
// for occasional debugging...
@@ -107,7 +107,7 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) {
107107
// read in the number of files contained in this BIG file.
108108
// change the order of the bytes cause the file size is in reverse byte order for some reason.
109109
fp->read(&numLittleFiles, 4);
110-
numLittleFiles = ntohl(numLittleFiles);
110+
numLittleFiles = betoh(numLittleFiles);
111111

112112
DEBUG_LOG(("Win32BIGFileSystem::openArchiveFile - %d are contained in archive\n", numLittleFiles));
113113
// for (Int i = 0; i < 2; ++i) {
@@ -127,8 +127,8 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) {
127127
fp->read(&fileOffset, 4);
128128
fp->read(&filesize, 4);
129129

130-
filesize = ntohl(filesize);
131-
fileOffset = ntohl(fileOffset);
130+
filesize = betoh(filesize);
131+
fileOffset = betoh(fileOffset);
132132

133133
fileInfo->m_archiveFilename = archiveFileName;
134134
fileInfo->m_offset = fileOffset;

GeneralsMD/Code/GameEngineDevice/Source/StdDevice/Common/StdBIGFileSystem.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "StdDevice/Common/StdBIGFile.h"
3737
#include "StdDevice/Common/StdBIGFileSystem.h"
3838
#include "Common/Registry.h"
39+
#include "Utility/endian_compat.h"
3940

4041
static const char *BIGFileIdentifier = "BIGF";
4142

@@ -113,7 +114,7 @@ ArchiveFile * StdBIGFileSystem::openArchiveFile(const Char *filename) {
113114
// read in the number of files contained in this BIG file.
114115
// change the order of the bytes cause the file size is in reverse byte order for some reason.
115116
fp->read(&numLittleFiles, 4);
116-
numLittleFiles = ntohl(numLittleFiles);
117+
numLittleFiles = betoh(numLittleFiles);
117118

118119
DEBUG_LOG(("StdBIGFileSystem::openArchiveFile - %d are contained in archive\n", numLittleFiles));
119120
// for (Int i = 0; i < 2; ++i) {
@@ -133,8 +134,8 @@ ArchiveFile * StdBIGFileSystem::openArchiveFile(const Char *filename) {
133134
fp->read(&fileOffset, 4);
134135
fp->read(&filesize, 4);
135136

136-
filesize = ntohl(filesize);
137-
fileOffset = ntohl(fileOffset);
137+
filesize = betoh(filesize);
138+
fileOffset = betoh(fileOffset);
138139

139140
fileInfo->m_archiveFilename = archiveFileName;
140141
fileInfo->m_offset = fileOffset;

GeneralsMD/Code/GameEngineDevice/Source/Win32Device/Common/Win32BIGFileSystem.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
// Bryan Cleveland, August 2002
2727
/////////////////////////////////////////////////////////////
2828

29-
#include <winsock2.h>
3029
#include "Common/AudioAffect.h"
3130
#include "Common/ArchiveFile.h"
3231
#include "Common/ArchiveFileSystem.h"
@@ -37,6 +36,7 @@
3736
#include "Win32Device/Common/Win32BIGFile.h"
3837
#include "Win32Device/Common/Win32BIGFileSystem.h"
3938
#include "Common/Registry.h"
39+
#include "Utility/endian_compat.h"
4040

4141
#ifdef RTS_INTERNAL
4242
// for occasional debugging...
@@ -120,7 +120,7 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) {
120120
// read in the number of files contained in this BIG file.
121121
// change the order of the bytes cause the file size is in reverse byte order for some reason.
122122
fp->read(&numLittleFiles, 4);
123-
numLittleFiles = ntohl(numLittleFiles);
123+
numLittleFiles = betoh(numLittleFiles);
124124

125125
DEBUG_LOG(("Win32BIGFileSystem::openArchiveFile - %d are contained in archive\n", numLittleFiles));
126126
// for (Int i = 0; i < 2; ++i) {
@@ -140,8 +140,8 @@ ArchiveFile * Win32BIGFileSystem::openArchiveFile(const Char *filename) {
140140
fp->read(&fileOffset, 4);
141141
fp->read(&filesize, 4);
142142

143-
filesize = ntohl(filesize);
144-
fileOffset = ntohl(fileOffset);
143+
filesize = betoh(filesize);
144+
fileOffset = betoh(fileOffset);
145145

146146
fileInfo->m_archiveFilename = archiveFileName;
147147
fileInfo->m_offset = fileOffset;

0 commit comments

Comments
 (0)