mirror of
https://github.com/electronicarts/CNC_TS_and_RA2_Mission_Editor.git
synced 2025-04-30 17:11:40 -04:00
Implemented IniMeta helpers to fetch combination of ini files .
This commit is contained in:
parent
d1a32df54b
commit
90fa8eb408
10 changed files with 308 additions and 4 deletions
39
MissionEditor/INIMeta.cpp
Normal file
39
MissionEditor/INIMeta.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "StdAfx.h"
|
||||
#include "INIMeta.h"
|
||||
#include <set>
|
||||
|
||||
void IniFileGroup::Append(const CIniFile& INI)
|
||||
{
|
||||
m_group.push_back(&INI);
|
||||
}
|
||||
|
||||
|
||||
const CIniFile* IniFileGroup::Nth(int idx) const
|
||||
{
|
||||
return m_group.at(idx);
|
||||
}
|
||||
|
||||
const CString& IniFileGroup::GetString(const CString & section, const CString & key) const
|
||||
{
|
||||
for (auto it = m_group.rbegin(); it != m_group.rend(); ++it) {
|
||||
auto const& got = (*it)->GetString(section, key);
|
||||
if (!got.IsEmpty()) {
|
||||
return got;
|
||||
}
|
||||
}
|
||||
return CIniFileSection::EmptyValue;
|
||||
}
|
||||
|
||||
CString IniFileGroup::GetStringOr(const CString & section, const CString & key, const CString& def) const
|
||||
{
|
||||
auto const& got = this->GetString(section, key);
|
||||
if (!got.IsEmpty()) {
|
||||
return got;
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
IniSectionGroup IniFileGroup::GetSection(const CString& section) const
|
||||
{
|
||||
return IniSectionGroup(*this, section);
|
||||
}
|
142
MissionEditor/INIMeta.h
Normal file
142
MissionEditor/INIMeta.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
#pragma once
|
||||
|
||||
#include <afx.h>
|
||||
#include "IniFile.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
using IndiceStorage = std::vector<CString>;
|
||||
using SequencedSection = std::vector<CString>;
|
||||
class IniSectionGroup;
|
||||
|
||||
/*
|
||||
* @brief This class uses to simulation a combination of a few ini dictionaries, to
|
||||
act as they are inside a same ini
|
||||
*/
|
||||
class IniFileGroup
|
||||
{
|
||||
friend class IniMegaFile;
|
||||
public:
|
||||
|
||||
using StorageType = std::vector<const CIniFile*>;
|
||||
|
||||
IniFileGroup() = default;
|
||||
|
||||
|
||||
const CString& GetString(const CString& section, const CString& key) const;
|
||||
CString GetStringOr(const CString& section, const CString& key, const CString& def) const;
|
||||
IniSectionGroup GetSection(const CString& section) const;
|
||||
|
||||
auto Size() const { return m_group.size(); }
|
||||
|
||||
void Append(const CIniFile& INI);
|
||||
const CIniFile* Nth(int idx) const;
|
||||
|
||||
auto begin() const { return m_group.begin(); }
|
||||
auto end() const { return m_group.end(); }
|
||||
bool empty() const { return m_group.empty(); }
|
||||
|
||||
private:
|
||||
StorageType m_group;
|
||||
};
|
||||
|
||||
class IniSectionGroup
|
||||
{
|
||||
using KvIter = CIniFileSection::Container::const_iterator;
|
||||
using GroupIter = IniFileGroup::StorageType::const_iterator;
|
||||
public:
|
||||
class Iterator;
|
||||
friend class Iterator;
|
||||
class Iterator {
|
||||
public:
|
||||
Iterator(const CString& section,
|
||||
GroupIter groupIter,
|
||||
GroupIter groupIterEnd,
|
||||
KvIter kvIter,
|
||||
KvIter kvIterEnd
|
||||
) :
|
||||
m_section(section),
|
||||
m_groupIter(groupIter),
|
||||
m_groupIterEnd(groupIterEnd),
|
||||
m_kvIter(kvIter),
|
||||
m_kvIterEnd(kvIterEnd)
|
||||
{
|
||||
}
|
||||
Iterator& operator++() {
|
||||
// section content still working
|
||||
if (m_kvIter != std::prev(m_kvIterEnd)) {
|
||||
m_kvIter++;
|
||||
return *this;
|
||||
}
|
||||
m_groupIter++;
|
||||
if (m_groupIter != m_groupIterEnd) {
|
||||
auto [beg, end] = IniSectionGroup::acquireNextKvGroup(m_section, m_groupIter, m_groupIterEnd);
|
||||
m_kvIter = beg;
|
||||
m_kvIterEnd = end;
|
||||
} else {
|
||||
m_kvIter = m_kvIterEnd;// to make (==) works
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto const& operator*() const {
|
||||
return *m_kvIter;
|
||||
}
|
||||
bool operator==(const Iterator& rhs) const {
|
||||
return m_groupIter == rhs.m_groupIter;
|
||||
}
|
||||
|
||||
private:
|
||||
GroupIter m_groupIter;
|
||||
GroupIter m_groupIterEnd;
|
||||
KvIter m_kvIter;
|
||||
KvIter m_kvIterEnd;
|
||||
const CString& m_section;
|
||||
};
|
||||
|
||||
IniSectionGroup(const IniFileGroup& source, const CString& secName) :
|
||||
m_source(source),
|
||||
m_section(secName)
|
||||
{
|
||||
}
|
||||
|
||||
Iterator begin() const {
|
||||
auto groupBeg = m_source.begin();
|
||||
auto [secItBeg, secItEnd] = acquireNextKvGroup(groupBeg);
|
||||
return Iterator(m_section, groupBeg, m_source.end(), secItBeg, secItEnd);
|
||||
}
|
||||
|
||||
Iterator end() const {
|
||||
auto secItEnd = KvIter{};
|
||||
if (!m_source.empty()) {
|
||||
auto const& sec = (*std::prev(m_source.end()))->GetSection(m_section);
|
||||
secItEnd = sec.end();
|
||||
}
|
||||
return Iterator(m_section, m_source.end(), m_source.end(), secItEnd, secItEnd);
|
||||
}
|
||||
|
||||
private:
|
||||
// attention: beginning iter
|
||||
static std::pair< KvIter, KvIter> acquireNextKvGroup(const CString& section, GroupIter& beg, const GroupIter end) {
|
||||
|
||||
auto secItBeg = KvIter{};
|
||||
auto secItEnd = KvIter{};
|
||||
for (; beg != end; ++beg) {
|
||||
auto const& sec = (*beg)->GetSection(section);
|
||||
if (sec.Size() == 0) {
|
||||
continue;
|
||||
}
|
||||
secItBeg = sec.begin();
|
||||
secItEnd = sec.end();
|
||||
break;
|
||||
}
|
||||
return { secItBeg, secItEnd };
|
||||
}
|
||||
|
||||
std::pair< KvIter, KvIter> acquireNextKvGroup(GroupIter& beg) const {
|
||||
return acquireNextKvGroup(m_section, beg, m_source.end());
|
||||
}
|
||||
|
||||
const IniFileGroup& m_source;
|
||||
CString m_section;
|
||||
};
|
|
@ -43,8 +43,9 @@ using std::map;
|
|||
|
||||
class CIniFileSection
|
||||
{
|
||||
static const CString EmptyValue;
|
||||
public:
|
||||
using Container = vector<std::pair<CString, CString>>;
|
||||
static const CString EmptyValue;
|
||||
|
||||
CIniFileSection();
|
||||
virtual ~CIniFileSection();
|
||||
|
@ -198,7 +199,7 @@ public:
|
|||
|
||||
private:
|
||||
map<CString, int64_t> value_pos{};
|
||||
vector<std::pair<CString, CString>> value_pairs{};// sequenced
|
||||
Container value_pairs{};// sequenced
|
||||
};
|
||||
|
||||
class CIniFile
|
||||
|
|
|
@ -498,6 +498,7 @@
|
|||
<ClCompile Include="Infantry.cpp" />
|
||||
<ClCompile Include="Info.cpp" />
|
||||
<ClCompile Include="IniFile.cpp" />
|
||||
<ClCompile Include="INIMeta.cpp" />
|
||||
<ClCompile Include="InputBox.cpp" />
|
||||
<ClCompile Include="IsoView.cpp" />
|
||||
<ClCompile Include="Lighting.cpp" />
|
||||
|
@ -609,6 +610,7 @@
|
|||
<ClInclude Include="ComboUInputDlg.h" />
|
||||
<ClInclude Include="defines.h" />
|
||||
<ClInclude Include="IniHelper.h" />
|
||||
<ClInclude Include="INIMeta.h" />
|
||||
<ClInclude Include="LineDrawer.h" />
|
||||
<ClInclude Include="DynamicGraphDlg.h" />
|
||||
<ClInclude Include="FinalSun.h" />
|
||||
|
@ -660,6 +662,7 @@
|
|||
<ClInclude Include="SingleplayerSettings.h" />
|
||||
<ClInclude Include="SpecialFlags.h" />
|
||||
<ClInclude Include="StdAfx.h" />
|
||||
<ClInclude Include="StringHelper.h" />
|
||||
<ClInclude Include="structs.h" />
|
||||
<ClInclude Include="Tags.h" />
|
||||
<ClInclude Include="TaskForce.h" />
|
||||
|
|
|
@ -282,6 +282,9 @@
|
|||
<ClCompile Include="TextDrawer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="INIMeta.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="MissionEditor.rc">
|
||||
|
@ -568,6 +571,12 @@
|
|||
<ClInclude Include="IniHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StringHelper.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="INIMeta.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="res\clifftoo.bmp">
|
||||
|
|
25
MissionEditor/StringHelper.h
Normal file
25
MissionEditor/StringHelper.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <afx.h>
|
||||
#include <vector>
|
||||
|
||||
namespace utilities {
|
||||
static std::vector<CString> split_string(const CString& pSource, TCHAR cSplit = ',')
|
||||
{
|
||||
std::vector<CString> ret;
|
||||
CString tmp = pSource;
|
||||
int pos = 0;
|
||||
|
||||
while ((pos = tmp.Find(cSplit)) != -1) {
|
||||
ret.push_back(tmp.Left(pos));
|
||||
tmp = tmp.Mid(pos + 1);
|
||||
}
|
||||
|
||||
if (!tmp.IsEmpty()) {
|
||||
ret.push_back(tmp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
70
UnitTest/CIni_Meta_Test.cpp
Normal file
70
UnitTest/CIni_Meta_Test.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "stdafx.h"
|
||||
#include "../MissionEditor/INIMeta.h"
|
||||
|
||||
#if 1
|
||||
TEST(IniFileGroup, ValidIniWithValidContentTest) {
|
||||
CIniFile iniFile1;
|
||||
CIniFile iniFile2;
|
||||
|
||||
const CString referenceList[] = {
|
||||
CString("GANCST"),
|
||||
CString("GAPOWR"),
|
||||
CString("NACNST"),
|
||||
CString("NAPOWR"),
|
||||
};
|
||||
|
||||
iniFile1.SetString("BuildingTypes", "0", "GANCST");
|
||||
iniFile1.SetString("BuildingTypes", "1", "GAPOWR");
|
||||
iniFile1.SetString("GACNST", "Strength", "1000");
|
||||
iniFile1.SetString("E2", "Strength", "100");
|
||||
|
||||
iniFile2.SetString("BuildingTypes", "2", "NACNST");
|
||||
iniFile2.SetString("BuildingTypes", "3", "NAPOWR");
|
||||
iniFile2.SetString("GACNST", "Strength", "2000");
|
||||
iniFile2.SetString("NEWIFV", "Cost", "1000");
|
||||
|
||||
IniFileGroup group;
|
||||
group.Append(iniFile1);
|
||||
group.Append(iniFile2);
|
||||
|
||||
auto const bldTypes = group.GetSection("BuildingTypes");
|
||||
auto idx = 0;
|
||||
//for (auto const& [key, val] : bldTypes) {
|
||||
for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) {
|
||||
auto const& [key, val] = *it;
|
||||
EXPECT_EQ(val, referenceList[idx++]);
|
||||
}
|
||||
|
||||
EXPECT_EQ(group.GetString("GACNST", "Strength"), "2000");
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(IniFileGroup, EmptyIniContentTest) {
|
||||
CIniFile iniFile1;
|
||||
CIniFile iniFile2;
|
||||
IniFileGroup group;
|
||||
|
||||
group.Append(iniFile1);
|
||||
group.Append(iniFile2);
|
||||
|
||||
auto const bldTypes = group.GetSection("BuildingTypes");
|
||||
auto contentCount = 0;
|
||||
for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) {
|
||||
auto const& [key, val] = *it;
|
||||
cout << key << "=" << val << endl;
|
||||
contentCount++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(contentCount, 0);
|
||||
|
||||
iniFile1.SetString("BuildingTypes", "0", "GANCST");
|
||||
|
||||
contentCount = 0;
|
||||
for (auto it = bldTypes.begin(); it != bldTypes.end(); ++it) {
|
||||
auto const& [key, val] = *it;
|
||||
cout << key << "=" << val << endl;
|
||||
contentCount++;
|
||||
}
|
||||
|
||||
EXPECT_EQ(contentCount, 1);
|
||||
}
|
|
@ -27,6 +27,9 @@
|
|||
#include <iostream>
|
||||
#include <afxwin.h>
|
||||
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
#if !defined(ASSERT)
|
||||
#define ASSERT(x) if (!(x)) throw("assertion failed");
|
||||
#endif
|
|
@ -102,9 +102,9 @@
|
|||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>_DEBUG;NOMINMAX;_CONSOLE;_AFXDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)googletest\x64\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir)googletest\x64\include;$(SolutionDir)MissionEditorPackLib;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeader>Create</PrecompiledHeader>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<LanguageStandard>stdcpp20</LanguageStandard>
|
||||
|
@ -133,11 +133,14 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\MissionEditor\IniFile.cpp" />
|
||||
<ClCompile Include="..\MissionEditor\INIMeta.cpp" />
|
||||
<ClCompile Include="CIni_Meta_Test.cpp" />
|
||||
<ClCompile Include="CIni_Test.cpp" />
|
||||
<ClCompile Include="UnitTest.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\MissionEditor\IniFile.h" />
|
||||
<ClInclude Include="..\MissionEditor\INIMeta.h" />
|
||||
<ClInclude Include="StdAfx.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
|
|
@ -24,6 +24,12 @@
|
|||
<ClCompile Include="..\MissionEditor\IniFile.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CIni_Meta_Test.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\MissionEditor\INIMeta.cpp">
|
||||
<Filter>源文件</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="StdAfx.h">
|
||||
|
@ -32,5 +38,8 @@
|
|||
<ClInclude Include="..\MissionEditor\IniFile.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\MissionEditor\INIMeta.h">
|
||||
<Filter>头文件</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Add table
Reference in a new issue