Skip to content

Commit 85fdc80

Browse files
authored
fix(filesystem): Decouple File System from NameKeyGenerator and its CRC influence (#1516)
1 parent 0609129 commit 85fdc80

File tree

10 files changed

+268
-19
lines changed

10 files changed

+268
-19
lines changed

Core/GameEngine/Include/Common/AsciiString.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class AsciiString
114114

115115
public:
116116

117+
typedef Char value_type;
118+
typedef value_type* pointer;
119+
typedef const value_type* const_pointer;
120+
117121
enum
118122
{
119123
MAX_FORMAT_BUF_LEN = 2048, ///< max total len of string created by format/format_va

Core/GameEngine/Include/Common/FileSystem.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
#include "Common/STLTypedefs.h"
5555
#include "Common/SubsystemInterface.h"
5656

57+
#include <Utility/hash_map_adapter.h>
58+
5759
//----------------------------------------------------------------------------
5860
// Forward References
5961
//----------------------------------------------------------------------------
@@ -117,7 +119,6 @@ struct FileInfo {
117119
* created when FileSystem::Open() gets called.
118120
*/
119121
//===============================
120-
#include <map>
121122

122123
class FileSystem : public SubsystemInterface
123124
{
@@ -147,7 +148,11 @@ class FileSystem : public SubsystemInterface
147148

148149
protected:
149150
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
150-
mutable std::map<unsigned,bool> m_fileExist;
151+
typedef std::hash_map<
152+
rts::string_key<AsciiString>, bool,
153+
rts::string_key_hash<AsciiString>,
154+
rts::string_key_equal<AsciiString> > FileExistMap;
155+
mutable FileExistMap m_fileExist;
151156
#endif
152157
};
153158

Core/GameEngine/Include/Common/UnicodeString.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class UnicodeString
114114

115115
public:
116116

117+
typedef WideChar value_type;
118+
typedef value_type* pointer;
119+
typedef const value_type* const_pointer;
120+
117121
enum
118122
{
119123
MAX_FORMAT_BUF_LEN = 2048, ///< max total len of string created by format/format_va

Core/GameEngine/Source/Common/System/FileSystem.cpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ File* FileSystem::openFile( const Char *filename, Int access, size_t bufferSize
183183
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
184184
if (file != NULL && (file->getAccess() & File::CREATE))
185185
{
186-
unsigned key = TheNameKeyGenerator->nameToLowercaseKey(filename);
187-
m_fileExist[key] = true;
186+
m_fileExist[filename]=true;
188187
}
189188
#endif
190189
}
@@ -206,29 +205,30 @@ Bool FileSystem::doesFileExist(const Char *filename) const
206205
USE_PERF_TIMER(FileSystem)
207206

208207
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
209-
unsigned key=TheNameKeyGenerator->nameToLowercaseKey(filename);
210-
std::map<unsigned,bool>::iterator i=m_fileExist.find(key);
211-
if (i!=m_fileExist.end())
212-
return i->second;
208+
{
209+
FileExistMap::iterator i = m_fileExist.find(FileExistMap::key_type::temporary(filename));
210+
if (i!=m_fileExist.end())
211+
return i->second;
212+
}
213213
#endif
214214

215215
if (TheLocalFileSystem->doesFileExist(filename))
216216
{
217217
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
218-
m_fileExist[key]=true;
218+
m_fileExist[filename]=true;
219219
#endif
220220
return TRUE;
221221
}
222222
if (TheArchiveFileSystem->doesFileExist(filename))
223223
{
224224
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
225-
m_fileExist[key]=true;
225+
m_fileExist[filename]=true;
226226
#endif
227227
return TRUE;
228228
}
229229

230230
#if ENABLE_FILESYSTEM_EXISTENCE_CACHE
231-
m_fileExist[key]=false;
231+
m_fileExist[filename]=false;
232232
#endif
233233
return FALSE;
234234
}

Generals/Code/GameEngine/Include/Common/NameKeyGenerator.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ class NameKeyGenerator : public SubsystemInterface
123123
SOCKET_COUNT = 6473
124124
};
125125

126+
#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
127+
Bool addReservedKey();
128+
#endif
129+
130+
NameKeyType nameToKeyImpl(const char* name);
131+
NameKeyType nameToLowercaseKeyImpl(const char *name);
132+
126133
void freeSockets();
127134

128135
Bucket* m_sockets[SOCKET_COUNT]; ///< Catalog of all Buckets already generated

Generals/Code/GameEngine/Include/Common/STLTypedefs.h

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,24 @@ namespace rts
177177
}
178178
};
179179

180+
template<> struct hash<const Char*>
181+
{
182+
size_t operator()(const Char* s) const
183+
{
184+
#ifdef USING_STLPORT
185+
std::hash<const Char*> hasher;
186+
return hasher(s);
187+
#else
188+
std::hash<std::string_view> hasher;
189+
return hasher(s);
190+
#endif
191+
}
192+
};
193+
180194
// This is the equal_to overload for char* comparisons. We compare the
181195
// strings to determine whether they are equal or not.
182196
// Other overloads should go into specific header files, not here (unless
183-
// they are ot be used in lots of places.)
197+
// they are to be used in lots of places.)
184198
template<> struct equal_to<const char*>
185199
{
186200
Bool operator()(const char* s1, const char* s2) const
@@ -227,6 +241,62 @@ namespace rts
227241
return (__t1.compareNoCase(__t2) < 0);
228242
}
229243
};
230-
}
244+
245+
// TheSuperHackers @info Structs to help create maps that can use C strings for
246+
// lookups without the need to allocate a string.
247+
template <typename String>
248+
struct string_key
249+
{
250+
typedef typename String::const_pointer const_pointer;
251+
252+
static string_key temporary(const_pointer s)
253+
{
254+
string_key key;
255+
key.cstr = s;
256+
return key;
257+
}
258+
259+
string_key(const_pointer s)
260+
: storage(s)
261+
, cstr(storage.str())
262+
{}
263+
264+
string_key(const String& s)
265+
: storage(s)
266+
, cstr(storage.str())
267+
{}
268+
269+
const_pointer c_str() const
270+
{
271+
return cstr;
272+
}
273+
274+
private:
275+
string_key() {}
276+
277+
String storage;
278+
const_pointer cstr;
279+
};
280+
281+
template <typename String>
282+
struct string_key_hash
283+
{
284+
typedef typename String::const_pointer const_pointer;
285+
size_t operator()(const string_key<String>& key) const
286+
{
287+
return hash<const_pointer>()(key.c_str());
288+
}
289+
};
290+
291+
template <typename String>
292+
struct string_key_equal
293+
{
294+
bool operator()(const string_key<String>& a, const string_key<String>& b) const
295+
{
296+
return strcmp(a.c_str(), b.c_str()) == 0;
297+
}
298+
};
299+
300+
} // namespace rts
231301

232302
#endif /* __STLTYPEDEFS_H__ */

Generals/Code/GameEngine/Source/Common/NameKeyGenerator.cpp

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,48 @@ AsciiString NameKeyGenerator::keyToName(NameKeyType key)
123123
}
124124

125125
//-------------------------------------------------------------------------------------------------
126-
NameKeyType NameKeyGenerator::nameToKey(const char* nameString)
126+
#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
127+
// TheSuperHackers @info xezon 04/09/2025 This key reservation is required for CRC compatibility,
128+
// because the name keys are somehow CRC relevant. It was originally used by the file exist cache
129+
// of the file system in Zero Hour.
130+
Bool NameKeyGenerator::addReservedKey()
131+
{
132+
switch (m_nextID)
133+
{
134+
case 97: nameToLowercaseKeyImpl("Data\\English\\Language9x.ini"); return true;
135+
case 98: nameToLowercaseKeyImpl("Data\\Audio\\Tracks\\English\\GLA_02.mp3"); return true;
136+
case 99: nameToLowercaseKeyImpl("Data\\Audio\\Tracks\\GLA_02.mp3"); return true;
137+
}
138+
return false;
139+
}
140+
#endif
141+
142+
//-------------------------------------------------------------------------------------------------
143+
NameKeyType NameKeyGenerator::nameToKey(const char* name)
144+
{
145+
const NameKeyType key = nameToKeyImpl(name);
146+
147+
#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
148+
while (addReservedKey());
149+
#endif
150+
151+
return key;
152+
}
153+
154+
//-------------------------------------------------------------------------------------------------
155+
NameKeyType NameKeyGenerator::nameToLowercaseKey(const char *name)
156+
{
157+
const NameKeyType key = nameToLowercaseKeyImpl(name);
158+
159+
#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
160+
while (addReservedKey());
161+
#endif
162+
163+
return key;
164+
}
165+
166+
//-------------------------------------------------------------------------------------------------
167+
NameKeyType NameKeyGenerator::nameToKeyImpl(const char* nameString)
127168
{
128169
Bucket *b;
129170

@@ -171,7 +212,7 @@ NameKeyType NameKeyGenerator::nameToKey(const char* nameString)
171212
} // end nameToKey
172213

173214
//-------------------------------------------------------------------------------------------------
174-
NameKeyType NameKeyGenerator::nameToLowercaseKey(const char* nameString)
215+
NameKeyType NameKeyGenerator::nameToLowercaseKeyImpl(const char* nameString)
175216
{
176217
Bucket *b;
177218

GeneralsMD/Code/GameEngine/Include/Common/NameKeyGenerator.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,13 @@ class NameKeyGenerator : public SubsystemInterface
121121
SOCKET_COUNT = 45007
122122
};
123123

124+
#if RTS_ZEROHOUR && RETAIL_COMPATIBLE_CRC
125+
Bool addReservedKey();
126+
#endif
127+
128+
NameKeyType nameToKeyImpl(const char* name);
129+
NameKeyType nameToLowercaseKeyImpl(const char *name);
130+
124131
void freeSockets();
125132

126133
Bucket* m_sockets[SOCKET_COUNT]; ///< Catalog of all Buckets already generated

GeneralsMD/Code/GameEngine/Include/Common/STLTypedefs.h

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,24 @@ namespace rts
177177
}
178178
};
179179

180+
template<> struct hash<const Char*>
181+
{
182+
size_t operator()(const Char* s) const
183+
{
184+
#ifdef USING_STLPORT
185+
std::hash<const Char*> hasher;
186+
return hasher(s);
187+
#else
188+
std::hash<std::string_view> hasher;
189+
return hasher(s);
190+
#endif
191+
}
192+
};
193+
180194
// This is the equal_to overload for char* comparisons. We compare the
181195
// strings to determine whether they are equal or not.
182196
// Other overloads should go into specific header files, not here (unless
183-
// they are ot be used in lots of places.)
197+
// they are to be used in lots of places.)
184198
template<> struct equal_to<const char*>
185199
{
186200
Bool operator()(const char* s1, const char* s2) const
@@ -227,6 +241,62 @@ namespace rts
227241
return (__t1.compareNoCase(__t2) < 0);
228242
}
229243
};
230-
}
244+
245+
// TheSuperHackers @info Structs to help create maps that can use C strings for
246+
// lookups without the need to allocate a string.
247+
template <typename String>
248+
struct string_key
249+
{
250+
typedef typename String::const_pointer const_pointer;
251+
252+
static string_key temporary(const_pointer s)
253+
{
254+
string_key key;
255+
key.cstr = s;
256+
return key;
257+
}
258+
259+
string_key(const_pointer s)
260+
: storage(s)
261+
, cstr(storage.str())
262+
{}
263+
264+
string_key(const String& s)
265+
: storage(s)
266+
, cstr(storage.str())
267+
{}
268+
269+
const_pointer c_str() const
270+
{
271+
return cstr;
272+
}
273+
274+
private:
275+
string_key() {}
276+
277+
String storage;
278+
const_pointer cstr;
279+
};
280+
281+
template <typename String>
282+
struct string_key_hash
283+
{
284+
typedef typename String::const_pointer const_pointer;
285+
size_t operator()(const string_key<String>& key) const
286+
{
287+
return hash<const_pointer>()(key.c_str());
288+
}
289+
};
290+
291+
template <typename String>
292+
struct string_key_equal
293+
{
294+
bool operator()(const string_key<String>& a, const string_key<String>& b) const
295+
{
296+
return strcmp(a.c_str(), b.c_str()) == 0;
297+
}
298+
};
299+
300+
} // namespace rts
231301

232302
#endif /* __STLTYPEDEFS_H__ */

0 commit comments

Comments
 (0)