Skip to content

Commit 497f7af

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

File tree

5 files changed

+217
-11
lines changed

5 files changed

+217
-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(expr, msg)
49+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
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+
28+
29+
#if defined(__linux__) || defined(__CYGWIN__)
30+
#include <endian.h>
31+
32+
#elif defined(__APPLE__)
33+
#include <libkern/OSByteOrder.h>
34+
35+
#define htobe16(x) OSSwapHostToBigInt16(x)
36+
#define htole16(x) OSSwapHostToLittleInt16(x)
37+
#define be16toh(x) OSSwapBigToHostInt16(x)
38+
#define le16toh(x) OSSwapLittleToHostInt16(x)
39+
40+
#define htobe32(x) OSSwapHostToBigInt32(x)
41+
#define htole32(x) OSSwapHostToLittleInt32(x)
42+
#define be32toh(x) OSSwapBigToHostInt32(x)
43+
#define le32toh(x) OSSwapLittleToHostInt32(x)
44+
45+
#define htobe64(x) OSSwapHostToBigInt64(x)
46+
#define htole64(x) OSSwapHostToLittleInt64(x)
47+
#define be64toh(x) OSSwapBigToHostInt64(x)
48+
#define le64toh(x) OSSwapLittleToHostInt64(x)
49+
50+
#elif defined(__OpenBSD__)
51+
#include <sys/endian.h>
52+
53+
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
54+
#include <sys/endian.h>
55+
56+
#define be16toh(x) betoh16(x)
57+
#define le16toh(x) letoh16(x)
58+
59+
#define be32toh(x) betoh32(x)
60+
#define le32toh(x) letoh32(x)
61+
62+
#define be64toh(x) betoh64(x)
63+
#define le64toh(x) letoh64(x)
64+
65+
#elif defined(_WIN32) || defined(_WIN64)
66+
#if defined(_MSC_VER) && _MSC_VER > 1300
67+
#include <intrin.h>
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+
#else
83+
#include <winsock2.h>
84+
#define htobe16(x) htons(x)
85+
#define htole16(x) (x)
86+
#define be16toh(x) ntohs(x)
87+
#define le16toh(x) (x)
88+
89+
#define htobe32(x) htonl(x)
90+
#define htole32(x) (x)
91+
#define be32toh(x) ntohl(x)
92+
#define le32toh(x) (x)
93+
94+
#define htobe64(x) ((unsigned __int64)htonl((unsigned long)(x & 0xFFFFFFFF)) << 32) | htonl((unsigned long)(x >> 32))
95+
#define htole64(x) (x)
96+
#define be64toh(x) ((unsigned __int64)ntohl((unsigned long)(x & 0xFFFFFFFF)) << 32) | ntohl((unsigned long)(x >> 32))
97+
#define le64toh(x) (x)
98+
#endif // _MSC_VER
99+
100+
#else
101+
#error platform not supported
102+
#endif
103+
104+
105+
//Endian helper function data types
106+
#if defined(__linux__) || defined(__CYGWIN__)
107+
typedef uint16_t SwapType16;
108+
typedef uint32_t SwapType32;
109+
typedef uint64_t SwapType64;
110+
111+
#elif defined(__APPLE__)
112+
typedef UInt16 SwapType16;
113+
typedef UInt32 SwapType32;
114+
typedef UInt64 SwapType64;
115+
116+
#elif defined(__OpenBSD__)
117+
typedef uint16_t SwapType16;
118+
typedef uint32_t SwapType32;
119+
typedef uint64_t SwapType64;
120+
121+
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
122+
typedef uint16_t SwapType16;
123+
typedef uint32_t SwapType32;
124+
typedef uint64_t SwapType64;
125+
126+
#elif defined(_WIN32) || defined(_WIN64)
127+
#if defined(_MSC_VER) && _MSC_VER < 1300
128+
typedef unsigned short SwapType16;
129+
typedef unsigned long SwapType32;
130+
typedef unsigned __int64 SwapType64;
131+
#else
132+
typedef unsigned short SwapType16;
133+
typedef unsigned long SwapType32;
134+
typedef unsigned long long SwapType64;
135+
#endif // _MSC_VER
136+
137+
#else
138+
#error platform not supported
139+
#endif
140+
141+
142+
//Endian helper functions
143+
static_assert(sizeof(SwapType16) == 2, "expected size does not match");
144+
static_assert(sizeof(SwapType32) == 4, "expected size does not match");
145+
static_assert(sizeof(SwapType64) == 8, "expected size does not match");
146+
147+
namespace Endian
148+
{
149+
template <typename Type, size_t Size = sizeof(Type)> struct htobeHelper;
150+
template <typename Type, size_t Size = sizeof(Type)> struct htoleHelper;
151+
template <typename Type, size_t Size = sizeof(Type)> struct betohHelper;
152+
template <typename Type, size_t Size = sizeof(Type)> struct letohHelper;
153+
154+
// 2 byte integer, enum
155+
template <typename Type> struct htobeHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(htobe16(static_cast<SwapType16>(value))); } };
156+
template <typename Type> struct htoleHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(htole16(static_cast<SwapType16>(value))); } };
157+
template <typename Type> struct betohHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(be16toh(static_cast<SwapType16>(value))); } };
158+
template <typename Type> struct letohHelper<Type, 2> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType16>(value))); } };
159+
// 4 byte integer, enum
160+
template <typename Type> struct htobeHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(htobe32(static_cast<SwapType32>(value))); } };
161+
template <typename Type> struct htoleHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(htole32(static_cast<SwapType32>(value))); } };
162+
template <typename Type> struct betohHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(be32toh(static_cast<SwapType32>(value))); } };
163+
template <typename Type> struct letohHelper<Type, 4> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType32>(value))); } };
164+
// 8 byte integer, enum
165+
template <typename Type> struct htobeHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(htobe64(static_cast<SwapType64>(value))); } };
166+
template <typename Type> struct htoleHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(htole64(static_cast<SwapType64>(value))); } };
167+
template <typename Type> struct betohHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(be64toh(static_cast<SwapType64>(value))); } };
168+
template <typename Type> struct letohHelper<Type, 8> { static inline Type swap(Type value) { return static_cast<Type>(le16toh(static_cast<SwapType64>(value))); } };
169+
// float
170+
template <> struct htobeHelper<float, 4> { static inline float swap(float value) { SwapType32 v = htobe32(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
171+
template <> struct htoleHelper<float, 4> { static inline float swap(float value) { SwapType32 v = htole32(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
172+
template <> struct betohHelper<float, 4> { static inline float swap(float value) { SwapType32 v = be32toh(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
173+
template <> struct letohHelper<float, 4> { static inline float swap(float value) { SwapType32 v = le16toh(*reinterpret_cast<SwapType32*>(&value)); return *reinterpret_cast<float*>(&v); } };
174+
// double
175+
template <> struct htobeHelper<double, 8> { static inline double swap(double value) { SwapType64 v = htobe64(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
176+
template <> struct htoleHelper<double, 8> { static inline double swap(double value) { SwapType64 v = htole64(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
177+
template <> struct betohHelper<double, 8> { static inline double swap(double value) { SwapType64 v = be64toh(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
178+
template <> struct letohHelper<double, 8> { static inline double swap(double value) { SwapType64 v = le16toh(*reinterpret_cast<SwapType64*>(&value)); return *reinterpret_cast<double*>(&v); } };
179+
} // namespace Endian
180+
181+
// c++ template functions, takes any 2, 4, 8 bytes, including float, double, enum
182+
183+
// Host to big endian
184+
template<typename Type> inline Type htobe(Type value) { return Endian::htobeHelper<Type>::swap(value); }
185+
// Host to little endian
186+
template<typename Type> inline Type htole(Type value) { return Endian::htoleHelper<Type>::swap(value); }
187+
// Big endian to host
188+
template<typename Type> inline Type betoh(Type value) { return Endian::betohHelper<Type>::swap(value); }
189+
// Little endian to host
190+
template<typename Type> inline Type letoh(Type value) { return Endian::letohHelper<Type>::swap(value); }
191+
192+
// Host to big endian
193+
template<typename Type> inline void htobe_ref(Type &value) { value = Endian::htobeHelper<Type>::swap(value); }
194+
// Host to little endian
195+
template<typename Type> inline void htole_ref(Type &value) { value = Endian::htoleHelper<Type>::swap(value); }
196+
// Big endian to host
197+
template<typename Type> inline void betoh_ref(Type &value) { value = Endian::betohHelper<Type>::swap(value); }
198+
// Little endian to host
199+
template<typename Type> inline void letoh_ref(Type &value) { value = Endian::letohHelper<Type>::swap(value); }
200+
201+
#endif // ENDIAN_COMPAT_H

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)