Guess and convert the encoding of the game title (again)

This commit is contained in:
Struma 2021-06-08 08:33:29 -04:00 committed by Roza
parent af1924abd9
commit b6ea039803
5 changed files with 370 additions and 26 deletions

View file

@ -96,6 +96,22 @@ $(DOWNLOADS)/sigcxx/Makefile: $(DOWNLOADS)/sigcxx/autogen.sh
$(DOWNLOADS)/sigcxx/autogen.sh:
$(CLONE) $(GITLAB)/mkxp-z/libsigcplusplus -b libsigc++-2-10 $(DOWNLOADS)/sigcxx
# uchardet
uchardet: init_dirs $(LIBDIR)/libuchardet.a
$(LIBDIR)/libuchardet.a: $(DOWNLOADS)/uchardet/cmakebuild/Makefile
cd $(DOWNLOADS)/uchardet/cmakebuild; \
make -j$(NPROC); make install
$(DOWNLOADS)/uchardet/cmakebuild/Makefile: $(DOWNLOADS)/uchardet/CMakeLists.txt
cd $(DOWNLOADS)/uchardet; \
mkdir cmakebuild; cd cmakebuild; \
$(CMAKE) -DBUILD_SHARED_LIBS=no
$(DOWNLOADS)/uchardet/CMakeLists.txt:
$(CLONE) $(GITHUB)/freedesktop/uchardet $(DOWNLOADS)/uchardet
# Pixman
pixman: init_dirs libpng $(LIBDIR)/libpixman-1.a
@ -310,5 +326,5 @@ clean-downloads:
clean-compiled:
-rm -rf build-$(SDK)-$(ARCH)
deps-core: libvorbis sigcxx pixman libpng libjpeg physfs sdl2 sdl2image sdlsound sdl2ttf openal openssl
deps-core: libvorbis sigcxx pixman libpng libjpeg physfs uchardet sdl2 sdl2image sdlsound sdl2ttf openal openssl
everything: deps-core ruby

View file

@ -101,6 +101,14 @@
3B10EE092568E96A00372D13 /* binding-mri.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B10EDF02568E96A00372D13 /* binding-mri.cpp */; };
3B10EE0B2568E96A00372D13 /* module_rpg.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B10EDF32568E96A00372D13 /* module_rpg.cpp */; };
3B10EE0C2568E96A00372D13 /* viewport-binding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B10EDF42568E96A00372D13 /* viewport-binding.cpp */; };
3B1BC0E1266F7C2600794D22 /* iniconfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B1BC0E0266F7C0C00794D22 /* iniconfig.cpp */; };
3B1BC0E2266F7C2700794D22 /* iniconfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B1BC0E0266F7C0C00794D22 /* iniconfig.cpp */; };
3B1BC0E3266F7C2700794D22 /* iniconfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B1BC0E0266F7C0C00794D22 /* iniconfig.cpp */; };
3B1BC0E4266F7C2800794D22 /* iniconfig.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B1BC0E0266F7C0C00794D22 /* iniconfig.cpp */; };
3B1BC0E8266F91E100794D22 /* libuchardet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1BC0E7266F91E100794D22 /* libuchardet.a */; };
3B1BC0EA266F91FE00794D22 /* libuchardet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1BC0E9266F91FE00794D22 /* libuchardet.a */; };
3B1BC0EC266F924B00794D22 /* libuchardet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1BC0EB266F924B00794D22 /* libuchardet.a */; };
3B1BC0ED266F924B00794D22 /* libuchardet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1BC0EB266F924B00794D22 /* libuchardet.a */; };
3B1C230725A142620075EF5D /* libruby.3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1C230625A142620075EF5D /* libruby.3.0.dylib */; };
3B1C230825A1426C0075EF5D /* libruby.3.0.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1C230625A142620075EF5D /* libruby.3.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
3B1C230B25A144A10075EF5D /* libruby.3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B1C230A25A144A10075EF5D /* libruby.3.0.dylib */; };
@ -917,6 +925,12 @@
3B10EDF32568E96A00372D13 /* module_rpg.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = module_rpg.cpp; sourceTree = "<group>"; };
3B10EDF42568E96A00372D13 /* viewport-binding.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "viewport-binding.cpp"; sourceTree = "<group>"; };
3B10EE1F2569348E00372D13 /* json5pp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = json5pp.hpp; sourceTree = "<group>"; };
3B1BC0DF266F7C0C00794D22 /* iniconfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = iniconfig.h; sourceTree = "<group>"; };
3B1BC0E0266F7C0C00794D22 /* iniconfig.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = iniconfig.cpp; sourceTree = "<group>"; };
3B1BC0E6266F8E8700794D22 /* dependencies.make */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; name = dependencies.make; path = Dependencies/dependencies.make; sourceTree = "<group>"; };
3B1BC0E7266F91E100794D22 /* libuchardet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libuchardet.a; path = "Dependencies/build-macosx-arm64/lib/libuchardet.a"; sourceTree = "<group>"; };
3B1BC0E9266F91FE00794D22 /* libuchardet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libuchardet.a; path = "Dependencies/build-macosx-x86_64/lib/libuchardet.a"; sourceTree = "<group>"; };
3B1BC0EB266F924B00794D22 /* libuchardet.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libuchardet.a; path = "Dependencies/build-macosx-x86_64/lib/libuchardet.a"; sourceTree = "<group>"; };
3B1C230625A142620075EF5D /* libruby.3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libruby.3.0.dylib; path = "Dependencies/build-macosx-arm64/lib/libruby.3.0.dylib"; sourceTree = "<group>"; };
3B1C230A25A144A10075EF5D /* libruby.3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libruby.3.0.dylib; path = "Dependencies/build-macosx-x86_64/lib/libruby.3.0.dylib"; sourceTree = "<group>"; };
3B1C230D25A144BF0075EF5D /* libruby.3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libruby.3.0.dylib; path = "Dependencies/build-macosx-universal/lib/libruby.3.0.dylib"; sourceTree = "<group>"; };
@ -1072,6 +1086,7 @@
3B1C23C725A19C600075EF5D /* libcrypto.a in Frameworks */,
3B1C23C825A19C600075EF5D /* libopenal.a in Frameworks */,
3B97F77725E6182100A569B5 /* libSDL2_sound.a in Frameworks */,
3B1BC0ED266F924B00794D22 /* libuchardet.a in Frameworks */,
3B1C23C925A19C600075EF5D /* libpixman-1.a in Frameworks */,
3B5E1F1225A881FB0086FFDC /* libGLESv2.dylib in Frameworks */,
3B1C23CA25A19C600075EF5D /* AppKit.framework in Frameworks */,
@ -1118,6 +1133,7 @@
files = (
3BC65D622584EED10063AFF1 /* libSDL2_image.a in Frameworks */,
3BC65D5A2584EED10063AFF1 /* libvorbis.a in Frameworks */,
3B1BC0E8266F91E100794D22 /* libuchardet.a in Frameworks */,
3B522DD2259BFF0B003301C4 /* libssl.a in Frameworks */,
3B5E1F0D25A881FB0086FFDC /* libEGL.dylib in Frameworks */,
3BC65D282584EDC60063AFF1 /* IOKit.framework in Frameworks */,
@ -1161,6 +1177,7 @@
files = (
3BC65E2C2584F4290063AFF1 /* libvorbisenc.a in Frameworks */,
3BC65E2D2584F4290063AFF1 /* libogg.a in Frameworks */,
3B1BC0EA266F91FE00794D22 /* libuchardet.a in Frameworks */,
3B522DCC259BFEE0003301C4 /* libssl.a in Frameworks */,
3B5E1F0B25A881FB0086FFDC /* libEGL.dylib in Frameworks */,
3BC65E222584F4290063AFF1 /* libSDL2_ttf.a in Frameworks */,
@ -1209,6 +1226,7 @@
3B522DD8259BFF2D003301C4 /* libcrypto.a in Frameworks */,
3B5A8445256A0F6300BAF2E5 /* libopenal.a in Frameworks */,
3B97F77625E6182100A569B5 /* libSDL2_sound.a in Frameworks */,
3B1BC0EC266F924B00794D22 /* libuchardet.a in Frameworks */,
3BE08107256879FE0006849F /* libpixman-1.a in Frameworks */,
3B5E1F1025A881FB0086FFDC /* libGLESv2.dylib in Frameworks */,
3B1C233025A16CB20075EF5D /* AppKit.framework in Frameworks */,
@ -1338,6 +1356,8 @@
3B10ED412568E95D00372D13 /* exception.h */,
3B10ED422568E95D00372D13 /* debugwriter.h */,
3B10EE1F2569348E00372D13 /* json5pp.hpp */,
3B1BC0DF266F7C0C00794D22 /* iniconfig.h */,
3B1BC0E0266F7C0C00794D22 /* iniconfig.cpp */,
3B5A842B2569E8BA00BAF2E5 /* mINI.h */,
);
path = util;
@ -1522,6 +1542,14 @@
path = ../binding;
sourceTree = "<group>";
};
3B1BC0E5266F8E2A00794D22 /* Makefiles */ = {
isa = PBXGroup;
children = (
3B1BC0E6266F8E8700794D22 /* dependencies.make */,
);
name = Makefiles;
sourceTree = "<group>";
};
3B1C231D25A15F8F0075EF5D /* mkxp */ = {
isa = PBXGroup;
children = (
@ -1638,6 +1666,7 @@
3BC65D492584EE690063AFF1 /* ARM64 */ = {
isa = PBXGroup;
children = (
3B1BC0E7266F91E100794D22 /* libuchardet.a */,
3BC65D4F2584EED10063AFF1 /* libfreetype.a */,
3BC65D512584EED10063AFF1 /* libogg.a */,
3BC65D562584EED10063AFF1 /* libopenal.a */,
@ -1666,6 +1695,7 @@
children = (
3B5E1EF425A880D50086FFDC /* OpenGL ES */,
3BC65D7D2584F3780063AFF1 /* libfreetype.a */,
3B1BC0E9266F91FE00794D22 /* libuchardet.a */,
3B522DA1259BAA13003301C4 /* libfluidsynth.dylib */,
3B1C230D25A144BF0075EF5D /* libruby.3.0.dylib */,
3BC65D822584F3780063AFF1 /* libogg.a */,
@ -1728,6 +1758,7 @@
3BDB22EB25644FBF00C4A63D = {
isa = PBXGroup;
children = (
3B1BC0E5266F8E2A00794D22 /* Makefiles */,
3BD2B7272565B343003DAD8A /* README.md */,
3BDB23E22564546E00C4A63D /* icon.icns */,
3BDB2409256470AE00C4A63D /* Player */,
@ -1787,6 +1818,7 @@
isa = PBXGroup;
children = (
3BE080FC256879FE0006849F /* libfreetype.a */,
3B1BC0EB266F924B00794D22 /* libuchardet.a */,
3B5A8444256A0F6300BAF2E5 /* libopenal.a */,
3BE080FD256879FE0006849F /* libogg.a */,
3BE081452568A5C60006849F /* libpng.a */,
@ -2107,6 +2139,7 @@
3B3F7D2D25B1A73A00EA5F1C /* SettingsMenuController.mm in Sources */,
3B1C23BF25A19C600075EF5D /* filesystemImplApple.mm in Sources */,
3B1C23C025A19C600075EF5D /* fake-api.cpp in Sources */,
3B1BC0E4266F7C2800794D22 /* iniconfig.cpp in Sources */,
3B1C23C125A19C600075EF5D /* sharedstate.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -2190,6 +2223,7 @@
3BC65D122584EDC60063AFF1 /* systemImplApple.mm in Sources */,
3BC65D132584EDC60063AFF1 /* graphics.cpp in Sources */,
3BC65D142584EDC60063AFF1 /* font.cpp in Sources */,
3B1BC0E3266F7C2700794D22 /* iniconfig.cpp in Sources */,
3BC65D172584EDC60063AFF1 /* filesystemImplApple.mm in Sources */,
3BC65D182584EDC60063AFF1 /* fake-api.cpp in Sources */,
3BC65D192584EDC60063AFF1 /* sharedstate.cpp in Sources */,
@ -2268,6 +2302,7 @@
3BC65DD32584F3AD0063AFF1 /* systemImplApple.mm in Sources */,
3BC65DD42584F3AD0063AFF1 /* graphics.cpp in Sources */,
3BC65DD52584F3AD0063AFF1 /* font.cpp in Sources */,
3B1BC0E1266F7C2600794D22 /* iniconfig.cpp in Sources */,
3BC65DD82584F3AD0063AFF1 /* filesystemImplApple.mm in Sources */,
3BC65DD92584F3AD0063AFF1 /* fake-api.cpp in Sources */,
3BC65DDA2584F3AD0063AFF1 /* sharedstate.cpp in Sources */,
@ -2346,6 +2381,7 @@
3B5A8464256A46B200BAF2E5 /* systemImplApple.mm in Sources */,
3B10EDC12568E95E00372D13 /* graphics.cpp in Sources */,
3B10EDC02568E95E00372D13 /* font.cpp in Sources */,
3B1BC0E2266F7C2700794D22 /* iniconfig.cpp in Sources */,
3B5A840D2569BE7C00BAF2E5 /* filesystemImplApple.mm in Sources */,
3B10EDB12568E95E00372D13 /* fake-api.cpp in Sources */,
3B10EDAC2568E95E00372D13 /* sharedstate.cpp in Sources */,
@ -3025,6 +3061,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Dependencies/Frameworks/ANGLE",
"$(PROJECT_DIR)/Dependencies/build-macosx-universal/lib",
"$(PROJECT_DIR)/Dependencies/build-macosx-x86_64/lib",
);
MARKETING_VERSION = 2.2.1;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
@ -3107,6 +3144,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Dependencies/Frameworks/ANGLE",
"$(PROJECT_DIR)/Dependencies/build-macosx-universal/lib",
"$(PROJECT_DIR)/Dependencies/build-macosx-x86_64/lib",
);
MARKETING_VERSION = 2.2.1;
MTL_ENABLE_DEBUG_INFO = NO;
@ -3310,6 +3348,7 @@
"$(DEPENDENCY_SEARCH_PATH)/include/ruby-$(MRI_VERSION)/$(BUILD_ARCH)-darwin",
"$(DEPENDENCY_SEARCH_PATH)/include/AL",
"$(DEPENDENCY_SEARCH_PATH)/include/openssl",
"$(DEPENDENCY_SEARCH_PATH)/include/uchardet",
"$(PROJECT_DIR)/Dependencies/Frameworks/ANGLE",
);
LIBRARY_SEARCH_PATHS = (
@ -3379,6 +3418,7 @@
"$(DEPENDENCY_SEARCH_PATH)/include/ruby-$(MRI_VERSION)/$(BUILD_ARCH)-darwin",
"$(DEPENDENCY_SEARCH_PATH)/include/AL",
"$(DEPENDENCY_SEARCH_PATH)/include/openssl",
"$(DEPENDENCY_SEARCH_PATH)/include/uchardet",
"$(PROJECT_DIR)/Dependencies/Frameworks/ANGLE",
);
LIBRARY_SEARCH_PATHS = (

View file

@ -20,8 +20,94 @@
#include "util/json5pp.hpp"
#include "util/mINI.h"
#include "util/iniconfig.h"
#if defined(MKXPZ_BUILD_XCODE) || defined(MKXPZ_INI_ENCODING)
#include <iconv.h>
#include <uchardet.h>
#include <errno.h>
#endif
namespace json = json5pp;
namespace ini = mINI;
/* http://stackoverflow.com/a/1031773 */
static bool validUtf8(const char *string)
{
const uint8_t *bytes = (uint8_t*) string;
while(*bytes)
{
if( (/* ASCII
* use bytes[0] <= 0x7F to allow ASCII control characters */
bytes[0] == 0x09 ||
bytes[0] == 0x0A ||
bytes[0] == 0x0D ||
(0x20 <= bytes[0] && bytes[0] <= 0x7E)
)
) {
bytes += 1;
continue;
}
if( (/* non-overlong 2-byte */
(0xC2 <= bytes[0] && bytes[0] <= 0xDF) &&
(0x80 <= bytes[1] && bytes[1] <= 0xBF)
)
) {
bytes += 2;
continue;
}
if( (/* excluding overlongs */
bytes[0] == 0xE0 &&
(0xA0 <= bytes[1] && bytes[1] <= 0xBF) &&
(0x80 <= bytes[2] && bytes[2] <= 0xBF)
) ||
(/* straight 3-byte */
((0xE1 <= bytes[0] && bytes[0] <= 0xEC) ||
bytes[0] == 0xEE ||
bytes[0] == 0xEF) &&
(0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
(0x80 <= bytes[2] && bytes[2] <= 0xBF)
) ||
(/* excluding surrogates */
bytes[0] == 0xED &&
(0x80 <= bytes[1] && bytes[1] <= 0x9F) &&
(0x80 <= bytes[2] && bytes[2] <= 0xBF)
)
) {
bytes += 3;
continue;
}
if( (/* planes 1-3 */
bytes[0] == 0xF0 &&
(0x90 <= bytes[1] && bytes[1] <= 0xBF) &&
(0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
(0x80 <= bytes[3] && bytes[3] <= 0xBF)
) ||
(/* planes 4-15 */
(0xF1 <= bytes[0] && bytes[0] <= 0xF3) &&
(0x80 <= bytes[1] && bytes[1] <= 0xBF) &&
(0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
(0x80 <= bytes[3] && bytes[3] <= 0xBF)
) ||
(/* plane 16 */
bytes[0] == 0xF4 &&
(0x80 <= bytes[1] && bytes[1] <= 0x8F) &&
(0x80 <= bytes[2] && bytes[2] <= 0xBF) &&
(0x80 <= bytes[3] && bytes[3] <= 0xBF)
)
) {
bytes += 4;
continue;
}
return false;
}
return true;
}
std::string prefPath(const char *org, const char *app) {
char *path = SDL_GetPrefPath(org, app);
@ -255,40 +341,82 @@ void Config::readGameINI() {
}
std::string iniFileName(execName + ".ini");
SDLRWStream iniFile(iniFileName.c_str(), "r");
if (mkxp_fs::fileExists(iniFileName.c_str())) {
ini::INIStructure iniStruct;
if (iniFile)
{
INIConfiguration ic;
if (ic.load(iniFile.stream()))
{
GUARD(game.title = ic.getStringProperty("Game", "Title"););
GUARD(game.scripts = ic.getStringProperty("Game", "Scripts"););
if (!ini::INIFile(iniFileName).read(iniStruct)) {
Debug() << "Failed to read INI file" << iniFileName;
}
else if (!iniStruct.has("Game")){
Debug() << "INI is missing [Game] section";
}
game.title = iniStruct["Game"]["Title"];
game.scripts = iniStruct["Game"]["Scripts"];
}
strReplace(game.scripts, '\\', '/');
if (game.title.empty()) {
Debug() << "INI is missing Game.Title property";
game.title = "mkxp-z";
Debug() << iniFileName + ": Could not find Game.Title";
}
if (game.scripts.empty())
Debug() << "INI is missing Game.Scripts property";
Debug() << iniFileName + ": Could not find Game.Scripts";
}
}
else
Debug() << "Could not read" << iniFileName;
if (dataPathOrg.empty()) {
bool convSuccess = false;
// Attempt to convert from other encodings to UTF-8
if (!validUtf8(game.title.c_str()))
{
#if defined(MKXPZ_BUILD_XCODE) || defined(MKXPZ_INI_ENCODING)
uchardet_t ud = uchardet_new();
uchardet_handle_data(ud, game.title.c_str(), game.title.length());
uchardet_data_end(ud);
const char *charset = uchardet_get_charset(ud);
Debug() << iniFileName << ": Assuming encoding is" << charset << "...";
iconv_t cd = iconv_open("UTF-8", charset);
uchardet_delete(ud);
size_t inLen = game.title.size();
size_t outLen = inLen * 4;
std::string buf(outLen, '\0');
char *inPtr = const_cast<char*>(game.title.c_str());
char *outPtr = const_cast<char*>(buf.c_str());
errno = 0;
size_t result = iconv(cd, &inPtr, &inLen, &outPtr, &outLen);
iconv_close(cd);
if (result != (size_t)-1 && errno == 0)
{
buf.resize(buf.size()-outLen);
game.title = buf;
convSuccess = true;
}
else {
Debug() << iniFileName << ": failed to convert game title to UTF-8";
}
#else
Debug() << iniFileName << ": Game title isn't valid UTF-8"
#endif
}
else
convSuccess = true;
if (game.title.empty() || !convSuccess)
game.title = "mkxp-z";
if (dataPathOrg.empty())
dataPathOrg = ".";
}
if (dataPathApp.empty()) {
if (dataPathApp.empty())
dataPathApp = game.title;
}
if (!dataPathApp.empty()) {
customDataPath = prefPath(dataPathOrg.c_str(), dataPathApp.c_str());
}
commonDataPath = prefPath(".", "mkxp-z");

114
src/util/iniconfig.cpp Normal file
View file

@ -0,0 +1,114 @@
#include "iniconfig.h"
#include <algorithm>
std::string toLowerCase(const std::string& str)
{
std::string lower = str;
std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
return lower;
}
std::string trim(const std::string& str, const std::string& chars = "\t\n\v\f\r ")
{
std::string trimmed = str;
trimmed.erase(trimmed.find_last_not_of(chars) + 1);
trimmed.erase(0, trimmed.find_first_not_of(chars));
return trimmed;
}
INIConfiguration::Section::Section (const std::string& sname) : m_Name (sname), m_PropertyMap()
{
}
bool INIConfiguration::Section::getStringProperty (const std::string& name, std::string& outPropStr) const
{
try
{
outPropStr = m_PropertyMap.at(toLowerCase(name)).m_Value;
return true;
}
catch (std::out_of_range& oorexcept)
{
return false;
}
}
bool INIConfiguration::load (std::istream& is)
{
if (!is.good())
{
return false;
}
std::string currSectionName;
std::string line;
std::getline (is, line);
while (!is.eof() && !is.bad())
{
if (line[0] == '[')
{
currSectionName = line.substr (1, line.find_last_of (']') - 1);
}
else if (line[0] != '#' && line.length() > 2)
{
int crloc = line.length() - 1;
if (crloc >= 0 && line[crloc] == '\r') //check for Windows-style newline
line.resize (crloc); //and correct
size_t equalsPos = line.find_first_of ("=");
if (equalsPos != std::string::npos)
{
std::string key = line.substr (0, equalsPos);
std::string val = line.substr (equalsPos + 1);
addProperty (currSectionName, key , val);
}
}
std::getline (is, line);
}
if (is.bad())
{
return false;
}
return true;
}
std::string INIConfiguration::getStringProperty(const std::string& sname, const std::string& name, const std::string& def) const
{
auto sectionIt = m_SectionMap.find(toLowerCase(sname));
if (sectionIt != m_SectionMap.end())
{
std::string prop;
if(sectionIt->second.getStringProperty(name, prop))
{
return prop;
}
}
return def;
}
void INIConfiguration::addProperty (const std::string& sname, const std::string& name, const std::string& val)
{
if (m_SectionMap.find (toLowerCase(sname)) == m_SectionMap.end())
{
m_SectionMap.emplace (toLowerCase(sname), Section (sname));
}
Section::Property p;
p.m_Name = trim(name);
p.m_Value = trim(val);
m_SectionMap.at (toLowerCase(sname)).m_PropertyMap[toLowerCase(p.m_Name)] = p;
}

46
src/util/iniconfig.h Normal file
View file

@ -0,0 +1,46 @@
#ifndef INICONFIG_H
#define INICONFIG_H
#include <iostream>
#include <map>
class INIConfiguration
{
class Section
{
friend class INIConfiguration;
struct Property
{
std::string m_Name;
std::string m_Value;
};
typedef std::map<std::string, Property> property_map;
public:
Section (const Section& s) = default;
Section (Section&& s) = default;
bool getStringProperty (const std::string& name, std::string& outPropStr) const;
private:
explicit Section (const std::string& name);
std::string m_Name;
property_map m_PropertyMap;
};
typedef std::map<std::string, Section> section_map;
public:
bool load (std::istream& inStream);
std::string getStringProperty(const std::string& sname, const std::string& name, const std::string& def = "") const;
protected:
void addProperty (const std::string& sname, const std::string& name, const std::string& val);
private:
section_map m_SectionMap;
};
#endif // INICONFIG_H