mirror of
https://github.com/electronicarts/CNC_TS_and_RA2_Mission_Editor.git
synced 2025-05-06 11:41:42 -04:00
refactored ini management, fixing performance issue and logic error from very low level .
This commit is contained in:
parent
13677476df
commit
c559292183
3 changed files with 190 additions and 174 deletions
|
@ -38,6 +38,9 @@ static char THIS_FILE[] = __FILE__;
|
|||
|
||||
using namespace std;
|
||||
|
||||
const CIniFileSection CIniFile::EmptySection;
|
||||
const CString CIniFileSection::EmptyValue;
|
||||
|
||||
bool SortDummy::operator()(const CString& x, const CString& y) const
|
||||
{
|
||||
// the length is more important than spelling (numbers!!!)...
|
||||
|
@ -95,14 +98,12 @@ void CIniFile::Clear()
|
|||
|
||||
CIniFileSection::CIniFileSection()
|
||||
{
|
||||
values.clear();
|
||||
value_orig_pos.clear();
|
||||
};
|
||||
|
||||
CIniFileSection::~CIniFileSection()
|
||||
{
|
||||
values.clear();
|
||||
value_orig_pos.clear();
|
||||
value_pos.clear();
|
||||
value_pairs.clear();
|
||||
};
|
||||
|
||||
WORD CIniFile::InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces)
|
||||
|
@ -158,7 +159,7 @@ WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL
|
|||
CString name = cLine.substr(0, equals).c_str();
|
||||
CString value = cLine.substr(equals + 1, cLine.size() - equals - 1).c_str();
|
||||
|
||||
int cuValueIndex = sections[cSec].values.size();
|
||||
int cuValueIndex = sections[cSec].Size();
|
||||
|
||||
if (bNoSpaces)
|
||||
{
|
||||
|
@ -166,8 +167,7 @@ WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL
|
|||
value.Trim();
|
||||
}
|
||||
|
||||
sections[cSec].values[name] = value;
|
||||
sections[cSec].value_orig_pos[name] = cuValueIndex;
|
||||
sections[cSec].Assign(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL
|
|||
return 0;
|
||||
}
|
||||
|
||||
const CIniFileSection* CIniFile::GetSection(std::size_t index) const
|
||||
const CIniFileSection* CIniFile::TryGetSection(std::size_t index) const
|
||||
{
|
||||
if (index > sections.size() - 1)
|
||||
return NULL;
|
||||
|
@ -192,7 +192,7 @@ const CIniFileSection* CIniFile::GetSection(std::size_t index) const
|
|||
return &i->second;
|
||||
}
|
||||
|
||||
CIniFileSection* CIniFile::GetSection(std::size_t index)
|
||||
CIniFileSection* CIniFile::TryGetSection(std::size_t index)
|
||||
{
|
||||
if (index > sections.size() - 1)
|
||||
return NULL;
|
||||
|
@ -204,59 +204,6 @@ CIniFileSection* CIniFile::GetSection(std::size_t index)
|
|||
return &i->second;
|
||||
}
|
||||
|
||||
const CIniFileSection* CIniFile::GetSection(const CString& section) const
|
||||
{
|
||||
auto it = sections.find(section);
|
||||
if (it == sections.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
CIniFileSection* CIniFile::GetSection(const CString& section)
|
||||
{
|
||||
auto it = sections.find(section);
|
||||
if (it == sections.end())
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
const CString* CIniFileSection::GetValue(std::size_t index) const noexcept
|
||||
{
|
||||
if (index > values.size() - 1)
|
||||
return NULL;
|
||||
|
||||
auto i = values.begin();
|
||||
for (auto e = 0;e < index;e++)
|
||||
i++;
|
||||
|
||||
return &i->second;
|
||||
}
|
||||
|
||||
CString* CIniFileSection::GetValue(std::size_t index) noexcept
|
||||
{
|
||||
if (index > values.size() - 1)
|
||||
return NULL;
|
||||
|
||||
auto i = values.begin();
|
||||
for (auto e = 0; e < index; e++) {
|
||||
if (i == values.end()) {
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i == values.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &i->second;
|
||||
}
|
||||
|
||||
CString CIniFileSection::GetValueByName(const CString& valueName, const CString& defaultValue) const
|
||||
{
|
||||
auto it = values.find(valueName);
|
||||
return (it == values.end()) ? defaultValue : it->second;
|
||||
}
|
||||
|
||||
const CString* CIniFile::GetSectionName(std::size_t index) const noexcept
|
||||
{
|
||||
if (index > sections.size() - 1)
|
||||
|
@ -274,19 +221,6 @@ CString& CIniFileSection::AccessValueByName(const CString& valueName)
|
|||
return values[valueName];
|
||||
}
|
||||
|
||||
const CString* CIniFileSection::GetValueName(std::size_t index) const noexcept
|
||||
{
|
||||
if (index > values.size() - 1)
|
||||
return NULL;
|
||||
|
||||
auto i = values.begin();
|
||||
for (auto e = 0; e < index; ++e)
|
||||
i++;
|
||||
|
||||
|
||||
return &(i->first);
|
||||
}
|
||||
|
||||
BOOL CIniFile::SaveFile(const CString& filename) const
|
||||
{
|
||||
return SaveFile(std::string(filename.GetString()));
|
||||
|
@ -298,14 +232,10 @@ BOOL CIniFile::SaveFile(const std::string& Filename) const
|
|||
|
||||
file.open(Filename, ios::out | ios::trunc);
|
||||
|
||||
int i;
|
||||
for (i = 0;i < sections.size();i++)
|
||||
{
|
||||
file << "[" << (LPCTSTR)*GetSectionName(i) << "]" << endl;
|
||||
int e;
|
||||
for (e = 0;e < GetSection(i)->values.size();e++)
|
||||
{
|
||||
file << (LPCTSTR) * (GetSection(i)->GetValueName(e)) << "=" << (LPCTSTR)*GetSection(i)->GetValue(e) << endl;
|
||||
for (auto const& sec : sections) {
|
||||
file << "[" << sec.first << "]" << endl;
|
||||
for (auto const& pair : sec.second) {
|
||||
file << pair.first << "=" << pair.second << endl;
|
||||
}
|
||||
file << endl;
|
||||
}
|
||||
|
@ -318,81 +248,28 @@ BOOL CIniFile::SaveFile(const std::string& Filename) const
|
|||
|
||||
int CIniFileSection::FindValue(CString sval) const noexcept
|
||||
{
|
||||
int i;
|
||||
auto it = values.cbegin();
|
||||
for (i = 0;i < values.size();i++)
|
||||
{
|
||||
if (sval == it->second)
|
||||
return i;
|
||||
it++;
|
||||
for (auto idx = 0;
|
||||
idx < this->value_pairs.size();
|
||||
++idx) {
|
||||
if (this->value_pairs[idx].second == sval) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int CIniFileSection::FindName(CString sval) const noexcept
|
||||
{
|
||||
int i;
|
||||
auto it = values.cbegin();
|
||||
for (i = 0;i < values.size();i++)
|
||||
{
|
||||
if (sval == it->first)
|
||||
return i;
|
||||
it++;
|
||||
auto const it = this->value_pos.find(sval);
|
||||
if (it != this->value_pos.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CIniFile::DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues)
|
||||
{
|
||||
int i;
|
||||
for (i = 0;i < sections.size();i++)
|
||||
{
|
||||
CIniFileSection& sec = *GetSection(i);
|
||||
int e;
|
||||
for (e = 0;e < sec.values.size();e++)
|
||||
{
|
||||
if (bValues) sec.GetValue(e)->TrimLeft();
|
||||
if (bValueNames)
|
||||
{
|
||||
CString value = *sec.GetValue(e);
|
||||
CString name = *sec.GetValueName(e);
|
||||
|
||||
sec.values.erase(name);
|
||||
name.TrimLeft();
|
||||
sec.values[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CIniFile::DeleteEndingSpaces(BOOL bValueNames, BOOL bValues)
|
||||
{
|
||||
int i;
|
||||
for (i = 0;i < sections.size();i++)
|
||||
{
|
||||
CIniFileSection& sec = *GetSection(i);
|
||||
int e;
|
||||
for (e = 0;e < sec.values.size();e++)
|
||||
{
|
||||
if (bValues) sec.GetValue(e)->TrimRight();
|
||||
if (bValueNames)
|
||||
{
|
||||
//CString& name=(CString&)*sec.GetValueName(e);
|
||||
//name.TrimRight();
|
||||
CString value = *sec.GetValue(e);
|
||||
CString name = *sec.GetValueName(e);
|
||||
|
||||
sec.values.erase(name);
|
||||
name.TrimRight();
|
||||
sec.values[name] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CString CIniFile::GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const
|
||||
{
|
||||
auto section = GetSection(sectionName);
|
||||
auto section = TryGetSection(sectionName);
|
||||
if (!section)
|
||||
return defaultValue;
|
||||
return section->GetValueByName(valueName, defaultValue);
|
||||
|
|
|
@ -33,7 +33,10 @@
|
|||
#include <map>
|
||||
#include <CString>
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <ios>
|
||||
#include "IniHelper.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
@ -49,30 +52,92 @@ public:
|
|||
class CIniFileSection
|
||||
{
|
||||
public:
|
||||
|
||||
static const CString EmptyValue;
|
||||
|
||||
CIniFileSection();
|
||||
virtual ~CIniFileSection();
|
||||
|
||||
CString GetValueByName(const CString& name, const CString& defaultValue = CString()) const;
|
||||
[[deprecated("instead use GetString or TryGetString")]]
|
||||
CString& AccessValueByName(const CString& name);
|
||||
|
||||
auto begin() noexcept
|
||||
{
|
||||
return values.begin();
|
||||
auto const& Nth(size_t index) const {
|
||||
ASSERT(index < value_pairs.size());
|
||||
return this->value_pairs[index];
|
||||
}
|
||||
|
||||
const CString* TryGetString(const CString& key) const {
|
||||
auto const it = value_pos.find(key);
|
||||
if (it != value_pos.end()) {
|
||||
return &this->value_pairs[it->second].second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CString& GetString(const CString& key) const {
|
||||
if (auto const ret = TryGetString(key)) {
|
||||
return *ret;
|
||||
}
|
||||
return EmptyValue;
|
||||
}
|
||||
CString GetStringOr(const CString& key, const CString& defaultValue) const {
|
||||
auto const it = value_pos.find(key);
|
||||
if (it != value_pos.end()) {
|
||||
return this->value_pairs[it->second].second;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
int GetInteger(const CString& key, int def = 0)const {
|
||||
return INIHelper::StringToInteger(this->GetString(key), def);
|
||||
}
|
||||
|
||||
size_t Size() const { return value_pos.size(); }
|
||||
|
||||
bool Exists(const CString& key) const {
|
||||
auto const it = value_pos.find(key);
|
||||
return it != value_pos.end();
|
||||
}
|
||||
|
||||
void Assign(const CString& key, const CString& value) {
|
||||
return this->Assign(key, CString(value));
|
||||
}
|
||||
|
||||
void Assign(const CString& key, CString&& value) {
|
||||
auto const it = value_pos.find(key);
|
||||
// new, never had one
|
||||
if (it == value_pos.end()) {
|
||||
this->value_pairs.push_back({ key, std::move(value) });
|
||||
value_pos[key] = value_pairs.size();
|
||||
return;
|
||||
}
|
||||
value_pairs[it->second].second = std::move(value);
|
||||
}
|
||||
|
||||
bool HasValue(const CString& val) const {
|
||||
return this->FindValue(val) >= 0;
|
||||
}
|
||||
|
||||
void RemoveAt(size_t idx) {
|
||||
ASSERT(idx < value_pairs.size());
|
||||
for (auto affectedIdx = idx + 1; affectedIdx < value_pairs.size(); ++affectedIdx) {
|
||||
auto const& kvPair = value_pairs[affectedIdx];
|
||||
auto const it = value_pos.find(kvPair.first);
|
||||
ASSERT(it != value_pos.end());
|
||||
it->second--;
|
||||
}
|
||||
auto const itErased = value_pairs.erase(value_pairs.begin() + idx);
|
||||
ASSERT(value_pos.erase(itErased->first), 1);
|
||||
}
|
||||
|
||||
auto begin() const noexcept
|
||||
{
|
||||
return values.begin();
|
||||
}
|
||||
|
||||
auto end() noexcept
|
||||
{
|
||||
return values.end();
|
||||
return value_pairs.begin();
|
||||
}
|
||||
|
||||
auto end() const noexcept
|
||||
{
|
||||
return values.end();
|
||||
return value_pairs.end();
|
||||
}
|
||||
|
||||
[[deprecated("instead use iterators or for_each")]]
|
||||
|
@ -87,28 +152,45 @@ public:
|
|||
[[deprecated("instead use iterators or for_each")]]
|
||||
const CString* GetValueName(std::size_t index) const noexcept;
|
||||
|
||||
[[deprecated("instead use iterators or for_each")]]
|
||||
const CString* GetValue(std::size_t index) const noexcept;
|
||||
|
||||
[[deprecated("instead use iterators or for_each")]]
|
||||
CString* GetValue(std::size_t index) noexcept;
|
||||
|
||||
public:
|
||||
map<CString, CString, SortDummy> values;
|
||||
map<CString, int, SortDummy> value_orig_pos;
|
||||
private:
|
||||
map<CString, int, SortDummy> value_pos{};
|
||||
vector<std::pair<CString, CString>> value_pairs{};// sequenced
|
||||
mutable bool isRegistry{false};
|
||||
};
|
||||
|
||||
class CIniFile
|
||||
{
|
||||
static const CIniFileSection EmptySection;
|
||||
|
||||
public:
|
||||
void DeleteEndingSpaces(BOOL bValueNames, BOOL bValues);
|
||||
void DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues);
|
||||
|
||||
const CString* GetSectionName(std::size_t Index) const noexcept;
|
||||
const CIniFileSection* GetSection(std::size_t index) const;
|
||||
CIniFileSection* GetSection(std::size_t index);
|
||||
const CIniFileSection* GetSection(const CString& section) const;
|
||||
CIniFileSection* GetSection(const CString& section);
|
||||
const CIniFileSection* TryGetSection(std::size_t index) const;
|
||||
CIniFileSection* TryGetSection(std::size_t index);
|
||||
|
||||
const CIniFileSection* TryGetSection(const CString& section) const
|
||||
{
|
||||
auto pMutThis = const_cast<std::remove_cv_t<std::remove_pointer_t<decltype(this)>>*>(this);
|
||||
return pMutThis->TryGetSection(section);
|
||||
}
|
||||
|
||||
CIniFileSection* TryGetSection(const CString& section)
|
||||
{
|
||||
auto it = sections.find(section);
|
||||
if (it != sections.end()) {
|
||||
return &it->second;
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const CIniFileSection& GetSection(const CString& section) const {
|
||||
auto const it = sections.find(section);
|
||||
if (it != sections.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return EmptySection;
|
||||
}
|
||||
|
||||
CString GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const;
|
||||
void Clear();
|
||||
WORD InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces = FALSE);
|
||||
|
@ -118,6 +200,32 @@ public:
|
|||
WORD LoadFile(const CString& filename, BOOL bNoSpaces = FALSE);
|
||||
WORD LoadFile(const std::string& filename, BOOL bNoSpaces = FALSE);
|
||||
|
||||
const CString& GetString(const CString& section, const CString& key) const {
|
||||
auto const it = sections.find(section);
|
||||
if (it != sections.end()) {
|
||||
return it->second.GetString(key);
|
||||
}
|
||||
return CIniFileSection::EmptyValue;
|
||||
}
|
||||
const bool GetBool(const CString& section, const CString& key, bool def = false) const {
|
||||
auto const& str = this->GetString(section, key);
|
||||
return INIHelper::StingToBool(str, def);
|
||||
}
|
||||
|
||||
void Assign(const CString& section, const CString& key, CString&& value) {
|
||||
auto const it = sections.find(section);
|
||||
if (it != sections.end()) {
|
||||
it->second.Assign(key, value);
|
||||
return;
|
||||
}
|
||||
auto&& newSec = CIniFileSection{};
|
||||
newSec.Assign(key, value);
|
||||
ASSERT(sections.insert({ key, std::move(newSec) }).second == true);
|
||||
}
|
||||
|
||||
void Assign(const CString& section, const CString& key, const CString& value) {
|
||||
return this->Assign(section, key, CString(value));
|
||||
}
|
||||
|
||||
auto begin() noexcept
|
||||
{
|
||||
|
@ -139,12 +247,12 @@ public:
|
|||
return sections.end();
|
||||
}
|
||||
|
||||
map<CString, CIniFileSection> sections;
|
||||
CIniFile();
|
||||
virtual ~CIniFile();
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
map<CString, CIniFileSection> sections;
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_INIFILE_H__96455620_6528_11D3_99E0_DB2A1EF71411__INCLUDED_)
|
||||
|
|
31
MissionEditor/IniHelper.h
Normal file
31
MissionEditor/IniHelper.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#pragma once
|
||||
#include <CString>
|
||||
#include <ctype.h>
|
||||
|
||||
class INIHelper
|
||||
{
|
||||
public:
|
||||
static bool StingToBool(const CString& str, bool def)
|
||||
{
|
||||
switch (toupper(static_cast<unsigned char>(*str))) {
|
||||
case '1':
|
||||
case 'T':
|
||||
case 'Y':
|
||||
return true;
|
||||
case '0':
|
||||
case 'F':
|
||||
case 'N':
|
||||
return false;
|
||||
default:
|
||||
return def;
|
||||
}
|
||||
}
|
||||
static int StringToInteger(const CString& str, int def)
|
||||
{
|
||||
int ret = 0;
|
||||
if (sscanf_s(str, "%d", &ret) == 1) {
|
||||
return ret;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue