diff --git a/src/Layers/xrRender/ModelPool.cpp b/src/Layers/xrRender/ModelPool.cpp index 6bdbb7cc2b3..e6529d0fe9a 100644 --- a/src/Layers/xrRender/ModelPool.cpp +++ b/src/Layers/xrRender/ModelPool.cpp @@ -396,7 +396,7 @@ void CModelPool::Prefetch() for (auto I = sect.Data.cbegin(); I != sect.Data.cend(); ++I) { const CInifile::Item& item = *I; - dxRender_Visual* V = Create(item.first.c_str()); + dxRender_Visual* V = Create(item.name.c_str()); Delete(V, FALSE); } Logging(TRUE); diff --git a/src/Layers/xrRender/Texture.cpp b/src/Layers/xrRender/Texture.cpp index ca82db5525e..1692e1774e1 100644 --- a/src/Layers/xrRender/Texture.cpp +++ b/src/Layers/xrRender/Texture.cpp @@ -27,7 +27,7 @@ bool is_enough_address_space_available() { return true; } int get_texture_load_lod(LPCSTR fn) { - CInifile::Sect& sect = pSettings->r_section("reduce_lod_texture_list"); + const CInifile::Sect& sect = pSettings->r_section("reduce_lod_texture_list"); auto it_ = sect.Data.cbegin(); auto it_e_ = sect.Data.cend(); @@ -38,7 +38,7 @@ int get_texture_load_lod(LPCSTR fn) for (; it != it_e; ++it) { - if (strstr(fn, it->first.c_str())) + if (strstr(fn, it->name.c_str())) { if (psTextureLOD < 1) { diff --git a/src/Layers/xrRender/TextureDescrManager.cpp b/src/Layers/xrRender/TextureDescrManager.cpp index af96de9fac8..6f4b28bbaef 100644 --- a/src/Layers/xrRender/TextureDescrManager.cpp +++ b/src/Layers/xrRender/TextureDescrManager.cpp @@ -53,11 +53,11 @@ void CTextureDescrMngr::LoadLTX(pcstr initial, bool listTHM) const auto processAssociation = [&](const CInifile::Item& item) { if (listTHM) - Msg("\t\t%s = %s", item.first.c_str(), item.second.c_str()); + Msg("\t\t%s = %s", item.name.c_str(), item.value.c_str()); lock.Enter(); - texture_desc& desc = m_texture_details[item.first]; - cl_dt_scaler*& dts = m_detail_scalers[item.first]; + texture_desc& desc = m_texture_details[item.name]; + cl_dt_scaler*& dts = m_detail_scalers[item.name]; lock.Leave(); if (desc.m_assoc) @@ -68,19 +68,19 @@ void CTextureDescrMngr::LoadLTX(pcstr initial, bool listTHM) string_path T; float s; - const int res = sscanf(*item.second, "%[^,],%f", T, &s); - R_ASSERT4(res == 2, "Bad texture association", item.first.c_str(), fname); + const int res = sscanf(*item.value, "%[^,],%f", T, &s); + R_ASSERT4(res == 2, "Bad texture association", item.name.c_str(), fname); desc.m_assoc->detail_name = T; if (dts) dts->scale = s; else dts = xr_new(s); - if (strstr(item.second.c_str(), "usage[diffuse_or_bump]")) + if (strstr(item.value.c_str(), "usage[diffuse_or_bump]")) desc.m_assoc->usage.set(texture_assoc::flDiffuseDetail | texture_assoc::flBumpDetail); - else if (strstr(item.second.c_str(), "usage[bump]")) + else if (strstr(item.value.c_str(), "usage[bump]")) desc.m_assoc->usage.set(texture_assoc::flBumpDetail); - else if (strstr(item.second.c_str(), "usage[diffuse]")) + else if (strstr(item.value.c_str(), "usage[diffuse]")) desc.m_assoc->usage.set(texture_assoc::flDiffuseDetail); }; xr_parallel_for_each(data.Data, processAssociation); @@ -97,10 +97,10 @@ void CTextureDescrMngr::LoadLTX(pcstr initial, bool listTHM) const auto processSpecification = [&](const CInifile::Item& item) { if (listTHM) - Msg("\t\t%s = %s", item.first.c_str(), item.second.c_str()); + Msg("\t\t%s = %s", item.name.c_str(), item.value.c_str()); lock.Enter(); - texture_desc& desc = m_texture_details[item.first]; + texture_desc& desc = m_texture_details[item.name]; lock.Leave(); if (desc.m_spec) @@ -110,8 +110,8 @@ void CTextureDescrMngr::LoadLTX(pcstr initial, bool listTHM) string_path bmode; const int res = - sscanf(item.second.c_str(), "bump_mode[%[^]]], material[%f]", bmode, &desc.m_spec->m_material); - R_ASSERT4(res == 2, "Bad texture specification", item.first.c_str(), fname); + sscanf(item.value.c_str(), "bump_mode[%[^]]], material[%f]", bmode, &desc.m_spec->m_material); + R_ASSERT4(res == 2, "Bad texture specification", item.name.c_str(), fname); if ((bmode[0] == 'u') && (bmode[1] == 's') && (bmode[2] == 'e') && (bmode[3] == ':')) { // bump-map specified diff --git a/src/Layers/xrRenderDX11/dx11Texture.cpp b/src/Layers/xrRenderDX11/dx11Texture.cpp index cafed2f3e8d..63c8605dff3 100644 --- a/src/Layers/xrRenderDX11/dx11Texture.cpp +++ b/src/Layers/xrRenderDX11/dx11Texture.cpp @@ -17,7 +17,7 @@ void fix_texture_name(pstr fn) int get_texture_load_lod(LPCSTR fn) { - CInifile::Sect& sect = pSettings->r_section("reduce_lod_texture_list"); + const CInifile::Sect& sect = pSettings->r_section("reduce_lod_texture_list"); auto it_ = sect.Data.cbegin(); auto it_e_ = sect.Data.cend(); @@ -29,7 +29,7 @@ int get_texture_load_lod(LPCSTR fn) for (; it != it_e; ++it) { - if (strstr(fn, it->first.c_str())) + if (strstr(fn, it->name.c_str())) { if (psTextureLOD < 1) { diff --git a/src/Layers/xrRenderGL/glTexture.cpp b/src/Layers/xrRenderGL/glTexture.cpp index 6e9ec4cffa7..03306df7d70 100644 --- a/src/Layers/xrRenderGL/glTexture.cpp +++ b/src/Layers/xrRenderGL/glTexture.cpp @@ -21,11 +21,11 @@ void fix_texture_name(pstr fn) int get_texture_load_lod(LPCSTR fn) { - CInifile::Sect& sect = pSettings->r_section("reduce_lod_texture_list"); + const CInifile::Sect& sect = pSettings->r_section("reduce_lod_texture_list"); for (const auto& item : sect.Data) { - if (strstr(fn, item.first.c_str())) + if (strstr(fn, item.name.c_str())) { if (psTextureLOD < 1) return 0; diff --git a/src/utils/mp_configs_verifyer/configs_dump_verifyer.cpp b/src/utils/mp_configs_verifyer/configs_dump_verifyer.cpp index 5f099a925bc..b0193506a82 100644 --- a/src/utils/mp_configs_verifyer/configs_dump_verifyer.cpp +++ b/src/utils/mp_configs_verifyer/configs_dump_verifyer.cpp @@ -93,17 +93,17 @@ LPCSTR configs_verifyer::get_section_diff(CInifile::Sect* sect_ptr, CInifile& ac for (auto cit = sect_ptr->Data.cbegin(), ciet = sect_ptr->Data.cend(); cit != ciet; ++cit) { - shared_str const& tmp_value = cit->second; + shared_str const& tmp_value = cit->value; shared_str real_value; if (tmp_active_param) { - if (active_params.line_exist(sect_ptr->Name.c_str(), cit->first)) + if (active_params.line_exist(sect_ptr->Name.c_str(), cit->name)) { - real_value = active_params.r_string(sect_ptr->Name.c_str(), cit->first.c_str()); + real_value = active_params.r_string(sect_ptr->Name.c_str(), cit->name.c_str()); if (tmp_value != real_value) { pcstr tmp_key_str = nullptr; - STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->first.c_str()); + STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->name.c_str()); STRCONCAT(diff_str, tmp_key_str, " = ", tmp_value.c_str(), ",right = ", real_value.c_str()); strncpy_s(dst_diff, diff_str, sizeof(dst_diff) - 1); dst_diff[sizeof(dst_diff) - 1] = 0; @@ -112,18 +112,18 @@ LPCSTR configs_verifyer::get_section_diff(CInifile::Sect* sect_ptr, CInifile& ac continue; } } - if (!pSettings->line_exist(sect_ptr->Name, cit->first)) + if (!pSettings->line_exist(sect_ptr->Name, cit->name)) { - STRCONCAT(diff_str, "line ", sect_ptr->Name.c_str(), "::", cit->first.c_str(), " not found"); + STRCONCAT(diff_str, "line ", sect_ptr->Name.c_str(), "::", cit->name.c_str(), " not found"); strncpy_s(dst_diff, diff_str, sizeof(dst_diff) - 1); dst_diff[sizeof(dst_diff) - 1] = 0; return dst_diff; } - real_value = pSettings->r_string(sect_ptr->Name.c_str(), cit->first.c_str()); + real_value = pSettings->r_string(sect_ptr->Name.c_str(), cit->name.c_str()); if (tmp_value != real_value) { pcstr tmp_key_str = nullptr; - STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->first.c_str()); + STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->name.c_str()); STRCONCAT(diff_str, tmp_key_str, " = ", tmp_value.c_str(), ",right = ", real_value.c_str()); strncpy_s(dst_diff, diff_str, sizeof(dst_diff) - 1); dst_diff[sizeof(dst_diff) - 1] = 0; diff --git a/src/utils/mp_configs_verifyer/mp_config_sections.cpp b/src/utils/mp_configs_verifyer/mp_config_sections.cpp index 3ba947b917e..f6ba52692ae 100644 --- a/src/utils/mp_configs_verifyer/mp_config_sections.cpp +++ b/src/utils/mp_configs_verifyer/mp_config_sections.cpp @@ -39,9 +39,9 @@ bool mp_config_sections::dump_one(CMemoryWriter& dest) return false; R_ASSERT(pSettings->section_exist(m_current_dump_sect->c_str())); - CInifile::Sect& tmp_sect = pSettings->r_section(m_current_dump_sect->c_str()); + const CInifile::Sect& tmp_sect = pSettings->r_section(m_current_dump_sect->c_str()); - m_tmp_dumper.sections().push_back(&tmp_sect); + m_tmp_dumper.sections().push_back(const_cast(&tmp_sect)); m_tmp_dumper.save_as(dest); m_tmp_dumper.sections().pop_back(); ++m_current_dump_sect; diff --git a/src/utils/xrCompress/xrCompress.cpp b/src/utils/xrCompress/xrCompress.cpp index cf2cc38cdf2..f3bd79aa11e 100644 --- a/src/utils/xrCompress/xrCompress.cpp +++ b/src/utils/xrCompress/xrCompress.cpp @@ -320,7 +320,7 @@ void xrCompressor::OpenPack(LPCSTR tgt_folder, int num) W.w_string(buff); for (const auto& it : S.Data) { - xr_sprintf(buff, "%s = %s", it.first.c_str(), it.second.c_str()); + xr_sprintf(buff, "%s = %s", it.name.c_str(), it.value.c_str()); W.w_string(buff); } W.seek(0); @@ -470,15 +470,15 @@ bool xrCompressor::IsFolderAccepted(const CInifile& ltx, LPCSTR path, bool& recu const auto& ef_sect = ltx.r_section("exclude_folders"); for (const auto& it : ef_sect.Data) { - recurse = CInifile::isBool(it.second.c_str()); + recurse = CInifile::isBool(it.value.c_str()); if (recurse) { - if (path == strstr(path, it.first.c_str())) + if (path == strstr(path, it.name.c_str())) return false; } else { - if (0 == xr_strcmp(path, it.first.c_str())) + if (0 == xr_strcmp(path, it.name.c_str())) return false; } } @@ -501,11 +501,11 @@ void xrCompressor::ProcessLTX(CInifile& ltx) const CInifile::Sect& if_sect = ltx.r_section("include_folders"); for (const auto& it : if_sect.Data) { - const BOOL ifRecurse = CInifile::isBool(it.second.c_str()); + const BOOL ifRecurse = CInifile::isBool(it.value.c_str()); const u32 folder_mask = FS_ListFolders | (ifRecurse ? 0 : FS_RootOnly); string_path path; - const LPCSTR _path = 0 == xr_strcmp(it.first.c_str(), ".\\") ? "" : it.first.c_str(); + const LPCSTR _path = 0 == xr_strcmp(it.name.c_str(), ".\\") ? "" : it.name.c_str(); xr_strcpy(path, _path); const size_t path_len = xr_strlen(path); if ((0 != path_len) && (path[path_len - 1] != '\\')) @@ -556,7 +556,7 @@ void xrCompressor::ProcessLTX(CInifile& ltx) { const CInifile::Sect& if_sect = ltx.r_section("include_files"); for (const auto& it : if_sect.Data) - files_list->push_back(xr_strdup(it.first.c_str())); + files_list->push_back(xr_strdup(it.name.c_str())); } PerformWork(); diff --git a/src/xrCore/Animation/SkeletonMotions.cpp b/src/xrCore/Animation/SkeletonMotions.cpp index 4336edda9ef..93410481cac 100644 --- a/src/xrCore/Animation/SkeletonMotions.cpp +++ b/src/xrCore/Animation/SkeletonMotions.cpp @@ -52,13 +52,13 @@ void CPartition::load(IKinematics* V, LPCSTR model_name) for (; it != it_e; ++it) { const CInifile::Item& I = *it; - if (I.first == part_name) + if (I.name == part_name) { - P[i].Name = I.second; + P[i].Name = I.value; } else { - u32 bid = V->LL_BoneID(I.first.c_str()); + u32 bid = V->LL_BoneID(I.name.c_str()); P[i].bones.push_back(bid); } } diff --git a/src/xrCore/CMakeLists.txt b/src/xrCore/CMakeLists.txt index 4734307cec8..997eef95231 100644 --- a/src/xrCore/CMakeLists.txt +++ b/src/xrCore/CMakeLists.txt @@ -344,6 +344,14 @@ target_sources_grouped( os_clipboard.h ) +target_sources_grouped( + TARGET xrCore + NAME "Parsing" + FILES + ParsingUtils.cpp + ParsingUtils.hpp +) + target_sources_grouped( TARGET xrCore NAME "PCH" diff --git a/src/xrCore/ParsingUtils.cpp b/src/xrCore/ParsingUtils.cpp new file mode 100644 index 00000000000..f4cf39caa5b --- /dev/null +++ b/src/xrCore/ParsingUtils.cpp @@ -0,0 +1,95 @@ +#include "stdafx.h" + +#include "ParsingUtils.hpp" + +ParseIncludeResult ParseInclude(pstr string, pcstr& out_include_name) +{ + VERIFY(string); + + // Skip any whitespace characters + string = ParseAllSpaces(string); + + // Check for #include + static constexpr pcstr IncludeTag = "#include"; + if (std::strncmp(string, IncludeTag, 8) != 0) + return ParseIncludeResult::NoInclude; + + string += 8; + + // Skip any whitespace characters + string = ParseAllSpaces(string); + + // Check that after the tag there is a quote + if (*string != '\"') + return ParseIncludeResult::Error; + + // Mark the start of the include name + ++string; + out_include_name = string; + + string = ParseUntil(string, '\"'); + + // Check for unterminated or empty include name + if (*string == '\0' || out_include_name == string) + return ParseIncludeResult::Error; + + // Check for unreasonably long include names + const size_t size = string - out_include_name; + if (size > 1024) + return ParseIncludeResult::Error; + + // NOTE(Andre): Yes this might look scary but it's perfectly fine. Since the include name is already in the string + // we are parsing and its not used afterwards we simply replace the closing quote with a null byte and we have a + // valid c-string pointed to by 'out_include_name' and safe ourselves the need to copy the string. + *string = '\0'; + + return ParseIncludeResult::Success; +} + +pcstr ParseAllSpaces(pcstr string) +{ + VERIFY(string); + + while (*string != '\0' && std::isspace(*string)) + ++string; + + return string; +} + +pstr ParseAllSpaces(pstr string) { return const_cast(ParseAllSpaces(reinterpret_cast(string))); } + +pcstr ParseUntil(pcstr string, const char character) +{ + VERIFY(string); + + while (*string != '\0' && *string != character) + ++string; + + return string; +} + +pstr ParseUntil(pstr string, const char character) +{ + return const_cast(ParseUntil(reinterpret_cast(string), character)); +} + +void StringCopyLowercase(pstr destination, pcstr src, std::size_t size) +{ + VERIFY(destination); + VERIFY(src); + + for (std::size_t i = 0; *src != '\0' && i < size; ++i) + { + *destination = std::tolower(*src); + ++src; + ++destination; + } + + // Ensure the string is null-terminated + *destination = '\0'; +} + +void StringCopyLowercase(pstr destination, shared_str src, std::size_t size) +{ + StringCopyLowercase(destination, *src, size); +} diff --git a/src/xrCore/ParsingUtils.hpp b/src/xrCore/ParsingUtils.hpp new file mode 100644 index 00000000000..1d5bd451a24 --- /dev/null +++ b/src/xrCore/ParsingUtils.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include "xr_types.h" +#include "xrstring.h" + +enum class ParseIncludeResult +{ + Success, /// There is a valid #include and 'out_include_name' contains the filename + Error, /// There is a #include but there is some problem + NoInclude, /// There is no #include on this line +}; + +// Given a string of the form: '#include "filename"' we try to parse filename into 'out_include_name' +// Note that the file name is parsed inplace to avoid copying the string +ParseIncludeResult ParseInclude(pstr string, pcstr& out_include_name); + +// Starting from the beginning of the string skips all characters for which 'std::isspace' is 'true'. +// Returns the first position where 'std::isspace' is 'false'. +pcstr ParseAllSpaces(pcstr string); + +pstr ParseAllSpaces(pstr string); + +// Starting from the begging of the string skips all characters until 'character' is found +// or until the end of the string is reached. +// Returns the first position where 'character' is found or the end of string if 'character' is not found +pcstr ParseUntil(pcstr string, const char character); + +pstr ParseUntil(pstr string, const char character); + +// Copies 'size' characters from 'src' to 'destination' and converts it to lowercase +void StringCopyLowercase(pstr destination, pcstr src, std::size_t size); + +void StringCopyLowercase(pstr destination, shared_str src, std::size_t size); diff --git a/src/xrCore/XML/XMLDocument.cpp b/src/xrCore/XML/XMLDocument.cpp index 4a43a765672..9697347ab57 100644 --- a/src/xrCore/XML/XMLDocument.cpp +++ b/src/xrCore/XML/XMLDocument.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "XMLDocument.hpp" +#include "ParsingUtils.hpp" pcstr UI_PATH = UI_PATH_DEFAULT; pcstr UI_PATH_WITH_DELIMITER = UI_PATH_DEFAULT_WITH_DELIMITER; @@ -11,61 +12,6 @@ XMLDocument::~XMLDocument() { ClearInternal(); } void XMLDocument::ClearInternal() { m_Doc.Clear(); } -enum class ParseIncludeResult -{ - Success, /// There is a valid #include and 'out_include_name' returns the filename - Error, /// There is a #include but there is some problem - NoInclude, /// There is no #include on this line -}; - -// Given a string of the form: '#include "filename"' we return the filename in 'out_include_name' -ParseIncludeResult ParseInclude(pstr string, pcstr& out_include_name) -{ - // Skip any whitespace characters - while (*string != '\0' && std::isblank(*string)) - { - ++string; - } - - // Check for #include - static constexpr pcstr IncludeTag = "#include"; - if (std::strncmp(string, IncludeTag, 8) != 0) - return ParseIncludeResult::NoInclude; - - string += 8; - - // Skip any whitespace characters - while (*string != '\0' && std::isblank(*string)) - ++string; - - // Check that after the tag there is a quote - if (*string != '\"') - return ParseIncludeResult::Error; - - // Mark the start of the include name - ++string; - out_include_name = string; - - while (*string != '\0' && *string != '\"') - ++string; - - // Check for unterminated or empty include name - if (*string == '\0' || out_include_name == string) - return ParseIncludeResult::Error; - - // Check for unreasonably long include names - const size_t size = string - out_include_name; - if (size > 1024) - return ParseIncludeResult::Error; - - // NOTE(Andre): Yes this might look scary but it's perfectly fine. Since the include name is already in the string - // we are parsing and its not used afterwards we simply replace the closing quote with a null byte and we have a - // valid c-string pointed to by 'out_include_name' and safe ourselves the need to copy the string. - *string = '\0'; - - return ParseIncludeResult::Success; -} - void ParseFile(pcstr path, CMemoryWriter& W, IReader* F, XMLDocument* xml, bool fatal, u8 include_depth) { // Prevent stack overflow due to recursive or cyclic includes diff --git a/src/xrCore/xrCore.vcxproj b/src/xrCore/xrCore.vcxproj index a8f7dd0af87..0576b909441 100644 --- a/src/xrCore/xrCore.vcxproj +++ b/src/xrCore/xrCore.vcxproj @@ -80,6 +80,7 @@ call .GitInfo.cmd + @@ -184,6 +185,7 @@ call .GitInfo.cmd + diff --git a/src/xrCore/xrCore.vcxproj.filters b/src/xrCore/xrCore.vcxproj.filters index 45d2a51cf57..25a414e6d10 100644 --- a/src/xrCore/xrCore.vcxproj.filters +++ b/src/xrCore/xrCore.vcxproj.filters @@ -118,6 +118,9 @@ {14c94737-f2c7-482d-9033-775a3da068cb} + + {3116121d-205f-4de2-be5a-da1dbf9919e7} + @@ -327,6 +330,9 @@ Math + + Parsing + @@ -704,6 +710,9 @@ Threading + + Parsing + diff --git a/src/xrCore/xr_ini.cpp b/src/xrCore/xr_ini.cpp index 263959f5099..ee97c083aa4 100644 --- a/src/xrCore/xr_ini.cpp +++ b/src/xrCore/xr_ini.cpp @@ -1,16 +1,19 @@ #include "stdafx.h" #include "FileSystem.h" +#include "ParsingUtils.hpp" #include "xrCore/xr_token.h" XRCORE_API CInifile const* pSettings = nullptr; XRCORE_API CInifile const* pSettingsAuth = nullptr; XRCORE_API CInifile const* pSettingsOpenXRay = nullptr; +XRCORE_API bool ltx_multiline_values_enabled = true; + #if defined(XR_PLATFORM_LINUX) || defined(XR_PLATFORM_BSD) || defined(XR_PLATFORM_APPLE) -#include -#define MSVCRT_EINVAL 22 -#define MSVCRT_ERANGE 34 +#include +#define MSVCRT_EINVAL 22 +#define MSVCRT_ERANGE 34 #define MSVCRT_UI64_MAX (((uint64_t)0xffffffff << 32) | 0xffffffff) @@ -233,7 +236,6 @@ uint64_t _cdecl _strtoui64(const char *nptr, char **endptr, int base) } #endif - CInifile* CInifile::Create(pcstr fileName, bool readOnly) { return xr_new(fileName, readOnly); @@ -241,44 +243,55 @@ CInifile* CInifile::Create(pcstr fileName, bool readOnly) void CInifile::Destroy(CInifile* ini) { xr_delete(ini); } +bool CInifile::isBool(pcstr str) +{ + VERIFY(str); + + return xr_strcmp(str, "on") == 0 || xr_strcmp(str, "yes") == 0 || xr_strcmp(str, "true") == 0 || + xr_strcmp(str, "1") == 0; +} + bool sect_pred(const CInifile::Sect* x, pcstr val) { + VERIFY(x); + return xr_strcmp(*x->Name, val) < 0; } bool item_pred(const CInifile::Item& x, pcstr val) { - if (!x.first || !val) - return x.first < val; - return xr_strcmp(*x.first, val) < 0; + if (!x.name || !val) + return x.name < val; + + return xr_strcmp(*x.name, val) < 0; } XRCORE_API bool _parse(pstr dest, pcstr src) { + VERIFY(dest); + VERIFY(src); + bool bInsideSTR = false; - if (src) + + while (*src) { - while (*src) + if (std::isspace(*src)) { - if (isspace((u8)*src)) + if (bInsideSTR) { - if (bInsideSTR) - { - *dest++ = *src++; - continue; - } - - while (*src && isspace(*src)) - ++src; - + *dest++ = *src++; continue; } - if (*src == '"') - bInsideSTR = !bInsideSTR; + src = ParseAllSpaces(src); - *dest++ = *src++; + continue; } + + if (*src == '"') + bInsideSTR = !bInsideSTR; + + *dest++ = *src++; } *dest = 0; return bInsideSTR; @@ -286,345 +299,551 @@ XRCORE_API bool _parse(pstr dest, pcstr src) XRCORE_API void _decorate(pstr dest, pcstr src) { - if (src) + VERIFY(dest); + VERIFY(src); + + bool bInsideSTR = false; + while (*src) { - bool bInsideSTR = false; - while (*src) + if (*src == ',') { - if (*src == ',') + if (bInsideSTR) + *dest++ = *src++; + else { - if (bInsideSTR) - *dest++ = *src++; - else - { - *dest++ = *src++; - *dest++ = ' '; - } - - continue; + *dest++ = *src++; + *dest++ = ' '; } - if (*src == '"') - bInsideSTR = !bInsideSTR; - *dest++ = *src++; + continue; } + if (*src == '"') + bInsideSTR = !bInsideSTR; + + *dest++ = *src++; } *dest = 0; } + //------------------------------------------------------------------------------ -bool CInifile::Sect::line_exist(pcstr line, pcstr* value) +bool CInifile::Sect::line_exist(pcstr line_name, pcstr* value) { - auto A = std::lower_bound(Data.begin(), Data.end(), line, item_pred); - if (A != Data.end() && xr_strcmp(*A->first, line) == 0) + VERIFY(line_name); + VERIFY(value); + + auto iterator = std::lower_bound(Data.begin(), Data.end(), line_name, item_pred); + if (iterator != Data.end() && xr_strcmp(*iterator->name, line_name) == 0) { if (value) - *value = *A->second; + *value = *iterator->value; + return true; } + return false; } + //------------------------------------------------------------------------------ -CInifile::CInifile(IReader* F, pcstr path, allow_include_func_t allow_include_func) +CInifile::CInifile(IReader* reader, pcstr path, allow_include_func_t allow_include_func) { m_file_name[0] = 0; m_flags.zero(); m_flags.set(eSaveAtEnd, false); m_flags.set(eReadOnly, true); m_flags.set(eOverrideNames, false); - Load(F, path, allow_include_func); + + Load(reader, path, allow_include_func, 0); } -CInifile::CInifile(pcstr fileName, bool readOnly, bool loadAtStart, bool saveAtEnd, u32 sect_count, allow_include_func_t allow_include_func) +CInifile::CInifile(pcstr fileName, bool readOnly, bool loadAtStart, bool saveAtEnd, u32 sect_count, + allow_include_func_t allow_include_func) { if (fileName && strstr(fileName, "system")) Msg("-----loading %s", fileName); - m_file_name[0] = 0; - m_flags.zero(); if (fileName) - xr_strcpy(m_file_name, sizeof m_file_name, fileName); + xr_strcpy(m_file_name, sizeof(m_file_name), fileName); + else + m_file_name[0] = 0; + m_flags.zero(); m_flags.set(eSaveAtEnd, saveAtEnd); m_flags.set(eReadOnly, readOnly); - if (loadAtStart) + if (!loadAtStart) + return; + + IReader* reader = FS.r_open(fileName); + if (!reader) { - IReader* R = FS.r_open(fileName); - if (R) - { - const xr_string path = EFS_Utils::ExtractFilePath(m_file_name); - if (sect_count) - DATA.reserve(sect_count); - Load(R, path.c_str(), allow_include_func); - FS.r_close(R); - } + Msg("! Ini File: Can't open file: '%s'", fileName); + return; } + + const xr_string path = EFS_Utils::ExtractFilePath(m_file_name); + DATA.reserve(sect_count); + + Load(reader, path.c_str(), allow_include_func, 0); + FS.r_close(reader); } CInifile::~CInifile() { if (!m_flags.test(eReadOnly) && m_flags.test(eSaveAtEnd) && !save_as()) - Log("!Can't save inifile:", m_file_name); + Log("! Ini File[%s]: Can't save file:", m_file_name); for (auto* val : DATA) - { xr_delete(val); - } } -static void insert_item(CInifile::Sect* tgt, const CInifile::Item& I) +void insert_item(CInifile::Sect* target, const CInifile::Item& item) { - auto sect_it = std::lower_bound(tgt->Data.begin(), tgt->Data.end(), *I.first, item_pred); - if (sect_it != tgt->Data.end() && sect_it->first.equal(I.first)) - { - sect_it->second = I.second; - //#ifdef DEBUG - // sect_it->comment= I.comment; - //#endif - } + VERIFY(target); + + auto sect_it = std::lower_bound(target->Data.begin(), target->Data.end(), *item.name, item_pred); + if (sect_it != target->Data.end() && sect_it->name.equal(item.name)) + sect_it->value = item.value; else - tgt->Data.insert(sect_it, I); + target->Data.emplace(sect_it, std::move(item)); } -IC bool is_empty_line_now(IReader* F) +void CInifile::Load(IReader* reader, pcstr path, allow_include_func_t allow_include_func, u8 include_depth) { - char* a0 = (char*)F->pointer() - 4; - char* a1 = (char*)F->pointer() - 3; - char* a2 = (char*)F->pointer() - 2; - char* a3 = (char*)F->pointer() - 1; + VERIFY(reader); - return *a0 == 13 && *a1 == 10 && *a2 == 13 && *a3 == 10; -}; + if (include_depth >= 128) + { + Msg("! Ini File[%s]: parsing failed. Maximum include depth reached (> 128)", path); + return; + } -void CInifile::Load(IReader* F, pcstr path, allow_include_func_t allow_include_func) -{ - R_ASSERT(F); Sect* Current = nullptr; - string4096 str; - string4096 str2; - - bool bInsideSTR = false; - - while (!F->eof()) + while (!reader->eof()) { - F->r_string(str, sizeof str); - _Trim(str); - pstr comm = strchr(str, ';'); - pstr comm_1 = strchr(str, '/'); - - if (comm_1 && *(comm_1 + 1) == '/' && (!comm || (comm && comm_1 < comm))) + string4096 str; + if (!reader->try_r_string(str, sizeof(str))) { - comm = comm_1; + xr_delete(Current); + Msg("! Ini File[%s]: parsing failed. Line is too long (>= 4096)", path); + return; } -#ifdef DEBUG - pstr comment = 0; -#endif - if (comm) + // Skip any leading whitespaces + pstr ptr = ParseAllSpaces(str); + + // Stop parsing if the line is empty + if (*ptr == '\0') + continue; + + // Stop parsing if the line is a comment + if (*ptr == ';' || (*ptr == '/' && ptr[1] == '/')) + continue; + + // Parse includes + pcstr include_name; + switch (ParseInclude(ptr, include_name)) { - //."bla-bla-bla;nah-nah-nah" - char quot = '"'; - bool in_quot = false; + case ParseIncludeResult::Success: + R_ASSERT(path && path[0]); - pcstr q1 = strchr(str, quot); - if (q1 && q1 < comm) - { - pcstr q2 = strchr(++q1, quot); - if (q2 && q2 > comm) - in_quot = true; - } + string_path file_path; + strconcat(sizeof(file_path), file_path, path, include_name); - if (!in_quot) + if (!allow_include_func || allow_include_func(file_path)) { - *comm = 0; -#ifdef DEBUG - comment = comm + 1; + IReader* I = FS.r_open(file_path); +#ifndef XR_PLATFORM_WINDOWS // XXX: replace with runtime check for case-sensitivity + if (I == nullptr) + { + xr_fs_nostrlwr(const_cast(include_name)); + strconcat(file_path, path, include_name); + I = FS.r_open(file_path); + } #endif + if (!I) + { + xr_delete(Current); + Msg("! Ini File[%s]: Can't open include file: '%s', file path: '%s'", path, include_name, file_path); + return; + } + + const xr_string include_path = EFS_Utils::ExtractFilePath(file_path); + Load(I, include_path.c_str(), allow_include_func, include_depth + 1); + FS.r_close(I); } + continue; + + case ParseIncludeResult::NoInclude: + // Continue parsing further down + break; + + case ParseIncludeResult::Error: + xr_delete(Current); + Msg("! Ini File[%s]: invalid include directive: '%s'", path, str); + return; } - if (str[0] && str[0] == '#' && strstr(str, "#include")) // handle includes + // Parse new section + if (*ptr == '[') { - string_path inc_name; - R_ASSERT(path && path[0]); - if (_GetItem(str, 1, inc_name, '"')) + ++ptr; + + // insert previous filled section if theres one, if that fails just stop parsing + if (Current && !insert_new_section(Current)) + return; + + // Start a new section + Current = xr_new(); + VERIFY(Current); + + // Parse section name and convert it to lowercase + pcstr name = ptr; + while (*ptr != '\0') { - string_path fn; - strconcat(sizeof fn, fn, path, inc_name); - if (!allow_include_func || allow_include_func(fn)) + if (*ptr == ']') + break; + else { - IReader* I = FS.r_open(fn); -#ifndef XR_PLATFORM_WINDOWS // XXX: replace with runtime check for case-sensitivity - if (I == nullptr) - { - xr_fs_nostrlwr(inc_name); - strconcat(fn, path, inc_name); - I = FS.r_open(fn); - } -#endif - R_ASSERT3(I, "Can't find include file:", inc_name); - const xr_string inc_path = EFS_Utils::ExtractFilePath(fn); - Load(I, inc_path.c_str(), allow_include_func); - FS.r_close(I); + *ptr = std::tolower(*ptr); + ++ptr; } } - } - else if (str[0] && str[0] == '[') // new section ? - { - // insert previous filled section - if (Current) + + // Check for missing closing bracket + if (*ptr == '\0') { - // store previous section - auto I = std::lower_bound(DATA.begin(), DATA.end(), *Current->Name, sect_pred); - if (I != DATA.end() && (*I)->Name == Current->Name) - xrDebug::Fatal(DEBUG_INFO, "Duplicate section '%s' found.", *Current->Name); - DATA.insert(I, Current); + xr_delete(Current); + Msg("! Ini File[%s]: Bad ini section found. Missing closing bracket: '%s'", path, str); + return; } - Current = xr_new(); - Current->Name = nullptr; - // start new section - R_ASSERT3(strchr(str, ']'), "Bad ini section found: ", str); - pcstr inherited_names = strstr(str, "]:"); - if (nullptr != inherited_names) + + // Replace the closing bracket with a zero to correctly null terminate name + *ptr = '\0'; + ++ptr; + + Current->Name = name; + + // Skip any whitespace after the closing bracket + ptr = ParseAllSpaces(ptr); + + // Parse inherited sections + if (*ptr == ':') { VERIFY2(m_flags.test(eReadOnly), "Allow for readonly mode only."); - inherited_names += 2; - u32 cnt = _GetItemCount(inherited_names); + + ++ptr; + + // Skip any whitespace after the colon + ptr = ParseAllSpaces(ptr); + + static constexpr size_t max_inherited_sections = 128; + + pcstr inherited_section_name = ptr; + pcstr inherited_sections[max_inherited_sections]; + u32 count = 0; u32 total_count = 0; - u32 k = 0; - for (k = 0; k < cnt; ++k) + + auto add_inherited_section = [&]() -> bool { + // Just skip empty section names + if (*inherited_section_name == '\0') + return true; + + // Check that the inherited section exists + const Sect* inherited_section = try_read_section(inherited_section_name); + if (!inherited_section) + { + xr_delete(Current); + Msg("! Ini File[%s]: Bad inherited section not found: '%s'", path, inherited_section_name); + return false; + } + total_count += inherited_section->Data.size(); + + inherited_sections[count++] = inherited_section_name; + if (count >= max_inherited_sections) + { + xr_delete(Current); + Msg("! Ini File[%s]: Too many inherited sections (>= 128)", path); + return false; + } + + return true; + }; + + // Parse all inherited sections + while (*ptr != '\0') { - string512 tmp; - _GetItem(inherited_names, k, tmp); - Sect& inherited_section = r_section(tmp); - total_count += inherited_section.Data.size(); + // Commas separate different inherited sections + if (*ptr == ',') + { + *ptr = '\0'; + + if (!add_inherited_section()) + return; + + inherited_section_name = ParseAllSpaces(++ptr); + } + else if (std::isspace(*ptr)) + { + // Replace space characters with nulls to ensure that the string ends at the first non-space + // character + *ptr = '\0'; + ++ptr; + } + else if (*ptr == ';' || (*ptr == '/' && (ptr[1] == '/'))) + { + // Start of a comment so everything after this can be ignored + *ptr = '\0'; + break; + } + else + { + // Section names need to be converted to lowercase + *ptr = std::tolower(*ptr); + ++ptr; + } } - Current->Data.reserve(Current->Data.size() + total_count); + // Add the trailing inherited section + if (!add_inherited_section()) + return; + + // Reserve enough space for all inherited sections + Current->Data.reserve(total_count); - for (k = 0; k < cnt; ++k) + // Copy inherited sections to the new section + for (u32 i = 0; i < count; ++i) { - string512 tmp; - _GetItem(inherited_names, k, tmp); - Sect& inherited_section = r_section(tmp); + const Sect& inherited_section = unchecked_read_section(inherited_sections[i]); for (auto it = inherited_section.Data.begin(); it != inherited_section.Data.end(); ++it) insert_item(Current, *it); } } - *strchr(str, ']') = 0; - Current->Name = xr_strlwr(str + 1); } else // name = value { - if (Current) + if (!Current) + continue; + + pstr name = ptr; + pstr value = nullptr; + pstr last_non_space = ptr; + + // Parse name + while (*ptr != '\0') + { + if (*ptr == '=') + break; + else if (*ptr == ';' || (*ptr == '/' && ptr[1] == '/')) + { + // Start of a comment so everything after this can be ignored + *ptr = '\0'; + break; + } + else + { + if (!std::isspace(*ptr)) + last_non_space = ptr; + + ++ptr; + } + } + + // Ensure name is correctly null-terminated with trailing spaces + if (std::isspace(last_non_space[1])) + last_non_space[1] = '\0'; + + // Check for empty name + if (*name == '\0') + { + xr_delete(Current); + Msg("! Ini File[%s]: Bad ini item found. Missing name: '%s'", path, str); + return; + } + + // Parse value + if (*ptr == '=') { - string4096 value_raw; - char* name = str; - char* t = strchr(name, '='); - if (t) + // Replace equal sign with a zero to create a null terminated string in name + *ptr = '\0'; + ++ptr; + + ptr = ParseAllSpaces(ptr); + + // Parse actual value as string + value = ptr; + pstr value_write_ptr = ptr; + bool inside_quoted_value = false; + while (*ptr != '\0') { - *t = 0; - _Trim(name); - ++t; - xr_strcpy(value_raw, t); - bInsideSTR = _parse(str2, value_raw); - if (bInsideSTR) // multiline str value + if (inside_quoted_value) { - string4096 prevStr; - xr_strcpy(prevStr, str2); + if (*ptr == '"') + inside_quoted_value = false; + + *value_write_ptr = *ptr; - bool incorrectFormat = false; - const size_t prevPos = F->tell(); - while (bInsideSTR) + ++ptr; + ++value_write_ptr; + } + else + { + // In non quoted strings comments terminate our value + if (*ptr == ';' || (*ptr == '/' && ptr[1] == '/')) { - xr_strcat(value_raw, sizeof value_raw, "\r\n"); - string4096 str_add_raw; - F->r_string(str_add_raw, sizeof str_add_raw); + *value_write_ptr = '\0'; + break; + } + else if (*ptr == '"') + { + inside_quoted_value = true; - cpstr sectionNameTester = strchr(str_add_raw, '['); - if (sectionNameTester) - { - if (strchr(sectionNameTester, ']')) - { - // That's a new section name! This is 100% error! - incorrectFormat = true; - } - } + *value_write_ptr = *ptr; - if (!(xr_strlen(value_raw) + xr_strlen(str_add_raw) < sizeof value_raw) - || incorrectFormat) + ++ptr; + ++value_write_ptr; + } + else + { + if (!std::isspace(*ptr)) { - Msg("! Incorrect inifile format: section[%s], variable[%s]. Odd number of quotes " - "(\") found, but " - "should be even. Trimming it to the first new line.", - Current->Name.c_str(), name); - _Trim(prevStr, '\"'); - xr_strcpy(str2, prevStr); - F->seek(prevPos); - break; + *value_write_ptr = *ptr; + ++value_write_ptr; } - xr_strcat(value_raw, sizeof value_raw, str_add_raw); - bInsideSTR = _parse(str2, value_raw); - if (bInsideSTR) - { - if (is_empty_line_now(F)) - xr_strcat(value_raw, sizeof value_raw, "\r\n"); - } + ++ptr; } } } - else - { - _Trim(name); - str2[0] = 0; - } - Item I; - I.first = name[0] ? name : NULL; - I.second = str2[0] ? str2 : NULL; - //#ifdef DEBUG - // I.comment = m_flags.test(eReadOnly)?0:comment; - //#endif + // Ensure the value is correctly null terminated + if (value_write_ptr < ptr) + *value_write_ptr = '\0'; - if (m_flags.test(eReadOnly)) + + // Handle multiline strings + if (!ltx_multiline_values_enabled && inside_quoted_value) { - if (*I.first) - insert_item(Current, I); + // There is no closing quote and multiline values are disabled so for compatibility we need append a closing quote + if (ptr >= str + sizeof(str)) + { + // Not enough space to fit the closing quote + xr_delete(Current); + Msg("! Ini File[%s]: parsing failed. Line is too long", path); + return; + } + + // Append closing quote + ptr[0] = '"'; + ptr[1] = '\0'; + + Msg("~ Ini File[%s]: Multiline values are not supported assuming single line with missing closing quote. '%s'", path, value); } else { - if (*I.first || *I.second - //#ifdef DEBUG - // || *I.comment - //#endif - ) - insert_item(Current, I); + // Normal handling of multiline values + while (inside_quoted_value) + { + if (reader->eof()) + { + xr_delete(Current); + Msg("! Ini File[%s]: parsing failed. Unterminated multiline value", path); + return; + } + + // Check if theres enough space for '\r\n' + if (ptr + 2 > str + sizeof(str)) + { + xr_delete(Current); + Msg("! Ini File[%s]: parsing failed. Multiline string is too long", path); + return; + } + + // Append '\r\n' at the end + ptr[0] = '\r'; + ptr[1] = '\n'; + ptr += 2; + + const size_t size_left = sizeof(str) - (ptr - str); + if (!reader->try_r_string(ptr, size_left)) + { + xr_delete(Current); + Msg("! Ini File[%s]: parsing failed. Multiline string is too long", path); + return; + } + + // Check if this line contains the closing quote + ptr = ParseUntil(ptr, '"'); + if (*ptr == '"') + { + // Put null terminator after the closing quote + ptr[1] = '\0'; + inside_quoted_value = false; + } + } } } + + // Copy parsed name and value into item + Item item; + item.name = name; + item.value = (value && *value) ? value : nullptr; + + if (m_flags.test(eReadOnly)) + insert_item(Current, item); + else if (*item.value) + insert_item(Current, item); } } + if (Current) + insert_new_section(Current); +} + +bool CInifile::insert_new_section(Sect* section) +{ + VERIFY(section); + + auto iterator = std::lower_bound(DATA.begin(), DATA.end(), *section->Name, sect_pred); + if (iterator != DATA.end() && (*iterator)->Name == section->Name) { - auto I = std::lower_bound(DATA.begin(), DATA.end(), *Current->Name, sect_pred); - if (I != DATA.end() && (*I)->Name == Current->Name) - xrDebug::Fatal(DEBUG_INFO, "Duplicate section '%s' found.", *Current->Name); - DATA.insert(I, Current); + Msg("! Ini File[%s]: Duplicate section '%s' found.", m_file_name, *section->Name); + xr_delete(section); + return false; } + + DATA.insert(iterator, section); + + return true; +} + +CInifile::Sect& CInifile::unchecked_read_section(pcstr section) +{ + VERIFY(section); + + auto iterator = std::lower_bound(DATA.cbegin(), DATA.cend(), section, sect_pred); + VERIFY3(iterator != DATA.cend() && (*iterator)->Name == section, "Section not found", section); + + return **iterator; +} + +const CInifile::Sect& CInifile::unchecked_read_section(pcstr section) const +{ + return const_cast(this)->unchecked_read_section(section); } void CInifile::save_as(IWriter& writer, bool bcheck) const { - string4096 temp, val; + string4096 temp; + string4096 val; for (auto r_it = DATA.begin(); r_it != DATA.end(); ++r_it) { - xr_sprintf(temp, sizeof temp, "[%s]", (*r_it)->Name.c_str()); + xr_sprintf(temp, sizeof(temp), "[%s]", (*r_it)->Name.c_str()); writer.w_string(temp); if (bcheck) { - xr_sprintf(temp, sizeof temp, "; %d %d %d", (*r_it)->Name._get()->dwCRC, (*r_it)->Name._get()->dwReference, + xr_sprintf(temp, sizeof(temp), "; %d %d %d", (*r_it)->Name._get()->dwCRC, (*r_it)->Name._get()->dwReference, (*r_it)->Name._get()->dwLength); writer.w_string(temp); } @@ -632,30 +851,27 @@ void CInifile::save_as(IWriter& writer, bool bcheck) const for (auto s_it = (*r_it)->Data.begin(); s_it != (*r_it)->Data.end(); ++s_it) { const Item& I = *s_it; - if (*I.first) + VERIFY(*I.name); + + if (*I.value) { - if (*I.second) - { - _decorate(val, *I.second); - // only name and value - xr_sprintf(temp, sizeof temp, "%8s%-32s = %-32s", " ", I.first.c_str(), val); - } - else - { - // only name - xr_sprintf(temp, sizeof temp, "%8s%-32s = ", " ", I.first.c_str()); - } + _decorate(val, *I.value); + // only name and value + xr_sprintf(temp, sizeof(temp), "%-32s = %-32s", " ", I.name.c_str(), val); } else { - // no name, so no value - temp[0] = 0; + // only name + xr_sprintf(temp, sizeof(temp), "%-32s", " ", I.name.c_str()); } + _TrimRight(temp); + if (temp[0]) writer.w_string(temp); } - writer.w_string(" "); + + writer.w_string(""); } } @@ -663,62 +879,97 @@ bool CInifile::save_as(pcstr new_fname) { // save if needed if (new_fname && new_fname[0]) - xr_strcpy(m_file_name, sizeof m_file_name, new_fname); + xr_strcpy(m_file_name, sizeof(m_file_name), new_fname); R_ASSERT(m_file_name[0]); convert_path_separators(m_file_name); IWriter* F = FS.w_open_ex(m_file_name); if (!F) + { + Msg("! Ini File[%s]: Can't open file for saving '%s'", m_file_name, new_fname); return false; + } save_as(*F); FS.w_close(F); + return true; } -bool CInifile::section_exist(pcstr S) const +void CInifile::set_override_names(bool value) noexcept { m_flags.set(eOverrideNames, value); } + +void CInifile::save_at_end(bool value) noexcept { m_flags.set(eSaveAtEnd, value); } + +void CInifile::set_readonly(bool value) /*noexcept*/ { m_flags.set(eReadOnly, value); } + +bool CInifile::section_exist(pcstr section_name) const { - auto I = std::lower_bound(DATA.begin(), DATA.end(), S, sect_pred); - return I != DATA.end() && xr_strcmp(*(*I)->Name, S) == 0; + VERIFY(section_name); + + auto I = std::lower_bound(DATA.begin(), DATA.end(), section_name, sect_pred); + return I != DATA.end() && xr_strcmp(*(*I)->Name, section_name) == 0; } -bool CInifile::line_exist(pcstr S, pcstr L) const +pcstr CInifile::fname() const /*noexcept*/ { return m_file_name; }; + +bool CInifile::line_exist(pcstr section_name, pcstr line_name) const { - if (!section_exist(S)) + VERIFY(section_name); + VERIFY(line_name); + + if (!section_exist(section_name)) return false; - Sect& I = r_section(S); - auto A = std::lower_bound(I.Data.begin(), I.Data.end(), L, item_pred); - return A != I.Data.end() && xr_strcmp(*A->first, L) == 0; + + const Sect& section = r_section(section_name); + + auto iterator = std::lower_bound(section.Data.begin(), section.Data.end(), line_name, item_pred); + return iterator != section.Data.end() && xr_strcmp(*iterator->name, line_name) == 0; } -u32 CInifile::line_count(pcstr Sname) const +u32 CInifile::line_count(pcstr section_name) const { - Sect& S = r_section(Sname); - u32 C = 0; - for (const auto& item : S.Data) - if (*item.first) - C++; - return C; + VERIFY(section_name); + + const Sect& section = r_section(section_name); + return section.Data.size(); } u32 CInifile::section_count() const { return DATA.size(); } + +CInifile::Root& CInifile::sections() { return DATA; } + +const CInifile::Root& CInifile::sections() const { return DATA; } + //-------------------------------------------------------------------------------------- -CInifile::Sect& CInifile::r_section(const shared_str& S) const { return r_section(*S); } -bool CInifile::line_exist(const shared_str& S, const shared_str& L)const { return line_exist(*S, *L); } -u32 CInifile::line_count(const shared_str& S) const { return line_count(*S); } -bool CInifile::section_exist(const shared_str& S) const { return section_exist(*S); } + +CInifile::Sect& CInifile::r_section(const shared_str& section_name) { return r_section(*section_name); } + +const CInifile::Sect& CInifile::r_section(const shared_str& section_name) const { return r_section(*section_name); } + +bool CInifile::line_exist(const shared_str& section_name, const shared_str& line_name) const +{ + return line_exist(*section_name, *line_name); +} + +u32 CInifile::line_count(const shared_str& section_name) const { return line_count(*section_name); } + +bool CInifile::section_exist(const shared_str& section_name) const { return section_exist(*section_name); } + //-------------------------------------------------------------------------------------- // Read functions //-------------------------------------------------------------------------------------- -CInifile::Sect& CInifile::r_section(pcstr S) const + +CInifile::Sect& CInifile::r_section(pcstr section_name) { - char section[256]; - xr_strcpy(section, sizeof section, S); - xr_strlwr(section); - auto I = std::lower_bound(DATA.cbegin(), DATA.cend(), section, sect_pred); + VERIFY(section_name); + + string256 section_lower; + StringCopyLowercase(section_lower, section_name, sizeof(section_lower)); + + auto I = std::lower_bound(DATA.cbegin(), DATA.cend(), section_lower, sect_pred); if (I == DATA.cend()) - xrDebug::Fatal(DEBUG_INFO, "Can't find section '%s'.", S); - else if (xr_strcmp(*(*I)->Name, section)) + xrDebug::Fatal(DEBUG_INFO, "Ini File[%s]: Can't find section '%s'.", m_file_name, section_name); + else if (xr_strcmp(*(*I)->Name, section_lower)) { // g_pStringContainer->verify(); @@ -731,510 +982,643 @@ CInifile::Sect& CInifile::r_section(pcstr S) const // F->w_string ("shared strings:"); // g_pStringContainer->dump(F); // FS.w_close (F); - xrDebug::Fatal(DEBUG_INFO, "Can't open section '%s' (only '%s' avail). Please attach [*.ini_log] file to your bug report", section, *(*I)->Name); + xrDebug::Fatal(DEBUG_INFO, + "Can't open section '%s' (only '%s' avail). Please attach [*.ini_log] file to your bug report", + section_lower, *(*I)->Name); } return **I; } -pcstr CInifile::r_string(pcstr S, pcstr L) const +const CInifile::Sect& CInifile::r_section(pcstr section_name) const { - Sect const& I = r_section(S); - auto A = std::lower_bound(I.Data.cbegin(), I.Data.cend(), L, item_pred); + return const_cast(this)->r_section(section_name); +} - if (A != I.Data.cend() && xr_strcmp(*A->first, L) == 0) - return *A->second; +pcstr CInifile::r_string(pcstr section_name, pcstr line_name) const +{ + VERIFY(section_name); + VERIFY(line_name); - xrDebug::Fatal(DEBUG_INFO, "Can't find variable %s in [%s]", L, S); + const Sect& section = r_section(section_name); + auto iterator = std::lower_bound(section.Data.cbegin(), section.Data.cend(), line_name, item_pred); + + if (iterator != section.Data.cend() && xr_strcmp(*iterator->name, line_name) == 0) + return *iterator->value; + + xrDebug::Fatal(DEBUG_INFO, "Can't find variable '%s' in [%s]", line_name, section_name); return nullptr; } -shared_str CInifile::r_string_wb(pcstr S, pcstr L) const +pcstr CInifile::r_string(const shared_str& section_name, pcstr line_name) const +{ + return r_string(*section_name, line_name); +} + +shared_str CInifile::r_string_wb(pcstr section_name, pcstr line_name) const { - pcstr _base = r_string(S, L); + pcstr base = r_string(section_name, line_name); - if (_base == nullptr) + if (base == nullptr) return shared_str(nullptr); - string4096 _original; - xr_strcpy(_original, sizeof _original, _base); - u32 _len = xr_strlen(_original); - if (0 == _len) + string4096 original; + xr_strcpy(original, sizeof(original), base); + + const u32 length = xr_strlen(original); + if (length == 0) return shared_str(""); - if ('"' == _original[_len - 1]) - _original[_len - 1] = 0; // skip end - if ('"' == _original[0]) - return shared_str(&_original[0] + 1); // skip begin - return shared_str(_original); + + if (original[length - 1] == '"') + original[length - 1] = '\0'; // skip end + + if (original[0] == '"') + return shared_str(&original[0] + 1); // skip begin + + return shared_str(original); } -u8 CInifile::r_u8(pcstr S, pcstr L) const +shared_str CInifile::r_string_wb(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return u8(atoi(C)); + return r_string_wb(*section_name, line_name); } -u16 CInifile::r_u16(pcstr S, pcstr L) const +u8 CInifile::r_u8(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return u16(atoi(C)); + pcstr string = r_string(section_name, line_name); + return u8(atoi(string)); } -u32 CInifile::r_u32(pcstr S, pcstr L) const +u8 CInifile::r_u8(const shared_str& section_name, pcstr line_name) const { return r_u8(*section_name, line_name); } + +u16 CInifile::r_u16(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return u32(atoi(C)); + pcstr string = r_string(section_name, line_name); + return u16(atoi(string)); } -u64 CInifile::r_u64(pcstr S, pcstr L) const +u16 CInifile::r_u16(const shared_str& section_name, pcstr line_name) const { return r_u16(*section_name, line_name); } + +u32 CInifile::r_u32(pcstr section_name, pcstr line_name) const +{ + pcstr string = r_string(section_name, line_name); + return u32(atoi(string)); +} + +u32 CInifile::r_u32(const shared_str& section_name, pcstr line_name) const { return r_u32(*section_name, line_name); } + +u64 CInifile::r_u64(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); + pcstr string = r_string(section_name, line_name); #ifndef _EDITOR - return _strtoui64(C, nullptr, 10); + return _strtoui64(string, nullptr, 10); #else - return (u64)_atoi64(C); + return (u64)_atoi64(string); #endif } -s64 CInifile::r_s64(pcstr S, pcstr L) const +u64 CInifile::r_u64(const shared_str& section_name, pcstr line_name) const { return r_u64(*section_name, line_name); } + +s8 CInifile::r_s8(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return _atoi64(C); + pcstr string = r_string(section_name, line_name); + return s8(atoi(string)); } -s8 CInifile::r_s8(pcstr S, pcstr L) const +s8 CInifile::r_s8(const shared_str& section_name, pcstr line_name) const { return r_s8(*section_name, line_name); } + +s16 CInifile::r_s16(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return s8(atoi(C)); + pcstr string = r_string(section_name, line_name); + return s16(atoi(string)); } -s16 CInifile::r_s16(pcstr S, pcstr L) const +s16 CInifile::r_s16(const shared_str& section_name, pcstr line_name) const { return r_s16(*section_name, line_name); } + +s32 CInifile::r_s32(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return s16(atoi(C)); + pcstr string = r_string(section_name, line_name); + return s32(atoi(string)); } -s32 CInifile::r_s32(pcstr S, pcstr L) const +s32 CInifile::r_s32(const shared_str& section_name, pcstr line_name) const { return r_s32(*section_name, line_name); } + +s64 CInifile::r_s64(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return s32(atoi(C)); + pcstr string = r_string(section_name, line_name); + return _atoi64(string); } -float CInifile::r_float(pcstr S, pcstr L) const +s64 CInifile::r_s64(const shared_str& section_name, pcstr line_name) const { return r_s64(*section_name, line_name); } + +float CInifile::r_float(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return float(atof(C)); + pcstr string = r_string(section_name, line_name); + return float(atof(string)); } -Fcolor CInifile::r_fcolor(pcstr S, pcstr L) const +float CInifile::r_float(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); + return r_float(*section_name, line_name); +} + +Fcolor CInifile::r_fcolor(pcstr section_name, pcstr line_name) const +{ + pcstr string = r_string(section_name, line_name); Fcolor V = {0, 0, 0, 0}; - sscanf(C, "%f,%f,%f,%f", &V.r, &V.g, &V.b, &V.a); + sscanf(string, "%f,%f,%f,%f", &V.r, &V.g, &V.b, &V.a); return V; } -u32 CInifile::r_color(pcstr S, pcstr L) const +Fcolor CInifile::r_fcolor(const shared_str& section_name, pcstr line_name) const +{ + return r_fcolor(*section_name, line_name); +} + +u32 CInifile::r_color(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - u32 r = 0, g = 0, b = 0, a = 255; - sscanf(C, "%u,%u,%u,%u", &r, &g, &b, &a); + pcstr string = r_string(section_name, line_name); + u32 r = 0; + u32 g = 0; + u32 b = 0; + u32 a = 255; + sscanf(string, "%u,%u,%u,%u", &r, &g, &b, &a); return color_rgba(r, g, b, a); } -Ivector2 CInifile::r_ivector2(pcstr S, pcstr L) const +u32 CInifile::r_color(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - Ivector2 V = {0, 0}; - sscanf(C, "%d,%d", &V.x, &V.y); - return V; + return r_color(*section_name, line_name); } -Ivector3 CInifile::r_ivector3(pcstr S, pcstr L) const +Ivector2 CInifile::r_ivector2(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - Ivector V = {0, 0, 0}; - sscanf(C, "%d,%d,%d", &V.x, &V.y, &V.z); - return V; + pcstr string = r_string(section_name, line_name); + Ivector2 vector = {0, 0}; + sscanf(string, "%d,%d", &vector.x, &vector.y); + return vector; } -Ivector4 CInifile::r_ivector4(pcstr S, pcstr L) const +Ivector2 CInifile::r_ivector2(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - Ivector4 V = {0, 0, 0, 0}; - sscanf(C, "%d,%d,%d,%d", &V.x, &V.y, &V.z, &V.w); - return V; + return r_ivector2(*section_name, line_name); } -Fvector2 CInifile::r_fvector2(pcstr S, pcstr L) const +Ivector3 CInifile::r_ivector3(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - Fvector2 V = {0.f, 0.f}; - sscanf(C, "%f,%f", &V.x, &V.y); - return V; + pcstr string = r_string(section_name, line_name); + Ivector vector = {0, 0, 0}; + sscanf(string, "%d,%d,%d", &vector.x, &vector.y, &vector.z); + return vector; } -Fvector3 CInifile::r_fvector3(pcstr S, pcstr L) const +Ivector3 CInifile::r_ivector3(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - Fvector3 V = {0.f, 0.f, 0.f}; - sscanf(C, "%f,%f,%f", &V.x, &V.y, &V.z); - return V; + return r_ivector3(*section_name, line_name); } -Fvector4 CInifile::r_fvector4(pcstr S, pcstr L) const +Ivector4 CInifile::r_ivector4(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - Fvector4 V = {0.f, 0.f, 0.f, 0.f}; - sscanf(C, "%f,%f,%f,%f", &V.x, &V.y, &V.z, &V.w); - return V; + pcstr string = r_string(section_name, line_name); + Ivector4 vector = {0, 0, 0, 0}; + sscanf(string, "%d,%d,%d,%d", &vector.x, &vector.y, &vector.z, &vector.w); + return vector; +} + +Ivector4 CInifile::r_ivector4(const shared_str& section_name, pcstr line_name) const +{ + return r_ivector4(*section_name, line_name); +} + +Fvector2 CInifile::r_fvector2(pcstr section_name, pcstr line_name) const +{ + pcstr string = r_string(section_name, line_name); + Fvector2 vector = {0.f, 0.f}; + sscanf(string, "%f,%f", &vector.x, &vector.y); + return vector; +} + +Fvector2 CInifile::r_fvector2(const shared_str& section_name, pcstr line_name) const +{ + return r_fvector2(*section_name, line_name); +} + +Fvector3 CInifile::r_fvector3(pcstr section_name, pcstr line_name) const +{ + pcstr string = r_string(section_name, line_name); + Fvector3 vector = {0.f, 0.f, 0.f}; + sscanf(string, "%f,%f,%f", &vector.x, &vector.y, &vector.z); + return vector; +} + +Fvector3 CInifile::r_fvector3(const shared_str& section_name, pcstr line_name) const +{ + return r_fvector3(*section_name, line_name); +} + +Fvector4 CInifile::r_fvector4(pcstr section_name, pcstr line_name) const +{ + pcstr string = r_string(section_name, line_name); + Fvector4 vector = {0.f, 0.f, 0.f, 0.f}; + sscanf(string, "%f,%f,%f,%f", &vector.x, &vector.y, &vector.z, &vector.w); + return vector; +} + +Fvector4 CInifile::r_fvector4(const shared_str& section_name, pcstr line_name) const +{ + return r_fvector4(*section_name, line_name); +} + +bool CInifile::r_bool(pcstr section_name, pcstr line_name) const +{ + pcstr string = r_string(section_name, line_name); + VERIFY2(string && xr_strlen(string) <= 5, + make_string("! Ini File[%s]: \"%s\" is not a valid bool value, section[%s], line[%s]", m_file_name, string, section_name, line_name)); + + char buffer[8]; + StringCopyLowercase(buffer, string, sizeof(buffer) - 1); + buffer[sizeof(buffer) - 1] = 0; + + return isBool(buffer); } -bool CInifile::r_bool(pcstr S, pcstr L) const +bool CInifile::r_bool(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - VERIFY2(C && xr_strlen(C) <= 5, make_string("\"%s\" is not a valid bool value, section[%s], line[%s]", C, S, L)); - char B[8]; - xr_strcpy(B, 7, C); - B[7] = 0; - xr_strlwr(B); - return isBool(B); + return r_bool(*section_name, line_name); } -CLASS_ID CInifile::r_clsid(pcstr S, pcstr L) const +CLASS_ID CInifile::r_clsid(pcstr section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - return TEXT2CLSID(C); + pcstr string = r_string(section_name, line_name); + return TEXT2CLSID(string); } -int CInifile::r_token(pcstr S, pcstr L, const xr_token* token_list) const +CLASS_ID CInifile::r_clsid(const shared_str& section_name, pcstr line_name) const { - pcstr C = r_string(S, L); - for (int i = 0; token_list[i].name; i++) - if (!xr_stricmp(C, token_list[i].name)) + return r_clsid(*section_name, line_name); +} + +int CInifile::r_token(pcstr section_name, pcstr line_name, const xr_token* token_list) const +{ + pcstr string = r_string(section_name, line_name); + for (size_t i = 0; token_list[i].name; ++i) + if (!xr_stricmp(string, token_list[i].name)) return token_list[i].id; + return 0; } -bool CInifile::r_line(pcstr S, int L, pcstr* N, pcstr* V) const +bool CInifile::r_line(pcstr section_name, int line_number, pcstr* name_out, pcstr* value_out) const { - Sect& SS = r_section(S); - if (L >= (int)SS.Data.size() || L < 0) + const Sect& section = r_section(section_name); + if (line_number >= (int)section.Data.size() || line_number < 0) return false; - for (auto I = SS.Data.cbegin(); I != SS.Data.cend(); ++I) - if (!L--) + + for (auto I = section.Data.cbegin(); I != section.Data.cend(); ++I) + if (!line_number--) { - *N = *I->first; - *V = *I->second; + *name_out = *I->name; + *value_out = *I->value; return true; } + return false; } -bool CInifile::r_line(const shared_str& S, int L, pcstr* N, pcstr* V) const { return r_line(*S, L, N, V); } -//-------------------------------------------------------------------------------------------------------- +bool CInifile::r_line(const shared_str& section_name, int line_number, pcstr* name_out, pcstr* value_out) const +{ + return r_line(*section_name, line_number, name_out, value_out); +} + +//-------------------------------------------------------------------------------------- // Write functions //-------------------------------------------------------------------------------------- -void CInifile::w_string(pcstr S, pcstr L, pcstr V, pcstr comment) + +void CInifile::w_string(pcstr section_name, pcstr line_name, pcstr value, pcstr comment) { R_ASSERT(!m_flags.test(eReadOnly)); // section - string256 sect; - _parse(sect, S); - xr_strlwr(sect); + string256 section; + _parse(section, section_name); + xr_strlwr(section); - if (!section_exist(sect)) + if (!section_exist(section)) { // create _new_ section Sect* NEW = xr_new(); - NEW->Name = sect; - auto I = std::lower_bound(DATA.begin(), DATA.end(), sect, sect_pred); - DATA.insert(I, NEW); + NEW->Name = section; + auto I = std::lower_bound(DATA.begin(), DATA.end(), section, sect_pred); + DATA.emplace(I, std::move(NEW)); } // parse line/value string4096 line; - _parse(line, L); - string4096 value; - _parse(value, V); + _parse(line, line_name); + string4096 value_parsed; + _parse(value_parsed, value); // duplicate & insert - Item I; - Sect& data = r_section(sect); - I.first = line[0] ? line : 0; - I.second = value[0] ? value : 0; + Item item; + Sect& data = r_section(section); + item.name = line[0] ? line : 0; + item.value = value_parsed[0] ? value_parsed : 0; - //#ifdef DEBUG - // I.comment = (comment?comment:0); - //#endif - auto it = std::lower_bound(data.Data.begin(), data.Data.end(), *I.first, item_pred); + auto it = std::lower_bound(data.Data.begin(), data.Data.end(), *item.name, item_pred); if (it != data.Data.end()) { - // Check for "first" matching - if (0 == xr_strcmp(*it->first, *I.first)) + // Check for "name" matching + if (xr_strcmp(*it->name, *item.name) == 0) { - bool b = m_flags.test(eOverrideNames); - R_ASSERT2(b, make_string("name[%s] already exist in section[%s]", line, sect).c_str()); - *it = I; + R_ASSERT2(m_flags.test(eOverrideNames), + make_string("! Ini File[%s]: name[%s] already exist in section[%s]", m_file_name, line, section).c_str()); + *it = item; } else - data.Data.insert(it, I); + data.Data.emplace(it, std::move(item)); } else - data.Data.insert(it, I); + data.Data.emplace(it, std::move(item)); } -void CInifile::w_u8(pcstr S, pcstr L, u8 V, pcstr comment) +void CInifile::w_u8(pcstr section_name, pcstr line_name, u8 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d", V); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_u16(pcstr S, pcstr L, u16 V, pcstr comment) + +void CInifile::w_u16(pcstr section_name, pcstr line_name, u16 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d", V); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_u32(pcstr S, pcstr L, u32 V, pcstr comment) + +void CInifile::w_u32(pcstr section_name, pcstr line_name, u32 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d", V); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_u64(pcstr S, pcstr L, u64 V, pcstr comment) +void CInifile::w_u64(pcstr section_name, pcstr line_name, u64 value, pcstr comment) { string128 temp; #ifndef _EDITOR - _ui64toa_s(V, temp, sizeof temp, 10); + _ui64toa_s(value, temp, sizeof(temp), 10); #else _ui64toa(V, temp, 10); #endif - w_string(S, L, temp, comment); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_s64(pcstr S, pcstr L, s64 V, pcstr comment) +void CInifile::w_s8(pcstr section_name, pcstr line_name, s8 value, pcstr comment) { string128 temp; -#ifndef _EDITOR - _i64toa_s(V, temp, sizeof temp, 10); -#else - _i64toa(V, temp, 10); -#endif - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_s8(pcstr S, pcstr L, s8 V, pcstr comment) +void CInifile::w_s16(pcstr section_name, pcstr line_name, s16 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d", V); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_s16(pcstr S, pcstr L, s16 V, pcstr comment) + +void CInifile::w_s32(pcstr section_name, pcstr line_name, s32 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d", V); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_s32(pcstr S, pcstr L, s32 V, pcstr comment) + +void CInifile::w_s64(pcstr section_name, pcstr line_name, s64 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d", V); - w_string(S, L, temp, comment); +#ifndef _EDITOR + _i64toa_s(value, temp, sizeof(temp), 10); +#else + _i64toa(V, temp, 10); +#endif + w_string(section_name, line_name, temp, comment); } -void CInifile::w_float(pcstr S, pcstr L, float V, pcstr comment) + +void CInifile::w_float(pcstr section_name, pcstr line_name, float value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%f", V); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%f", value); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_fcolor(pcstr S, pcstr L, const Fcolor& V, pcstr comment) + +void CInifile::w_fcolor(pcstr section_name, pcstr line_name, const Fcolor& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%f,%f,%f,%f", V.r, V.g, V.b, V.a); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%f,%f,%f,%f", value.r, value.g, value.b, value.a); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_color(pcstr S, pcstr L, u32 V, pcstr comment) +void CInifile::w_color(pcstr section_name, pcstr line_name, u32 value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d,%d,%d,%d", color_get_R(V), color_get_G(V), color_get_B(V), color_get_A(V)); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d,%d,%d,%d", color_get_R(value), color_get_G(value), color_get_B(value), + color_get_A(value)); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_ivector2(pcstr S, pcstr L, const Ivector2& V, pcstr comment) +void CInifile::w_ivector2(pcstr section_name, pcstr line_name, const Ivector2& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d,%d", V.x, V.y); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d,%d", value.x, value.y); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_ivector3(pcstr S, pcstr L, const Ivector3& V, pcstr comment) +void CInifile::w_ivector3(pcstr section_name, pcstr line_name, const Ivector3& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d,%d,%d", V.x, V.y, V.z); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d,%d,%d", value.x, value.y, value.z); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_ivector4(pcstr S, pcstr L, const Ivector4& V, pcstr comment) +void CInifile::w_ivector4(pcstr section_name, pcstr line_name, const Ivector4& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%d,%d,%d,%d", V.x, V.y, V.z, V.w); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%d,%d,%d,%d", value.x, value.y, value.z, value.w); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_fvector2(pcstr S, pcstr L, const Fvector2& V, pcstr comment) +void CInifile::w_fvector2(pcstr section_name, pcstr line_name, const Fvector2& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%f,%f", V.x, V.y); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%f,%f", value.x, value.y); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_fvector3(pcstr S, pcstr L, const Fvector3& V, pcstr comment) +void CInifile::w_fvector3(pcstr section_name, pcstr line_name, const Fvector3& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%f,%f,%f", V.x, V.y, V.z); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%f,%f,%f", value.x, value.y, value.z); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_fvector4(pcstr S, pcstr L, const Fvector4& V, pcstr comment) +void CInifile::w_fvector4(pcstr section_name, pcstr line_name, const Fvector4& value, pcstr comment) { string128 temp; - xr_sprintf(temp, sizeof temp, "%f,%f,%f,%f", V.x, V.y, V.z, V.w); - w_string(S, L, temp, comment); + xr_sprintf(temp, sizeof(temp), "%f,%f,%f,%f", value.x, value.y, value.z, value.w); + w_string(section_name, line_name, temp, comment); } -void CInifile::w_bool(pcstr S, pcstr L, bool V, pcstr comment) { w_string(S, L, V ? "on" : "off", comment); } -void CInifile::remove_line(pcstr S, pcstr L) +void CInifile::w_bool(pcstr section_name, pcstr line_name, bool value, pcstr comment) +{ + w_string(section_name, line_name, value ? "on" : "off", comment); +} + +void CInifile::remove_line(pcstr section_name, pcstr line_name) { R_ASSERT(!m_flags.test(eReadOnly)); - if (line_exist(S, L)) + if (line_exist(section_name, line_name)) { - Sect& data = r_section(S); - auto A = std::lower_bound(data.Data.begin(), data.Data.end(), L, item_pred); - R_ASSERT(A != data.Data.end() && xr_strcmp(*A->first, L) == 0); - data.Data.erase(A); + Sect& data = r_section(section_name); + + auto iterator = std::lower_bound(data.Data.begin(), data.Data.end(), line_name, item_pred); + R_ASSERT(iterator != data.Data.end() && xr_strcmp(*iterator->name, line_name) == 0); + data.Data.erase(iterator); } } -void CInifile::set_readonly(bool b) +template<> +XRCORE_API pcstr CInifile::read(pcstr section_name, pcstr line_name) const { - m_flags.set(eReadOnly, b); + return r_string(section_name, line_name); } template<> -XRCORE_API pcstr CInifile::read(pcstr section, pcstr line) const +XRCORE_API u8 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_string(section, line); + return r_u8(section_name, line_name); } template<> -XRCORE_API u8 CInifile::read(pcstr section, pcstr line) const +XRCORE_API u16 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_u8(section, line); + return r_u16(section_name, line_name); } template<> -XRCORE_API u16 CInifile::read(pcstr section, pcstr line) const +XRCORE_API u32 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_u16(section, line); + return r_u32(section_name, line_name); } template<> -XRCORE_API u32 CInifile::read(pcstr section, pcstr line) const +XRCORE_API u64 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_u32(section, line); + return r_u64(section_name, line_name); } template<> -XRCORE_API s8 CInifile::read(pcstr section, pcstr line) const +XRCORE_API s8 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_s8(section, line); + return r_s8(section_name, line_name); } template<> -XRCORE_API s16 CInifile::read(pcstr section, pcstr line) const +XRCORE_API s16 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_s16(section, line); + return r_s16(section_name, line_name); } template<> -XRCORE_API s32 CInifile::read(pcstr section, pcstr line) const +XRCORE_API s32 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_s32(section, line); + return r_s32(section_name, line_name); } template<> -XRCORE_API s64 CInifile::read(pcstr section, pcstr line) const +XRCORE_API s64 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_s64(section, line); + return r_s64(section_name, line_name); } template<> -XRCORE_API float CInifile::read(pcstr section, pcstr line) const +XRCORE_API float CInifile::read(pcstr section_name, pcstr line_name) const { - return r_float(section, line); + return r_float(section_name, line_name); } template<> -XRCORE_API Fcolor CInifile::read(pcstr section, pcstr line) const +XRCORE_API Fcolor CInifile::read(pcstr section_name, pcstr line_name) const { - return r_fcolor(section, line); + return r_fcolor(section_name, line_name); } template<> -XRCORE_API Ivector2 CInifile::read(pcstr section, pcstr line) const +XRCORE_API Ivector2 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_ivector2(section, line); + return r_ivector2(section_name, line_name); } template<> -XRCORE_API Ivector3 CInifile::read(pcstr section, pcstr line) const +XRCORE_API Ivector3 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_ivector3(section, line); + return r_ivector3(section_name, line_name); } template<> -XRCORE_API Ivector4 CInifile::read(pcstr section, pcstr line) const +XRCORE_API Ivector4 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_ivector4(section, line); + return r_ivector4(section_name, line_name); } template<> -XRCORE_API bool CInifile::try_read(Ivector4& outValue, pcstr section, pcstr line) const +XRCORE_API bool CInifile::try_read(Ivector4& out_value, pcstr section_name, pcstr line_name) const { - pcstr C = r_string(section, line); - return 4 == sscanf(C, "%d,%d,%d,%d", &outValue.x, &outValue.y, &outValue.z, &outValue.w); + pcstr string = r_string(section_name, line_name); + return sscanf(string, "%d,%d,%d,%d", &out_value.x, &out_value.y, &out_value.z, &out_value.w) == 4; } template<> -XRCORE_API Fvector2 CInifile::read(pcstr section, pcstr line) const +XRCORE_API Fvector2 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_fvector2(section, line); + return r_fvector2(section_name, line_name); } template<> -XRCORE_API bool CInifile::try_read(Fvector2& outValue, pcstr section, pcstr line) const +XRCORE_API bool CInifile::try_read(Fvector2& out_value, pcstr section_name, pcstr line_name) const { - pcstr C = r_string(section, line); - return 2 == sscanf(C, "%f,%f", &outValue.x, &outValue.y); + pcstr string = r_string(section_name, line_name); + return sscanf(string, "%f,%f", &out_value.x, &out_value.y) == 2; } template<> -XRCORE_API Fvector3 CInifile::read(pcstr section, pcstr line) const +XRCORE_API Fvector3 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_fvector3(section, line); + return r_fvector3(section_name, line_name); } template<> -XRCORE_API Fvector4 CInifile::read(pcstr section, pcstr line) const +XRCORE_API Fvector4 CInifile::read(pcstr section_name, pcstr line_name) const { - return r_fvector4(section, line); + return r_fvector4(section_name, line_name); } template<> -XRCORE_API bool CInifile::read(pcstr section, pcstr line) const +XRCORE_API bool CInifile::read(pcstr section_name, pcstr line_name) const +{ + return r_bool(section_name, line_name); +} + +XRCORE_API CInifile::Sect* CInifile::try_read_section(pcstr section_name) +{ + auto I = std::lower_bound(DATA.cbegin(), DATA.cend(), section_name, sect_pred); + + if (I != DATA.cend() && xr_strcmp(*(*I)->Name, section_name) == 0) + return *I; + else + return nullptr; +} + +XRCORE_API const CInifile::Sect* CInifile::try_read_section(pcstr section_name) const { - return r_bool(section, line); + return const_cast(this)->try_read_section(section_name); } diff --git a/src/xrCore/xr_ini.h b/src/xrCore/xr_ini.h index 76add450d55..dead0cca088 100644 --- a/src/xrCore/xr_ini.h +++ b/src/xrCore/xr_ini.h @@ -15,7 +15,6 @@ constexpr pcstr OPENXRAY_INI_SECTION = "openxray"; // refs -class CInifile; struct xr_token; class IReader; @@ -24,17 +23,8 @@ class XRCORE_API CInifile public: struct XRCORE_API Item { - shared_str first; - shared_str second; - //#ifdef DEBUG - // shared_str comment; - //#endif - Item() - : first(nullptr), second(nullptr) - //#ifdef DEBUG - // , comment(0) - //#endif - {}; + shared_str name = nullptr; + shared_str value = nullptr; }; using Items = xr_vector; @@ -44,7 +34,7 @@ class XRCORE_API CInifile shared_str Name; Items Data; - bool line_exist(pcstr line, pcstr* value = nullptr); + [[nodiscard]] bool line_exist(pcstr line_name, pcstr* value = nullptr); }; using Root = xr_vector; @@ -53,10 +43,7 @@ class XRCORE_API CInifile static CInifile* Create(pcstr fileName, bool readOnly = true); static void Destroy(CInifile*); - static bool isBool(pcstr str) - { - return xr_strcmp(str, "on") == 0 || xr_strcmp(str, "yes") == 0 || xr_strcmp(str, "true") == 0 || xr_strcmp(str, "1") == 0; - } + static bool isBool(pcstr str); private: enum @@ -69,195 +56,235 @@ class XRCORE_API CInifile string_path m_file_name; Root DATA; - void Load(IReader* F, pcstr path, allow_include_func_t allow_include_func = nullptr); + void Load(IReader* reader, pcstr path, allow_include_func_t allow_include_func, u8 include_depth); + + bool insert_new_section(Sect* section); + + [[nodiscard]] Sect& unchecked_read_section(pcstr section_name); + [[nodiscard]] const Sect& unchecked_read_section(pcstr section_name) const; public: - CInifile(IReader* F, pcstr path = nullptr, allow_include_func_t allow_include_func = nullptr); + CInifile(IReader* reader, pcstr path = nullptr, allow_include_func_t allow_include_func = nullptr); CInifile(pcstr fileName, bool readOnly = true, bool loadAtStart = true, bool saveAtEnd = true, u32 sect_count = 0, allow_include_func_t allow_include_func = nullptr); virtual ~CInifile(); + bool save_as(pcstr new_fname = nullptr); void save_as(IWriter& writer, bool bcheck = false) const; - void set_override_names(bool b) noexcept { m_flags.set(eOverrideNames, b); } - void save_at_end(bool b) noexcept { m_flags.set(eSaveAtEnd, b); } - pcstr fname() const /*noexcept*/ { return m_file_name; }; - Sect& r_section(pcstr S) const; - Sect& r_section(const shared_str& S) const; - bool line_exist(pcstr S, pcstr L)const; - bool line_exist(const shared_str& S, const shared_str& L)const; - u32 line_count(pcstr S) const; - u32 line_count(const shared_str& S) const; - u32 section_count() const; - bool section_exist(pcstr S) const; - bool section_exist(const shared_str& S) const; - Root& sections() { return DATA; } - Root const& sections() const { return DATA; } + void set_override_names(bool value) noexcept; + void save_at_end(bool value) noexcept; + void set_readonly(bool value) /*noexcept*/; + + [[nodiscard]] Sect& r_section(pcstr section_name); + [[nodiscard]] const Sect& r_section(pcstr section_name) const; + [[nodiscard]] Sect& r_section(const shared_str& section_name); + [[nodiscard]] const Sect& r_section(const shared_str& section_name) const; + + [[nodiscard]] pcstr fname() const /*noexcept*/; + [[nodiscard]] bool line_exist(pcstr section_name, pcstr line_name) const; + [[nodiscard]] bool line_exist(const shared_str& section_name, const shared_str& line_name) const; + [[nodiscard]] u32 line_count(pcstr section_name) const; + [[nodiscard]] u32 line_count(const shared_str& section_name) const; + [[nodiscard]] u32 section_count() const; + [[nodiscard]] bool section_exist(pcstr section_name) const; + [[nodiscard]] bool section_exist(const shared_str& section_name) const; + [[nodiscard]] Root& sections(); + [[nodiscard]] const Root& sections() const; // Generic reading templated functions template - T read(pcstr section, pcstr line) const; + [[nodiscard]] T read(pcstr section_name, pcstr line_name) const; template - T read(const shared_str& section, pcstr line) const + [[nodiscard]] T read(const shared_str& section_name, pcstr line_name) const { - return read(section.c_str(), line); + VERIFY(line_name); + + return read(section_name.c_str(), line_name); } template - bool try_read(T& outValue, pcstr section, pcstr line) const; + bool try_read(T& out_value, pcstr section_name, pcstr line_name) const; template - bool try_read(T& outValue, const shared_str& section, pcstr line) const + bool try_read(T& out_value, const shared_str& section_name, pcstr line_name) const { - return try_read(outValue, section.c_str(), line); + VERIFY(line_name); + + return try_read(out_value, section_name.c_str(), line_name); } + [[nodiscard]] Sect* try_read_section(pcstr section_name); + [[nodiscard]] const Sect* try_read_section(pcstr section_name) const; + // Returns value if it exist, or returns default value template - T read_if_exists(pcstr section, pcstr line, T defaultValue) const + T read_if_exists(pcstr section_name, pcstr line_name, T default_value) const { - if (line_exist(section, line)) + VERIFY(section_name); + VERIFY(line_name); + + if (line_exist(section_name, line_name)) { - return read(section, line); + return read(section_name, line_name); } - return defaultValue; + + return default_value; } template - T read_if_exists(const shared_str& section, pcstr line, T defaultValue) const + T read_if_exists(const shared_str& section_name, pcstr line_name, T default_value) const { - return read_if_exists(section.c_str(), line, defaultValue); + return read_if_exists(section_name.c_str(), line_name, default_value); } // Returns true if value is exist and assigns it or returns false template - bool read_if_exists(T& outValue, pcstr section, pcstr line) const + bool read_if_exists(T& out_value, pcstr section_name, pcstr line_name) const { - if (line_exist(section, line)) + VERIFY(section_name); + VERIFY(line_name); + + if (line_exist(section_name, line_name)) { - outValue = read(section, line); + out_value = read(section_name, line_name); return true; } + return false; } template - bool read_if_exists(T& outValue, const shared_str& section, pcstr line) const + bool read_if_exists(T& out_value, const shared_str& section_name, pcstr line_name) const { - return read_if_exists(outValue, section.c_str(), line); + return read_if_exists(out_value, section_name.c_str(), line_name); } // Returns true if value or fallback value exist, crashes otherwise template - bool read_if_exists(T& outValue, pcstr section, pcstr line, pcstr line2, bool at_least_one = false) const + bool read_if_exists( + T& out_value, pcstr section_name, pcstr line_name, pcstr line2_name, bool at_least_one = false) const { - if (line_exist(section, line)) + VERIFY(section_name); + VERIFY(line_name); + VERIFY(line2_name); + + if (line_exist(section_name, line_name)) { - outValue = read(section, line); + out_value = read(section_name, line_name); return true; } - if (line_exist(section, line2)) + + if (line_exist(section_name, line2_name)) { - outValue = read(section, line2); + out_value = read(section_name, line2_name); return true; } + if (at_least_one) - outValue = read(section, line); // provoke crash + xrDebug::Fatal(DEBUG_INFO, "! Ini File[%s]: Can't find line '%s' or '%s' in section '%s'", m_file_name, line_name, line2_name, section_name); + return false; } template - bool read_if_exists(T& outValue, const shared_str& section, pcstr line, pcstr line2, bool at_least_one = false) const + bool read_if_exists(T& out_value, const shared_str& section_name, pcstr line_name, pcstr line2_name, + bool at_least_one = false) const { - return read_if_exists(outValue, section.c_str(), line, line2, at_least_one); + return read_if_exists(out_value, section_name.c_str(), line_name, line2_name, at_least_one); } template - bool try_read_if_exists(T& outValue, pcstr section, pcstr line) const + bool try_read_if_exists(T& out_value, pcstr section_name, pcstr line_name) const { - if (line_exist(section, line)) + VERIFY(section_name); + VERIFY(line_name); + + if (line_exist(section_name, line_name)) { - return try_read(outValue, section, line); + return try_read(out_value, section_name, line_name); } + return false; } template - bool try_read_if_exists(T& outValue, const shared_str& section, pcstr line) const + bool try_read_if_exists(T& out_value, const shared_str& section_name, pcstr line_name) const { - return try_read_if_exists(outValue, section.c_str(), line); + return try_read_if_exists(out_value, section_name.c_str(), line_name); } // Generic reading functions - CLASS_ID r_clsid(pcstr S, pcstr L) const; - CLASS_ID r_clsid(const shared_str& S, pcstr L) const { return r_clsid(*S, L); } - pcstr r_string(pcstr S, pcstr L) const; // Left quotes in place - pcstr r_string(const shared_str& S, pcstr L) const { return r_string(*S, L); } // Left quotes in place - shared_str r_string_wb(pcstr S, pcstr L) const; // Remove quotes - shared_str r_string_wb(const shared_str& S, pcstr L) const { return r_string_wb(*S, L); } // Remove quotes - u8 r_u8(pcstr S, pcstr L) const; - u8 r_u8(const shared_str& S, pcstr L) const { return r_u8(*S, L); } - u16 r_u16(pcstr S, pcstr L) const; - u16 r_u16(const shared_str& S, pcstr L) const { return r_u16(*S, L); } - u32 r_u32(pcstr S, pcstr L) const; - u32 r_u32(const shared_str& S, pcstr L) const { return r_u32(*S, L); } - u64 r_u64(pcstr S, pcstr L) const; - s8 r_s8(pcstr S, pcstr L) const; - s8 r_s8(const shared_str& S, pcstr L) const { return r_s8(*S, L); } - s16 r_s16(pcstr S, pcstr L) const; - s16 r_s16(const shared_str& S, pcstr L) const { return r_s16(*S, L); } - s32 r_s32(pcstr S, pcstr L) const; - s32 r_s32(const shared_str& S, pcstr L) const { return r_s32(*S, L); } - s64 r_s64(pcstr S, pcstr L) const; - float r_float(pcstr S, pcstr L) const; - float r_float(const shared_str& S, pcstr L) const { return r_float(*S, L); } - Fcolor r_fcolor(pcstr S, pcstr L) const; - Fcolor r_fcolor(const shared_str& S, pcstr L) const { return r_fcolor(*S, L); } - u32 r_color(pcstr S, pcstr L) const; - u32 r_color(const shared_str& S, pcstr L) const { return r_color(*S, L); } - Ivector2 r_ivector2(pcstr S, pcstr L) const; - Ivector2 r_ivector2(const shared_str& S, pcstr L) const { return r_ivector2(*S, L); } - Ivector3 r_ivector3(pcstr S, pcstr L) const; - Ivector3 r_ivector3(const shared_str& S, pcstr L) const { return r_ivector3(*S, L); } - Ivector4 r_ivector4(pcstr S, pcstr L) const; - Ivector4 r_ivector4(const shared_str& S, pcstr L) const { return r_ivector4(*S, L); } - Fvector2 r_fvector2(pcstr S, pcstr L) const; - Fvector2 r_fvector2(const shared_str& S, pcstr L) const { return r_fvector2(*S, L); } - Fvector3 r_fvector3(pcstr S, pcstr L) const; - Fvector3 r_fvector3(const shared_str& S, pcstr L) const { return r_fvector3(*S, L); } - Fvector4 r_fvector4(pcstr S, pcstr L) const; - Fvector4 r_fvector4(const shared_str& S, pcstr L) const { return r_fvector4(*S, L); } - bool r_bool(pcstr S, pcstr L) const; - bool r_bool(const shared_str& S, pcstr L) const { return r_bool(*S, L); } - int r_token(pcstr S, pcstr L, const xr_token* token_list) const; - bool r_line(pcstr S, int L, pcstr* N, pcstr* V) const; - bool r_line(const shared_str& S, int L, pcstr* N, pcstr* V) const; - - void w_string(pcstr S, pcstr L, pcstr V, pcstr comment = nullptr); - void w_u8(pcstr S, pcstr L, u8 V, pcstr comment = nullptr); - void w_u16(pcstr S, pcstr L, u16 V, pcstr comment = nullptr); - void w_u32(pcstr S, pcstr L, u32 V, pcstr comment = nullptr); - void w_u64(pcstr S, pcstr L, u64 V, pcstr comment = nullptr); - void w_s64(pcstr S, pcstr L, s64 V, pcstr comment = nullptr); - void w_s8(pcstr S, pcstr L, s8 V, pcstr comment = nullptr); - void w_s16(pcstr S, pcstr L, s16 V, pcstr comment = nullptr); - void w_s32(pcstr S, pcstr L, s32 V, pcstr comment = nullptr); - void w_float(pcstr S, pcstr L, float V, pcstr comment = nullptr); - void w_fcolor(pcstr S, pcstr L, const Fcolor& V, pcstr comment = nullptr); - void w_color(pcstr S, pcstr L, u32 V, pcstr comment = nullptr); - void w_ivector2(pcstr S, pcstr L, const Ivector2& V, pcstr comment = nullptr); - void w_ivector3(pcstr S, pcstr L, const Ivector3& V, pcstr comment = nullptr); - void w_ivector4(pcstr S, pcstr L, const Ivector4& V, pcstr comment = nullptr); - void w_fvector2(pcstr S, pcstr L, const Fvector2& V, pcstr comment = nullptr); - void w_fvector3(pcstr S, pcstr L, const Fvector3& V, pcstr comment = nullptr); - void w_fvector4(pcstr S, pcstr L, const Fvector4& V, pcstr comment = nullptr); - void w_bool(pcstr S, pcstr L, bool V, pcstr comment = nullptr); - - void remove_line(pcstr S, pcstr L); - void set_readonly(bool b); + [[nodiscard]] CLASS_ID r_clsid(pcstr section_name, pcstr line_name) const; + [[nodiscard]] CLASS_ID r_clsid(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] pcstr r_string(pcstr section_name, pcstr line_name) const; // Left quotes in place + [[nodiscard]] pcstr r_string(const shared_str& section_name, pcstr line_name) const; // Left quotes in place + [[nodiscard]] shared_str r_string_wb(pcstr section_name, pcstr line_name) const; // Remove quotes + [[nodiscard]] shared_str r_string_wb(const shared_str& section_name, pcstr line_name) const; // Remove quotes + [[nodiscard]] u8 r_u8(pcstr section_name, pcstr line_name) const; + [[nodiscard]] u8 r_u8(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] u16 r_u16(pcstr section_name, pcstr line_name) const; + [[nodiscard]] u16 r_u16(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] u32 r_u32(pcstr section_name, pcstr line_name) const; + [[nodiscard]] u32 r_u32(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] u64 r_u64(pcstr section_name, pcstr line_name) const; + [[nodiscard]] u64 r_u64(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] s8 r_s8(pcstr section_name, pcstr line_name) const; + [[nodiscard]] s8 r_s8(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] s16 r_s16(pcstr section_name, pcstr line_name) const; + [[nodiscard]] s16 r_s16(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] s32 r_s32(pcstr section_name, pcstr line_name) const; + [[nodiscard]] s32 r_s32(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] s64 r_s64(pcstr section_name, pcstr line_name) const; + [[nodiscard]] s64 r_s64(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] float r_float(pcstr section_name, pcstr line_name) const; + [[nodiscard]] float r_float(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Fcolor r_fcolor(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Fcolor r_fcolor(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] u32 r_color(pcstr section_name, pcstr line_name) const; + [[nodiscard]] u32 r_color(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Ivector2 r_ivector2(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Ivector2 r_ivector2(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Ivector3 r_ivector3(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Ivector3 r_ivector3(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Ivector4 r_ivector4(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Ivector4 r_ivector4(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Fvector2 r_fvector2(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Fvector2 r_fvector2(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Fvector3 r_fvector3(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Fvector3 r_fvector3(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] Fvector4 r_fvector4(pcstr section_name, pcstr line_name) const; + [[nodiscard]] Fvector4 r_fvector4(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] bool r_bool(pcstr section_name, pcstr line_name) const; + [[nodiscard]] bool r_bool(const shared_str& section_name, pcstr line_name) const; + [[nodiscard]] int r_token(pcstr section_name, pcstr line_name, const xr_token* token_list) const; + bool r_line(pcstr section_name, int line_number, pcstr* name_out, pcstr* value_out) const; + bool r_line(const shared_str& section_name, int line_number, pcstr* name_out, pcstr* value_out) const; + + void w_string(pcstr section_name, pcstr line_name, pcstr value, pcstr comment = nullptr); + void w_u8(pcstr section_name, pcstr line_name, u8 value, pcstr comment = nullptr); + void w_u16(pcstr section_name, pcstr line_name, u16 value, pcstr comment = nullptr); + void w_u32(pcstr section_name, pcstr line_name, u32 value, pcstr comment = nullptr); + void w_u64(pcstr section_name, pcstr line_name, u64 value, pcstr comment = nullptr); + void w_s8(pcstr section_name, pcstr line_name, s8 value, pcstr comment = nullptr); + void w_s16(pcstr section_name, pcstr line_name, s16 value, pcstr comment = nullptr); + void w_s32(pcstr section_name, pcstr line_name, s32 value, pcstr comment = nullptr); + void w_s64(pcstr section_name, pcstr line_name, s64 value, pcstr comment = nullptr); + void w_float(pcstr section_name, pcstr line_name, float value, pcstr comment = nullptr); + void w_fcolor(pcstr section_name, pcstr line_name, const Fcolor& value, pcstr comment = nullptr); + void w_color(pcstr section_name, pcstr line_name, u32 value, pcstr comment = nullptr); + void w_ivector2(pcstr section_name, pcstr line_name, const Ivector2& value, pcstr comment = nullptr); + void w_ivector3(pcstr section_name, pcstr line_name, const Ivector3& value, pcstr comment = nullptr); + void w_ivector4(pcstr section_name, pcstr line_name, const Ivector4& value, pcstr comment = nullptr); + void w_fvector2(pcstr section_name, pcstr line_name, const Fvector2& value, pcstr comment = nullptr); + void w_fvector3(pcstr section_name, pcstr line_name, const Fvector3& value, pcstr comment = nullptr); + void w_fvector4(pcstr section_name, pcstr line_name, const Fvector4& value, pcstr comment = nullptr); + void w_bool(pcstr section_name, pcstr line_name, bool value, pcstr comment = nullptr); + + void remove_line(pcstr section_name, pcstr line_name); }; #define READ_IF_EXISTS(ltx, method, section, name, default_value) \ @@ -268,4 +295,6 @@ extern XRCORE_API CInifile const* pSettings; extern XRCORE_API CInifile const* pSettingsAuth; extern XRCORE_API CInifile const* pSettingsOpenXRay; +extern XRCORE_API bool ltx_multiline_values_enabled; + #endif //__XR_INI_H__ diff --git a/src/xrEngine/IGame_ObjectPool.cpp b/src/xrEngine/IGame_ObjectPool.cpp index 1aef7c98b95..f4efe7fe84e 100644 --- a/src/xrEngine/IGame_ObjectPool.cpp +++ b/src/xrEngine/IGame_ObjectPool.cpp @@ -20,11 +20,11 @@ void IGame_ObjectPool::prefetch() CInifile::Sect const& sect = pSettings->r_section(section); for (const auto& item : sect.Data) { - CLASS_ID CLS = pSettings->r_clsid(item.first.c_str(), "class"); + CLASS_ID CLS = pSettings->r_clsid(item.name.c_str(), "class"); p_count++; IGameObject* pObject = smart_cast(NEW_INSTANCE(CLS)); - pObject->Load(item.first.c_str()); - VERIFY2(pObject->cNameSect().c_str(), item.first.c_str()); + pObject->Load(item.name.c_str()); + VERIFY2(pObject->cNameSect().c_str(), item.name.c_str()); m_PrefetchObjects.push_back(pObject); } diff --git a/src/xrEngine/main.cpp b/src/xrEngine/main.cpp index e927f7aa75f..ca2b5dbf4a7 100644 --- a/src/xrEngine/main.cpp +++ b/src/xrEngine/main.cpp @@ -122,11 +122,9 @@ ENGINE_API void InitSettings() CInifile::allow_include_func_t includeFilter; includeFilter.bind(&includePred, &PathIncludePred::IsIncluded); - InitConfig(pSettings, "system.ltx"); - InitConfig(pSettingsAuth, "system.ltx", true, true, true, false, 0, includeFilter); InitConfig(pSettingsOpenXRay, "openxray.ltx", false, true, true, false); - InitConfig(pGameIni, "game.ltx"); + // Determine game mode if (strstr(Core.Params, "-shoc") || strstr(Core.Params, "-soc")) set_shoc_mode(); else if (strstr(Core.Params, "-cs")) @@ -147,6 +145,13 @@ ENGINE_API void InitSettings() else if (xr_strcmpi("unlock", gameMode) == 0) set_free_mode(); } + + ltx_multiline_values_enabled = + pSettingsOpenXRay->read_if_exists("compatibility", "ltx_multiline_values", !ShadowOfChernobylMode); + + InitConfig(pSettings, "system.ltx"); + InitConfig(pSettingsAuth, "system.ltx", true, true, true, false, 0, includeFilter); + InitConfig(pGameIni, "game.ltx"); } ENGINE_API void InitConsole() diff --git a/src/xrGame/BoneProtections.cpp b/src/xrGame/BoneProtections.cpp index 154a755141b..26d72c84242 100644 --- a/src/xrGame/BoneProtections.cpp +++ b/src/xrGame/BoneProtections.cpp @@ -47,30 +47,30 @@ void SBoneProtections::reload(const shared_str& bone_sect, IKinematics* kinemati m_default.armor = 0.0f; m_default.BonePassBullet = FALSE; - CInifile::Sect& protections = pSettings->r_section(bone_sect); + const CInifile::Sect& protections = pSettings->r_section(bone_sect); for (auto i = protections.Data.cbegin(); protections.Data.cend() != i; ++i) { string256 buffer; BoneProtection BP; - BP.koeff = (float)atof(_GetItem(i->second.c_str(), 0, buffer)); - BP.armor = (float)atof(_GetItem(i->second.c_str(), 1, buffer)); - BP.BonePassBullet = (bool)(atof(_GetItem(i->second.c_str(), 2, buffer)) > 0.5f); + BP.koeff = (float)atof(_GetItem(i->value.c_str(), 0, buffer)); + BP.armor = (float)atof(_GetItem(i->value.c_str(), 1, buffer)); + BP.BonePassBullet = (bool)(atof(_GetItem(i->value.c_str(), 2, buffer)) > 0.5f); - if (!xr_strcmp(i->first.c_str(), "default")) + if (!xr_strcmp(i->name.c_str(), "default")) { m_default = BP; } else { - if (!xr_strcmp(i->first.c_str(), "hit_fraction")) + if (!xr_strcmp(i->name.c_str(), "hit_fraction")) continue; - s16 bone_id = kinematics->LL_BoneID(i->first); + s16 bone_id = kinematics->LL_BoneID(i->name); // TODO: fix that warning // warning: result of comparison of constant 65535 with expression of type 's16' (aka 'short') is always true - R_ASSERT2(BI_NONE != bone_id, i->first.c_str()); + R_ASSERT2(BI_NONE != bone_id, i->name.c_str()); m_bones_koeff.insert(std::make_pair(bone_id, BP)); } } @@ -90,28 +90,28 @@ void SBoneProtections::add(const shared_str& bone_sect, IKinematics* kinematics) } m_fHitFracNpc += READ_IF_EXISTS(pSettings, r_float, bone_sect.c_str(), "hit_fraction_npc", defaultHitFraction); - CInifile::Sect& protections = pSettings->r_section(bone_sect); + const CInifile::Sect& protections = pSettings->r_section(bone_sect); for (auto i = protections.Data.cbegin(); protections.Data.cend() != i; ++i) { - if (!xr_strcmp(i->first.c_str(), "hit_fraction")) + if (!xr_strcmp(i->name.c_str(), "hit_fraction")) continue; string256 buffer; - if (!xr_strcmp(i->first.c_str(), "default")) + if (!xr_strcmp(i->name.c_str(), "default")) { BoneProtection& BP = m_default; - BP.koeff += (float)atof(_GetItem(i->second.c_str(), 0, buffer)); - BP.armor += (float)atof(_GetItem(i->second.c_str(), 1, buffer)); + BP.koeff += (float)atof(_GetItem(i->value.c_str(), 0, buffer)); + BP.armor += (float)atof(_GetItem(i->value.c_str(), 1, buffer)); } else { - s16 bone_id = kinematics->LL_BoneID(i->first); + s16 bone_id = kinematics->LL_BoneID(i->name); // TODO: fix that warning // warning: result of comparison of constant 65535 with expression of type 's16' (aka 'short') is always true - R_ASSERT2(BI_NONE != bone_id, i->first.c_str()); + R_ASSERT2(BI_NONE != bone_id, i->name.c_str()); BoneProtection& BP = m_bones_koeff[bone_id]; - BP.koeff += (float)atof(_GetItem(i->second.c_str(), 0, buffer)); - BP.armor += (float)atof(_GetItem(i->second.c_str(), 1, buffer)); + BP.koeff += (float)atof(_GetItem(i->value.c_str(), 0, buffer)); + BP.armor += (float)atof(_GetItem(i->value.c_str(), 1, buffer)); } } } diff --git a/src/xrGame/Car.cpp b/src/xrGame/Car.cpp index 7c0c2405c37..0df862b8ee2 100644 --- a/src/xrGame/Car.cpp +++ b/src/xrGame/Car.cpp @@ -949,17 +949,17 @@ void CCar::Init() for (auto I = data.Data.cbegin(); I != data.Data.cend(); ++I) { const CInifile::Item& item = *I; - u16 index = pKinematics->LL_BoneID(*item.first); - R_ASSERT3(index != BI_NONE, "Wrong bone name", *item.first); + u16 index = pKinematics->LL_BoneID(*item.name); + R_ASSERT3(index != BI_NONE, "Wrong bone name", *item.name); xr_map::iterator i = m_wheels_map.find(index); if (i != m_wheels_map.end()) - i->second.CDamagableHealthItem::Init(float(atof(*item.second)), 2); + i->second.CDamagableHealthItem::Init(float(atof(*item.value)), 2); else { xr_map::iterator i = m_doors.find(index); - R_ASSERT3(i != m_doors.end(), "only wheel and doors bones allowed for damage defs", *item.first); - i->second.CDamagableHealthItem::Init(float(atof(*item.second)), 1); + R_ASSERT3(i != m_doors.end(), "only wheel and doors bones allowed for damage defs", *item.name); + i->second.CDamagableHealthItem::Init(float(atof(*item.value)), 1); } } } diff --git a/src/xrGame/ContextMenu.cpp b/src/xrGame/ContextMenu.cpp index 514bbcd0ecd..e84dadf61c7 100644 --- a/src/xrGame/ContextMenu.cpp +++ b/src/xrGame/ContextMenu.cpp @@ -22,9 +22,9 @@ void CContextMenu::Load(CInifile* INI, LPCSTR SECT) char Event[128], Param[128]; Event[0] = 0; Param[0] = 0; - sscanf(*I->second, "%[^,],%s", Event, Param); + sscanf(*I->value, "%[^,],%s", Event, Param); MenuItem Item; - Item.Name = xr_strdup(*I->first); + Item.Name = xr_strdup(*I->name); Item.Event = Engine.Event.Create(Event); Item.Param = xr_strdup(Param); Items.push_back(Item); diff --git a/src/xrGame/Level_load.cpp b/src/xrGame/Level_load.cpp index b1c6776b38a..d29bc625b6d 100644 --- a/src/xrGame/Level_load.cpp +++ b/src/xrGame/Level_load.cpp @@ -104,12 +104,12 @@ bool CLevel::Load_GameSpecific_After() // loading random (around player) sounds if (pSettings->section_exist("sounds_random")) { - CInifile::Sect& S = pSettings->r_section("sounds_random"); + const CInifile::Sect& S = pSettings->r_section("sounds_random"); Sounds_Random.reserve(S.Data.size()); for (auto I = S.Data.cbegin(); S.Data.cend() != I; ++I) { Sounds_Random.push_back(ref_sound()); - Sounds_Random.back().create(*I->first, st_Effect, sg_SourceType); + Sounds_Random.back().create(*I->name, st_Effect, sg_SourceType); } Sounds_Random_dwNextTime = Device.TimerAsync() + 50000; Sounds_Random_Enabled = FALSE; diff --git a/src/xrGame/PHCollisionDamageReceiver.cpp b/src/xrGame/PHCollisionDamageReceiver.cpp index 9904d48778e..0b34fd0dbc1 100644 --- a/src/xrGame/PHCollisionDamageReceiver.cpp +++ b/src/xrGame/PHCollisionDamageReceiver.cpp @@ -23,9 +23,9 @@ void CPHCollisionDamageReceiver::Init() CInifile::Sect& data = ini->r_section("collision_damage"); for (const auto& item : data.Data) { - u16 index = K->LL_BoneID(*item.first); - R_ASSERT3(index != BI_NONE, "Wrong bone name", *item.first); - BoneInsert(index, float(atof(*item.second))); + u16 index = K->LL_BoneID(*item.name); + R_ASSERT3(index != BI_NONE, "Wrong bone name", *item.name); + BoneInsert(index, float(atof(*item.value))); CODEGeom* og = sh->PPhysicsShell()->get_GeomByID(index); // R_ASSERT3(og, "collision damage bone has no physics collision", *item.first); if (og) diff --git a/src/xrGame/PHDestroyable.cpp b/src/xrGame/PHDestroyable.cpp index 8aa6f628029..006e0eeb8a8 100644 --- a/src/xrGame/PHDestroyable.cpp +++ b/src/xrGame/PHDestroyable.cpp @@ -173,8 +173,8 @@ void CPHDestroyable::Load(CInifile* ini, LPCSTR section) if (data.Data.size() > 0) m_flags.set(fl_destroyable, true); for (const auto& I : data.Data) - if (I.first.size()) - m_destroyed_obj_visual_names.push_back(I.first); + if (I.name.size()) + m_destroyed_obj_visual_names.push_back(I.name); } } void CPHDestroyable::Load(LPCSTR section) diff --git a/src/xrGame/ParticlesPlayer.cpp b/src/xrGame/ParticlesPlayer.cpp index c9b85f3ac13..e84f12eacca 100644 --- a/src/xrGame/ParticlesPlayer.cpp +++ b/src/xrGame/ParticlesPlayer.cpp @@ -84,10 +84,10 @@ void CParticlesPlayer::LoadParticles(IKinematics* K) CInifile::Sect& data = ini->r_section("particle_bones"); for (const auto& item : data.Data) { - u16 index = K->LL_BoneID(*item.first); - R_ASSERT3(index != BI_NONE, "Particles bone not found", *item.first); + u16 index = K->LL_BoneID(*item.name); + R_ASSERT3(index != BI_NONE, "Particles bone not found", *item.name); Fvector offs; - sscanf(*item.second, "%f,%f,%f", &offs.x, &offs.y, &offs.z); + sscanf(*item.value, "%f,%f,%f", &offs.x, &offs.y, &offs.z); m_Bones.push_back(SBoneInfo(index, offs)); bone_mask |= u64(1) << u64(index); } diff --git a/src/xrGame/UIGameCustom.cpp b/src/xrGame/UIGameCustom.cpp index 02c2035a755..7b709b2b5ee 100644 --- a/src/xrGame/UIGameCustom.cpp +++ b/src/xrGame/UIGameCustom.cpp @@ -389,7 +389,7 @@ void CMapListHelper::LoadMapInfo(const char* cfgName, const xr_string& levelName shLevelVer = levelCfg.r_string("map_usage", "ver"); for (CInifile::Item& kv : levelCfg.r_section("map_usage").Data) { - const shared_str& gameType = kv.first; + const shared_str& gameType = kv.name; if (gameType == "ver") continue; SGameTypeMaps* suitableLevels = GetMapListInt(gameType); @@ -432,8 +432,8 @@ void CMapListHelper::Load() for (CInifile::Item& weatherDesc : weatherCfg.Data) { MPWeatherDesc gw; - gw.Name = weatherDesc.first; - gw.StartTime = weatherDesc.second; + gw.Name = weatherDesc.name; + gw.StartTime = weatherDesc.value; m_weathers.push_back(gw); } // scan for additional maps diff --git a/src/xrGame/ai/monsters/basemonster/base_monster_startup.cpp b/src/xrGame/ai/monsters/basemonster/base_monster_startup.cpp index 152383e43e4..77b1b422a0a 100644 --- a/src/xrGame/ai/monsters/basemonster/base_monster_startup.cpp +++ b/src/xrGame/ai/monsters/basemonster/base_monster_startup.cpp @@ -534,9 +534,9 @@ void CBaseMonster::fill_bones_body_parts(LPCSTR body_part, CriticalWoundType wou IKinematics* kinematics = smart_cast(Visual()); VERIFY(kinematics); - CInifile::Sect& body_part_section = pSettings->r_section(body_parts_section); + const CInifile::Sect& body_part_section = pSettings->r_section(body_parts_section); auto I = body_part_section.Data.cbegin(); auto E = body_part_section.Data.cend(); for (; I != E; ++I) - m_bones_body_parts.emplace(kinematics->LL_BoneID((*I).first), u32(wound_type)); + m_bones_body_parts.emplace(kinematics->LL_BoneID((*I).name), u32(wound_type)); } diff --git a/src/xrGame/ai/stalker/ai_stalker.cpp b/src/xrGame/ai/stalker/ai_stalker.cpp index c1cf7cc2d5a..6e900286607 100644 --- a/src/xrGame/ai/stalker/ai_stalker.cpp +++ b/src/xrGame/ai/stalker/ai_stalker.cpp @@ -1240,11 +1240,11 @@ void CAI_Stalker::fill_bones_body_parts(LPCSTR bone_id, const ECriticalWoundType IKinematics* kinematics = smart_cast(Visual()); VERIFY(kinematics); - CInifile::Sect& body_part_section = pSettings->r_section(body_part_section_id); + const CInifile::Sect& body_part_section = pSettings->r_section(body_part_section_id); auto I = body_part_section.Data.cbegin(); auto E = body_part_section.Data.cend(); for (; I != E; ++I) - m_bones_body_parts.emplace(kinematics->LL_BoneID((*I).first), u32(wound_type)); + m_bones_body_parts.emplace(kinematics->LL_BoneID((*I).name), u32(wound_type)); } void CAI_Stalker::on_before_change_team() diff --git a/src/xrGame/configs_dump_verifyer.cpp b/src/xrGame/configs_dump_verifyer.cpp index 930316d7a0f..9b6252b49af 100644 --- a/src/xrGame/configs_dump_verifyer.cpp +++ b/src/xrGame/configs_dump_verifyer.cpp @@ -89,17 +89,17 @@ LPCSTR configs_verifyer::get_section_diff(CInifile::Sect* sect_ptr, CInifile& ac for (auto cit = sect_ptr->Data.cbegin(), ciet = sect_ptr->Data.cend(); cit != ciet; ++cit) { - shared_str const& tmp_value = cit->second; + shared_str const& tmp_value = cit->value; shared_str real_value; if (tmp_active_param) { - if (active_params.line_exist(sect_ptr->Name.c_str(), cit->first)) + if (active_params.line_exist(sect_ptr->Name.c_str(), cit->name)) { - real_value = active_params.r_string(sect_ptr->Name.c_str(), cit->first.c_str()); + real_value = active_params.r_string(sect_ptr->Name.c_str(), cit->name.c_str()); if (tmp_value != real_value) { pcstr tmp_key_str = nullptr; - STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->first.c_str()); + STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->name.c_str()); STRCONCAT(diff_str, tmp_key_str, " = ", tmp_value.c_str(), ",right = ", real_value.c_str()); strncpy_s(dst_diff, diff_str, sizeof(dst_diff) - 1); dst_diff[sizeof(dst_diff) - 1] = 0; @@ -108,18 +108,18 @@ LPCSTR configs_verifyer::get_section_diff(CInifile::Sect* sect_ptr, CInifile& ac continue; } } - if (!pSettings->line_exist(sect_ptr->Name, cit->first)) + if (!pSettings->line_exist(sect_ptr->Name, cit->name)) { - STRCONCAT(diff_str, "line ", sect_ptr->Name.c_str(), "::", cit->first.c_str(), " not found"); + STRCONCAT(diff_str, "line ", sect_ptr->Name.c_str(), "::", cit->name.c_str(), " not found"); strncpy_s(dst_diff, diff_str, sizeof(dst_diff) - 1); dst_diff[sizeof(dst_diff) - 1] = 0; return dst_diff; } - real_value = pSettings->r_string(sect_ptr->Name.c_str(), cit->first.c_str()); + real_value = pSettings->r_string(sect_ptr->Name.c_str(), cit->name.c_str()); if (tmp_value != real_value) { pcstr tmp_key_str = nullptr; - STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->first.c_str()); + STRCONCAT(tmp_key_str, sect_ptr->Name.c_str(), "::", cit->name.c_str()); STRCONCAT(diff_str, tmp_key_str, " = ", tmp_value.c_str(), ",right = ", real_value.c_str()); strncpy_s(dst_diff, diff_str, sizeof(dst_diff) - 1); dst_diff[sizeof(dst_diff) - 1] = 0; diff --git a/src/xrGame/damage_manager.cpp b/src/xrGame/damage_manager.cpp index db5e7365786..4d13aa6a0ef 100644 --- a/src/xrGame/damage_manager.cpp +++ b/src/xrGame/damage_manager.cpp @@ -74,25 +74,25 @@ void CDamageManager::load_section(LPCSTR section, CInifile const* ini) { string32 buffer; IKinematics* kinematics = smart_cast(m_object->Visual()); - CInifile::Sect& damages = ini->r_section(section); + const CInifile::Sect& damages = ini->r_section(section); for (const auto & i : damages.Data) { - if (xr_strcmp(*i.first, "default")) + if (xr_strcmp(*i.name, "default")) { // read all except default line VERIFY(m_object); - int bone = kinematics->LL_BoneID(i.first); - R_ASSERT2(BI_NONE != bone, *i.first); + int bone = kinematics->LL_BoneID(i.name); + R_ASSERT2(BI_NONE != bone, *i.name); CBoneInstance& bone_instance = kinematics->LL_GetBoneInstance(u16(bone)); - bone_instance.set_param(0, (float)atof(_GetItem(*i.second, 0, buffer))); - bone_instance.set_param(1, (float)atoi(_GetItem(*i.second, 1, buffer))); - bone_instance.set_param(2, (float)atof(_GetItem(*i.second, 2, buffer))); - if (_GetItemCount(*i.second) < 4) + bone_instance.set_param(0, (float)atof(_GetItem(*i.value, 0, buffer))); + bone_instance.set_param(1, (float)atoi(_GetItem(*i.value, 1, buffer))); + bone_instance.set_param(2, (float)atof(_GetItem(*i.value, 2, buffer))); + if (_GetItemCount(*i.value) < 4) { - bone_instance.set_param(3, (float)atof(_GetItem(*i.second, 0, buffer))); + bone_instance.set_param(3, (float)atof(_GetItem(*i.value, 0, buffer))); } else { - bone_instance.set_param(3, (float)atof(_GetItem(*i.second, 3, buffer))); + bone_instance.set_param(3, (float)atof(_GetItem(*i.value, 3, buffer))); } if (0 == bone && (fis_zero(bone_instance.get_param(0)) || fis_zero(bone_instance.get_param(2)))) { diff --git a/src/xrGame/ini_table_loader.h b/src/xrGame/ini_table_loader.h index 3b3af18bc9b..b4b6b624ea5 100644 --- a/src/xrGame/ini_table_loader.h +++ b/src/xrGame/ini_table_loader.h @@ -96,22 +96,22 @@ typename CSIni_Table::ITEM_TABLE& CSIni_Table::table() m_pTable->resize(table_size); string64 buffer; - CInifile::Sect& table_ini = pSettings->r_section(table_sect); + const CInifile::Sect& table_ini = pSettings->r_section(table_sect); R_ASSERT3(table_ini.Data.size() == table_size, "wrong size for table in section", table_sect); for (auto i = table_ini.Data.cbegin(); table_ini.Data.cend() != i; ++i) { typename T_INI_LOADER::index_type cur_index = - T_INI_LOADER::IdToIndex((*i).first, type_max); + T_INI_LOADER::IdToIndex((*i).name, type_max); if (type_max == cur_index) - xrDebug::Fatal(DEBUG_INFO, "wrong community %s in section [%s]", (*i).first.c_str(), table_sect); + xrDebug::Fatal(DEBUG_INFO, "wrong community %s in section [%s]", (*i).name.c_str(), table_sect); (*m_pTable)[cur_index].resize(cur_table_width); for (size_t j = 0; j < cur_table_width; j++) { - (*m_pTable)[cur_index][j] = convert(_GetItem(*(*i).second, (int)j, buffer)); + (*m_pTable)[cur_index][j] = convert(_GetItem(*(*i).value, (int)j, buffer)); } } diff --git a/src/xrGame/inventory_upgrade_manager.cpp b/src/xrGame/inventory_upgrade_manager.cpp index 0f14436e22f..605acd8f7a7 100644 --- a/src/xrGame/inventory_upgrade_manager.cpp +++ b/src/xrGame/inventory_upgrade_manager.cpp @@ -177,7 +177,7 @@ class check_upgraded_inventory_section const auto it = std::find_if(ib, ie, [&](const CInifile::Item& item) { - return item.first == item_id; + return item.name == item_id; }); return it != ie; @@ -226,12 +226,12 @@ void Manager::load_all_properties() pSettings->section_exist(properties_section), make_string("Section [%s] does not exist !", properties_section)); VERIFY2(pSettings->line_count(properties_section), make_string("Section [%s] is empty !", properties_section)); - CInifile::Sect& inv_section = pSettings->r_section(properties_section); + const CInifile::Sect& inv_section = pSettings->r_section(properties_section); auto ib = inv_section.Data.begin(); auto ie = inv_section.Data.end(); for (; ib != ie; ++ib) { - shared_str property_id((*ib).first); + shared_str property_id((*ib).name); add_property(property_id); } diff --git a/src/xrGame/level_sounds.cpp b/src/xrGame/level_sounds.cpp index 017dfcacfcb..1f2565438f5 100644 --- a/src/xrGame/level_sounds.cpp +++ b/src/xrGame/level_sounds.cpp @@ -202,7 +202,7 @@ void CLevelSoundManager::Load() for (; it != end; ++it) { m_MusicTracks.push_back(SMusicTrack()); - m_MusicTracks.back().Load(*it->first, *it->second); + m_MusicTracks.back().Load(*it->name, *it->value); } } } diff --git a/src/xrGame/mp_config_sections.cpp b/src/xrGame/mp_config_sections.cpp index 7c14f5d064e..46db1c6e8a0 100644 --- a/src/xrGame/mp_config_sections.cpp +++ b/src/xrGame/mp_config_sections.cpp @@ -40,9 +40,9 @@ bool mp_config_sections::dump_one(CMemoryWriter& dest) return false; R_ASSERT(pSettings->section_exist(m_current_dump_sect->c_str())); - CInifile::Sect& tmp_sect = pSettings->r_section(m_current_dump_sect->c_str()); + const CInifile::Sect& tmp_sect = pSettings->r_section(m_current_dump_sect->c_str()); - m_tmp_dumper.sections().push_back(&tmp_sect); + m_tmp_dumper.sections().push_back(const_cast(&tmp_sect)); m_tmp_dumper.save_as(dest); m_tmp_dumper.sections().pop_back(); ++m_current_dump_sect; diff --git a/src/xrGame/purchase_list.cpp b/src/xrGame/purchase_list.cpp index 93630048020..2c46dbafd25 100644 --- a/src/xrGame/purchase_list.cpp +++ b/src/xrGame/purchase_list.cpp @@ -27,12 +27,12 @@ void CPurchaseList::process(CInifile& ini_file, LPCSTR section, CInventoryOwner& auto E = S.Data.cend(); for (; I != E; ++I) { - VERIFY3((*I).second.size(), "PurchaseList : cannot handle lines in section without values", section); + VERIFY3((*I).value.size(), "PurchaseList : cannot handle lines in section without values", section); string256 temp0, temp1; - THROW3(_GetItemCount(*(*I).second) == 2, "Invalid parameters in section", section); - process(game_object, (*I).first, atoi(_GetItem(*(*I).second, 0, temp0)), - (float)atof(_GetItem(*(*I).second, 1, temp1))); + THROW3(_GetItemCount(*(*I).value) == 2, "Invalid parameters in section", section); + process(game_object, (*I).name, atoi(_GetItem(*(*I).value, 0, temp0)), + (float)atof(_GetItem(*(*I).value, 1, temp1))); } } diff --git a/src/xrGame/step_manager.cpp b/src/xrGame/step_manager.cpp index 3dcc3b7aeaf..c700901e2f7 100644 --- a/src/xrGame/step_manager.cpp +++ b/src/xrGame/step_manager.cpp @@ -267,22 +267,22 @@ Fvector CStepManager::get_foot_position(ELegType leg_type) return global_transform.c; } -void CStepManager::load_foot_bones(CInifile::Sect& data) +void CStepManager::load_foot_bones(const CInifile::Sect& data) { for (auto I = data.Data.cbegin(); I != data.Data.cend(); ++I) { const CInifile::Item& item = *I; - u16 index = smart_cast(m_object->Visual())->LL_BoneID(*item.second); - VERIFY3(index != BI_NONE, "foot bone not found", *item.second); + u16 index = smart_cast(m_object->Visual())->LL_BoneID(*item.value); + VERIFY3(index != BI_NONE, "foot bone not found", *item.value); - if (xr_strcmp(*item.first, "front_left") == 0) + if (xr_strcmp(*item.name, "front_left") == 0) m_foot_bones[eFrontLeft] = index; - else if (xr_strcmp(*item.first, "front_right") == 0) + else if (xr_strcmp(*item.name, "front_right") == 0) m_foot_bones[eFrontRight] = index; - else if (xr_strcmp(*item.first, "back_right") == 0) + else if (xr_strcmp(*item.name, "back_right") == 0) m_foot_bones[eBackRight] = index; - else if (xr_strcmp(*item.first, "back_left") == 0) + else if (xr_strcmp(*item.name, "back_left") == 0) m_foot_bones[eBackLeft] = index; } } diff --git a/src/xrGame/step_manager.h b/src/xrGame/step_manager.h index 03ad3f78404..e21fac25cdc 100644 --- a/src/xrGame/step_manager.h +++ b/src/xrGame/step_manager.h @@ -45,7 +45,7 @@ class CStepManager virtual bool is_on_ground() { return true; } private: void reload_foot_bones(); - void load_foot_bones(CInifile::Sect& data); + void load_foot_bones(const CInifile::Sect& data); float get_blend_time(); }; diff --git a/src/xrGame/trade_parameters.cpp b/src/xrGame/trade_parameters.cpp index 1b66171a703..15e7bfbccde 100644 --- a/src/xrGame/trade_parameters.cpp +++ b/src/xrGame/trade_parameters.cpp @@ -19,6 +19,6 @@ void CTradeParameters::process(action_show, CInifile& ini_file, const shared_str auto I = S.Data.cbegin(); auto E = S.Data.cend(); for (; I != E; ++I) - if (!(*I).second.size()) - m_show.disable((*I).first); + if (!(*I).value.size()) + m_show.disable((*I).name); } diff --git a/src/xrGame/trade_parameters_inline.h b/src/xrGame/trade_parameters_inline.h index 4984a3fc596..974137c5144 100644 --- a/src/xrGame/trade_parameters_inline.h +++ b/src/xrGame/trade_parameters_inline.h @@ -77,16 +77,16 @@ IC void CTradeParameters::process(_action_type type, CInifile& ini_file, const s auto E = S.Data.cend(); for (; I != E; ++I) { - if (!(*I).second.size()) + if (!(*I).value.size()) { - _action.disable((*I).first); + _action.disable((*I).name); continue; } string256 temp0, temp1; - THROW3(_GetItemCount(*(*I).second) == 2, "Invalid parameters in section", *section); - _action.enable((*I).first, CTradeFactors((float)atof(_GetItem(*(*I).second, 0, temp0)), - (float)atof(_GetItem(*(*I).second, 1, temp1)))); + THROW3(_GetItemCount(*(*I).value) == 2, "Invalid parameters in section", *section); + _action.enable((*I).name, CTradeFactors((float)atof(_GetItem(*(*I).value, 0, temp0)), + (float)atof(_GetItem(*(*I).value, 1, temp1)))); } } diff --git a/src/xrGame/ui/UIBuyWndShared.cpp b/src/xrGame/ui/UIBuyWndShared.cpp index 17d48323873..e4d5b0d30b8 100644 --- a/src/xrGame/ui/UIBuyWndShared.cpp +++ b/src/xrGame/ui/UIBuyWndShared.cpp @@ -6,15 +6,15 @@ extern pcstr _list_names[]; void CItemMgr::Load(const shared_str& sect_cost) { - CInifile::Sect& sect = pSettings->r_section(sect_cost); + const CInifile::Sect& sect = pSettings->r_section(sect_cost); u32 idx = 0; for (auto it = sect.Data.cbegin(); it != sect.Data.cend(); ++it, ++idx) { - _i& val = m_items[it->first]; + _i& val = m_items[it->name]; val.slot_idx = 0xff; int c = sscanf( - it->second.c_str(), "%d,%d,%d,%d,%d", &val.cost[0], &val.cost[1], &val.cost[2], &val.cost[3], &val.cost[4]); + it->value.c_str(), "%d,%d,%d,%d,%d", &val.cost[0], &val.cost[1], &val.cost[2], &val.cost[3], &val.cost[4]); VERIFY(c > 0); while (c < _RANK_COUNT) diff --git a/src/xrGame/ui/UICharacterInfo.cpp b/src/xrGame/ui/UICharacterInfo.cpp index e3367896ab5..141c26afa2a 100644 --- a/src/xrGame/ui/UICharacterInfo.cpp +++ b/src/xrGame/ui/UICharacterInfo.cpp @@ -388,12 +388,12 @@ bool CUICharacterInfo::ignore_community(shared_str const& check_community) if (!pSettings->section_exist(comm_section_str)) return false; - CInifile::Sect& faction_section = pSettings->r_section(comm_section_str); + const CInifile::Sect& faction_section = pSettings->r_section(comm_section_str); auto ib = faction_section.Data.begin(); auto ie = faction_section.Data.end(); for (; ib != ie; ++ib) { - if (check_community == (*ib).first) + if (check_community == (*ib).name) { return true; } diff --git a/src/xrGame/ui/UIInvUpgradeProperty.cpp b/src/xrGame/ui/UIInvUpgradeProperty.cpp index 296a64489c2..595cfdfa1b5 100644 --- a/src/xrGame/ui/UIInvUpgradeProperty.cpp +++ b/src/xrGame/ui/UIInvUpgradeProperty.cpp @@ -158,7 +158,7 @@ bool UIInvUpgPropertiesWnd::init_from_xml(LPCSTR xml_name) VERIFY2(pSettings->line_count(properties_section), make_string("Section [%s] is empty !", properties_section)); shared_str property_id; - CInifile::Sect& inv_section = pSettings->r_section(properties_section); + const CInifile::Sect& inv_section = pSettings->r_section(properties_section); auto ib = inv_section.Data.begin(); auto ie = inv_section.Data.end(); for (; ib != ie; ++ib) @@ -166,7 +166,7 @@ bool UIInvUpgPropertiesWnd::init_from_xml(LPCSTR xml_name) UIProperty* ui_property = xr_new(); // load one time !! ui_property->init_from_xml(ui_xml); - property_id._set((*ib).first); + property_id._set((*ib).name); if (!ui_property->init_property(property_id)) { Msg("! Invalid property <%s> in inventory upgrade manager!", property_id.c_str()); diff --git a/src/xrGame/ui/UIMapWnd.cpp b/src/xrGame/ui/UIMapWnd.cpp index d60f258202e..795327fd23d 100644 --- a/src/xrGame/ui/UIMapWnd.cpp +++ b/src/xrGame/ui/UIMapWnd.cpp @@ -182,7 +182,7 @@ bool CUIMapWnd::Init(cpcstr xml_name, cpcstr start_from, bool critical /*= true* auto it = S.Data.cbegin(), end = S.Data.cend(); for (; it != end; ++it) { - shared_str map_name = it->first; + shared_str map_name = it->name; xr_strlwr(map_name); R_ASSERT2(m_GameMaps.end() == m_GameMaps.find(map_name), "Duplicate level name not allowed"); diff --git a/src/xrGame/ui/UIRankingWnd.cpp b/src/xrGame/ui/UIRankingWnd.cpp index 80a3df7154f..9229f3169ef 100644 --- a/src/xrGame/ui/UIRankingWnd.cpp +++ b/src/xrGame/ui/UIRankingWnd.cpp @@ -163,10 +163,10 @@ bool CUIRankingWnd::Init() { node = xml.NavigateToNode("fraction_list", 0); xml.SetLocalRoot(node); - CInifile::Sect& faction_section = pSettings->r_section(fract_section); + const CInifile::Sect& faction_section = pSettings->r_section(fract_section); for (const auto& item : faction_section.Data) { - add_faction(xml, item.first); + add_faction(xml, item.name); } node = xml.NavigateToNode("fraction_list", 0); xml.SetLocalRoot(stored_root); @@ -193,9 +193,9 @@ bool CUIRankingWnd::Init() if (pSettings->section_exist(section)) { - CInifile::Sect& achievs_section = pSettings->r_section(section); + const CInifile::Sect& achievs_section = pSettings->r_section(section); for (const auto& item : achievs_section.Data) - add_achievement(xml, item.first); + add_achievement(xml, item.name); } } xml.SetLocalRoot(stored_root); diff --git a/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp b/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp index 2c2b2ee52ac..f2674cdc135 100644 --- a/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp +++ b/src/xrServerEntities/xrServer_Objects_ALife_Monsters.cpp @@ -42,12 +42,12 @@ void setup_location_types_section(GameGraph::TERRAIN_VECTOR& m_vertex_types, CIn GameGraph::STerrainPlace terrain_mask; terrain_mask.tMask.resize(GameGraph::LOCATION_TYPE_COUNT); - CInifile::Sect& sect = ini->r_section(section); + const CInifile::Sect& sect = ini->r_section(section); auto I = sect.Data.cbegin(); auto E = sect.Data.cend(); for (; I != E; ++I) { - pcstr S = *(*I).first; + pcstr S = *(*I).name; string16 I2; u32 N = _GetItemCount(S);