mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #5279 from LRFLEW/case-insensitive-ini
Make the INI keys case insensitive
This commit is contained in:
commit
6d2776da2b
|
@ -726,11 +726,11 @@
|
|||
D429FF411E36ABCD009342A6 /* tile_inspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tile_inspector.h; sourceTree = "<group>"; };
|
||||
D42E33751E5C27D600D630AF /* Config.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Config.cpp; sourceTree = "<group>"; };
|
||||
D42E33761E5C27D600D630AF /* Config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Config.h; sourceTree = "<group>"; };
|
||||
D42E33771E5C27D600D630AF /* ConfigEnum.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConfigEnum.h; sourceTree = "<group>"; };
|
||||
D42E33771E5C27D600D630AF /* ConfigEnum.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ConfigEnum.hpp; sourceTree = "<group>"; };
|
||||
D42E33781E5C27D600D630AF /* IniReader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IniReader.cpp; sourceTree = "<group>"; };
|
||||
D42E33791E5C27D600D630AF /* IniReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IniReader.h; sourceTree = "<group>"; };
|
||||
D42E33791E5C27D600D630AF /* IniReader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IniReader.hpp; sourceTree = "<group>"; };
|
||||
D42E337A1E5C27D600D630AF /* IniWriter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IniWriter.cpp; sourceTree = "<group>"; };
|
||||
D42E337B1E5C27D600D630AF /* IniWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IniWriter.h; sourceTree = "<group>"; };
|
||||
D42E337B1E5C27D600D630AF /* IniWriter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IniWriter.hpp; sourceTree = "<group>"; };
|
||||
D42E337C1E5C27D600D630AF /* KeyboardShortcuts.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = KeyboardShortcuts.cpp; sourceTree = "<group>"; };
|
||||
D433A4FA1E4A861F00D9A6DF /* SawyerChunk.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SawyerChunk.cpp; path = rct12/SawyerChunk.cpp; sourceTree = "<group>"; };
|
||||
D433A4FB1E4A861F00D9A6DF /* SawyerChunk.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SawyerChunk.h; path = rct12/SawyerChunk.h; sourceTree = "<group>"; };
|
||||
|
@ -1622,11 +1622,11 @@
|
|||
children = (
|
||||
D42E33751E5C27D600D630AF /* Config.cpp */,
|
||||
D42E33761E5C27D600D630AF /* Config.h */,
|
||||
D42E33771E5C27D600D630AF /* ConfigEnum.h */,
|
||||
D42E33771E5C27D600D630AF /* ConfigEnum.hpp */,
|
||||
D42E33781E5C27D600D630AF /* IniReader.cpp */,
|
||||
D42E33791E5C27D600D630AF /* IniReader.h */,
|
||||
D42E33791E5C27D600D630AF /* IniReader.hpp */,
|
||||
D42E337A1E5C27D600D630AF /* IniWriter.cpp */,
|
||||
D42E337B1E5C27D600D630AF /* IniWriter.h */,
|
||||
D42E337B1E5C27D600D630AF /* IniWriter.hpp */,
|
||||
D42E337C1E5C27D600D630AF /* KeyboardShortcuts.cpp */,
|
||||
);
|
||||
path = config;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
*****************************************************************************/
|
||||
#pragma endregion
|
||||
|
||||
#include <cctype>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
@ -57,13 +58,46 @@ struct LineRange
|
|||
}
|
||||
};
|
||||
|
||||
struct StringIHash
|
||||
{
|
||||
std::size_t operator()(const std::string &s) const
|
||||
{
|
||||
typedef std::char_traits<char> Traits;
|
||||
std::size_t seed = 0;
|
||||
for (const char &c : s)
|
||||
{
|
||||
const Traits::int_type value = std::toupper(Traits::to_int_type(c));
|
||||
// Simple Hash Combine as used by Boost.Functional/Hash
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
struct StringICmp
|
||||
{
|
||||
bool operator()(const std::string &a, const std::string &b) const
|
||||
{
|
||||
typedef std::char_traits<char> Traits;
|
||||
if (a.size() != b.size()) return false;
|
||||
const char *s1 = a.data(), *s2 = b.data();
|
||||
for (std::size_t i = a.size(); i > 0; --i, ++s1, ++s2)
|
||||
{
|
||||
const int c1 = std::toupper(Traits::to_int_type(*s1));
|
||||
const int c2 = std::toupper(Traits::to_int_type(*s1));
|
||||
if (c1 != c2) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class IniReader final : public IIniReader
|
||||
{
|
||||
private:
|
||||
std::vector<uint8> _buffer;
|
||||
std::vector<Span> _lines;
|
||||
std::unordered_map<std::string, LineRange> _sections;
|
||||
std::unordered_map<std::string, std::string> _values;
|
||||
std::vector<uint8> _buffer;
|
||||
std::vector<Span> _lines;
|
||||
std::unordered_map<std::string, LineRange, StringIHash, StringICmp> _sections;
|
||||
std::unordered_map<std::string, std::string, StringIHash, StringICmp> _values;
|
||||
|
||||
public:
|
||||
IniReader(IStream * stream)
|
||||
|
|
|
@ -12,6 +12,7 @@ protected:
|
|||
static const std::string predefined;
|
||||
static const std::string duplicate;
|
||||
static const std::string untrimmed;
|
||||
static const std::string caseInsensitive;
|
||||
};
|
||||
|
||||
static auto Enum_Currency = ConfigEnum<sint32>({});
|
||||
|
@ -105,6 +106,19 @@ TEST_F(IniReaderTest, read_untrimmed)
|
|||
delete ir;
|
||||
}
|
||||
|
||||
TEST_F(IniReaderTest, read_case_insensitive)
|
||||
{
|
||||
MemoryStream ms(caseInsensitive.c_str(), caseInsensitive.size());
|
||||
ASSERT_EQ(ms.CanRead(), true);
|
||||
ASSERT_EQ(ms.CanWrite(), false);
|
||||
IIniReader * ir = CreateIniReader(&ms);
|
||||
ASSERT_NE(ir, nullptr);
|
||||
ASSERT_EQ(ir->ReadSection("section"), true);
|
||||
ASSERT_EQ(ir->GetString("foo", "yyy"), "bar");
|
||||
ASSERT_EQ(ir->ReadSection("SeCtIoN"), true);
|
||||
delete ir;
|
||||
}
|
||||
|
||||
const std::string IniReaderTest::predefined =
|
||||
"[bool]\n"
|
||||
"boolval = true\n\n"
|
||||
|
@ -130,3 +144,7 @@ const std::string IniReaderTest::untrimmed =
|
|||
"[section]\n"
|
||||
"one = true \n"
|
||||
" str = \" xxx \"";
|
||||
|
||||
const std::string IniReaderTest::caseInsensitive =
|
||||
"[sEcTiOn]\n"
|
||||
"foo = \"bar\"\n";
|
||||
|
|
Loading…
Reference in New Issue