Skip to content

Commit 4f1f489

Browse files
authored
[GEN][ZH] Add endian compat for BIGFileSystems (#798)
1 parent 2467451 commit 4f1f489

File tree

5 files changed

+262
-11
lines changed

5 files changed

+262
-11
lines changed

Dependencies/Utility/Utility/CppMacros.h

Lines changed: 4 additions & 0 deletions
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(expr, msg)
49+
#endif
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
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+
// VC6 does not support pragma once
23+
#ifndef ENDIAN_COMPAT_H
24+
#define ENDIAN_COMPAT_H
25+
26+
#include <Utility/CppMacros.h>
27+
#include <Utility/stdint_adapter.h>
28+
29+
30+
#if defined(__linux__) || defined(__CYGWIN__)
31+
#include <endian.h>
32+
33+
#elif defined(__APPLE__)
34+
#include <libkern/OSByteOrder.h>
35+
36+
#define htobe16(x) OSSwapHostToBigInt16(x)
37+
#define htole16(x) OSSwapHostToLittleInt16(x)
38+
#define be16toh(x) OSSwapBigToHostInt16(x)
39+
#define le16toh(x) OSSwapLittleToHostInt16(x)
40+
41+
#define htobe32(x) OSSwapHostToBigInt32(x)
42+
#define htole32(x) OSSwapHostToLittleInt32(x)
43+
#define be32toh(x) OSSwapBigToHostInt32(x)
44+
#define le32toh(x) OSSwapLittleToHostInt32(x)
45+
46+
#define htobe64(x) OSSwapHostToBigInt64(x)
47+
#define htole64(x) OSSwapHostToLittleInt64(x)
48+
#define be64toh(x) OSSwapBigToHostInt64(x)
49+
#define le64toh(x) OSSwapLittleToHostInt64(x)
50+
51+
#elif defined(__OpenBSD__)
52+
#include <sys/endian.h>
53+
54+
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
55+
#include <sys/endian.h>
56+
57+
#define be16toh(x) betoh16(x)
58+
#define le16toh(x) letoh16(x)
59+
60+
#define be32toh(x) betoh32(x)
61+
#define le32toh(x) letoh32(x)
62+
63+
#define be64toh(x) betoh64(x)
64+
#define le64toh(x) letoh64(x)
65+
66+
#elif defined(_WIN32) || defined(_WIN64)
67+
#if !(defined(_MSC_VER) && _MSC_VER < 1300)
68+
#include <intrin.h>
69+
#define htobe16(x) _byteswap_ushort(x)
70+
#define htole16(x) (x)
71+
#define be16toh(x) _byteswap_ushort(x)
72+
#define le16toh(x) (x)
73+
74+
#define htobe32(x) _byteswap_ulong(x)
75+
#define htole32(x) (x)
76+
#define be32toh(x) _byteswap_ulong(x)
77+
#define le32toh(x) (x)
78+
79+
#define htobe64(x) _byteswap_uint64(x)
80+
#define htole64(x) (x)
81+
#define be64toh(x) _byteswap_uint64(x)
82+
#define le64toh(x) (x)
83+
#else
84+
#define bswap16(x) ( (uint16_t)( ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8) ) )
85+
#define bswap32(x) ( ((x & 0xFF000000) >> 24) | \
86+
((x & 0x00FF0000) >> 8) | \
87+
((x & 0x0000FF00) << 8) | \
88+
((x & 0x000000FF) << 24) )
89+
#define bswap64(x) ( (((uint64_t)(x) & 0xFF00000000000000) >> 56) | \
90+
(((uint64_t)(x) & 0x00FF000000000000) >> 40) | \
91+
(((uint64_t)(x) & 0x0000FF0000000000) >> 24) | \
92+
(((uint64_t)(x) & 0x000000FF00000000) >> 8) | \
93+
(((uint64_t)(x) & 0x00000000FF000000) << 8) | \
94+
(((uint64_t)(x) & 0x0000000000FF0000) << 24) | \
95+
(((uint64_t)(x) & 0x000000000000FF00) << 40) | \
96+
(((uint64_t)(x) & 0x00000000000000FF) << 56) )
97+
98+
#define htobe16(x) bswap16(x)
99+
#define htole16(x) (x)
100+
#define be16toh(x) bswap16(x)
101+
#define le16toh(x) (x)
102+
103+
#define htobe32(x) bswap32(x)
104+
#define htole32(x) (x)
105+
#define be32toh(x) bswap32(x)
106+
#define le32toh(x) (x)
107+
108+
#define htobe64(x) bswap64(x)
109+
#define htole64(x) (x)
110+
#define be64toh(x) bswap64(x)
111+
#define le64toh(x) (x)
112+
113+
#endif // _MSC_VER
114+
115+
#else
116+
#error platform not supported
117+
#endif
118+
119+
120+
// Endian helper function data types
121+
#if defined(__linux__) || defined(__CYGWIN__)
122+
typedef uint16_t SwapType16;
123+
typedef uint32_t SwapType32;
124+
typedef uint64_t SwapType64;
125+
126+
#elif defined(__APPLE__)
127+
typedef UInt16 SwapType16;
128+
typedef UInt32 SwapType32;
129+
typedef UInt64 SwapType64;
130+
131+
#elif defined(__OpenBSD__)
132+
typedef uint16_t SwapType16;
133+
typedef uint32_t SwapType32;
134+
typedef uint64_t SwapType64;
135+
136+
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
137+
typedef uint16_t SwapType16;
138+
typedef uint32_t SwapType32;
139+
typedef uint64_t SwapType64;
140+
141+
#elif defined(_WIN32) || defined(_WIN64)
142+
typedef uint16_t SwapType16;
143+
typedef uint32_t SwapType32;
144+
typedef uint64_t SwapType64;
145+
146+
#else
147+
#error platform not supported
148+
#endif
149+
150+
151+
// Endian helper functions
152+
static_assert(sizeof(SwapType16) == 2, "expected size does not match");
153+
static_assert(sizeof(SwapType32) == 4, "expected size does not match");
154+
static_assert(sizeof(SwapType64) == 8, "expected size does not match");
155+
156+
// VC6 compatible overloaded endian functions
157+
#if defined(_MSC_VER) && _MSC_VER < 1300
158+
159+
// Big endian to host
160+
inline int16_t betoh(int16_t value) { return be16toh(value); }
161+
inline uint16_t betoh(uint16_t value) { return be16toh(value); }
162+
inline int32_t betoh(int32_t value) { return be32toh(value); }
163+
inline uint32_t betoh(uint32_t value) { return be32toh(value); }
164+
inline int64_t betoh(int64_t value) { return be64toh(value); }
165+
inline uint64_t betoh(uint64_t value) { return be64toh(value); }
166+
// Host to big endian
167+
inline int16_t htobe(int16_t value) { return htobe16(value); }
168+
inline uint16_t htobe(uint16_t value) { return htobe16(value); }
169+
inline int32_t htobe(int32_t value) { return htobe32(value); }
170+
inline uint32_t htobe(uint32_t value) { return htobe32(value); }
171+
inline int64_t htobe(int64_t value) { return htobe64(value); }
172+
inline uint64_t htobe(uint64_t value) { return htobe64(value); }
173+
// Little endian to host
174+
inline int16_t letoh(int16_t value) { return le16toh(value); }
175+
inline uint16_t letoh(uint16_t value) { return le16toh(value); }
176+
inline int32_t letoh(int32_t value) { return le32toh(value); }
177+
inline uint32_t letoh(uint32_t value) { return le32toh(value); }
178+
inline int64_t letoh(int64_t value) { return le64toh(value); }
179+
inline uint64_t letoh(uint64_t value) { return le64toh(value); }
180+
// Host to little endian
181+
inline int16_t htole(int16_t value) { return htole16(value); }
182+
inline uint16_t htole(uint16_t value) { return htole16(value); }
183+
inline int32_t htole(int32_t value) { return htole32(value); }
184+
inline uint32_t htole(uint32_t value) { return htole32(value); }
185+
inline int64_t htole(int64_t value) { return htole64(value); }
186+
inline uint64_t htole(uint64_t value) { return htole64(value); }
187+
188+
#else
189+
190+
namespace Endian
191+
{
192+
template <typename Type, size_t Size = sizeof(Type)> struct htobeHelper;
193+
template <typename Type, size_t Size = sizeof(Type)> struct htoleHelper;
194+
template <typename Type, size_t Size = sizeof(Type)> struct betohHelper;
195+
template <typename Type, size_t Size = sizeof(Type)> struct letohHelper;
196+
197+
// 2 byte integer, enum
198+
template <typename Type> struct htobeHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(htobe16(static_cast<SwapType16>(value))); } };
199+
template <typename Type> struct htoleHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(htole16(static_cast<SwapType16>(value))); } };
200+
template <typename Type> struct betohHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(be16toh(static_cast<SwapType16>(value))); } };
201+
template <typename Type> struct letohHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType16>(value))); } };
202+
// 4 byte integer, enum
203+
template <typename Type> struct htobeHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(htobe32(static_cast<SwapType32>(value))); } };
204+
template <typename Type> struct htoleHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(htole32(static_cast<SwapType32>(value))); } };
205+
template <typename Type> struct betohHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(be32toh(static_cast<SwapType32>(value))); } };
206+
template <typename Type> struct letohHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType32>(value))); } };
207+
// 8 byte integer, enum
208+
template <typename Type> struct htobeHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(htobe64(static_cast<SwapType64>(value))); } };
209+
template <typename Type> struct htoleHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(htole64(static_cast<SwapType64>(value))); } };
210+
template <typename Type> struct betohHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(be64toh(static_cast<SwapType64>(value))); } };
211+
template <typename Type> struct letohHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType64>(value))); } };
212+
// float
213+
template <> struct htobeHelper<float, 4> { static inline float swap(float value) { SwapType32 v = htobe32(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
214+
template <> struct htoleHelper<float, 4> { static inline float swap(float value) { SwapType32 v = htole32(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
215+
template <> struct betohHelper<float, 4> { static inline float swap(float value) { SwapType32 v = be32toh(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
216+
template <> struct letohHelper<float, 4> { static inline float swap(float value) { SwapType32 v = le16toh(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
217+
// double
218+
template <> struct htobeHelper<double, 8> { static inline double swap(double value) { SwapType64 v = htobe64(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
219+
template <> struct htoleHelper<double, 8> { static inline double swap(double value) { SwapType64 v = htole64(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
220+
template <> struct betohHelper<double, 8> { static inline double swap(double value) { SwapType64 v = be64toh(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
221+
template <> struct letohHelper<double, 8> { static inline double swap(double value) { SwapType64 v = le16toh(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
222+
} // namespace Endian
223+
224+
// c++ template functions, takes any 2, 4, 8 bytes, including float, double, enum
225+
226+
// Host to big endian
227+
template<typename Type> inline Type htobe(Type value) { return Endian::htobeHelper<Type>::swap(value); }
228+
// Host to little endian
229+
template<typename Type> inline Type htole(Type value) { return Endian::htoleHelper<Type>::swap(value); }
230+
// Big endian to host
231+
template<typename Type> inline Type betoh(Type value) { return Endian::betohHelper<Type>::swap(value); }
232+
// Little endian to host
233+
template<typename Type> inline Type letoh(Type value) { return Endian::letohHelper<Type>::swap(value); }
234+
235+
// Host to big endian
236+
template<typename Type> inline void htobe_ref(Type &value) { value = Endian::htobeHelper<Type>::swap(value); }
237+
// Host to little endian
238+
template<typename Type> inline void htole_ref(Type &value) { value = Endian::htoleHelper<Type>::swap(value); }
239+
// Big endian to host
240+
template<typename Type> inline void betoh_ref(Type &value) { value = Endian::betohHelper<Type>::swap(value); }
241+
// Little endian to host
242+
template<typename Type> inline void letoh_ref(Type &value) { value = Endian::letohHelper<Type>::swap(value); }
243+
244+
#endif // _MSC_VER < 1300
245+
246+
#endif // ENDIAN_COMPAT_H

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

Lines changed: 4 additions & 4 deletions
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

Lines changed: 4 additions & 3 deletions
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

Lines changed: 4 additions & 4 deletions
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)