IniFile.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  2. FinalSun/FinalAlert 2 Mission Editor
  3. Copyright (C) 1999-2024 Electronic Arts, Inc.
  4. Authored by Matthias Wagner
  5. This program is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. */
  16. // IniFile.cpp: Implementierung der Klasse CIniFile.
  17. //
  18. //////////////////////////////////////////////////////////////////////
  19. #include "stdafx.h"
  20. #include "IniFile.h"
  21. #include <string>
  22. #include <algorithm>
  23. #include <stdexcept>
  24. #ifdef _DEBUG
  25. #undef THIS_FILE
  26. static char THIS_FILE[] = __FILE__;
  27. #define new DEBUG_NEW
  28. #endif
  29. using namespace std;
  30. bool SortDummy::operator()(const CString& x, const CString& y) const
  31. {
  32. // the length is more important than spelling (numbers!!!)...
  33. if (x.GetLength() < y.GetLength()) return true;
  34. if (x.GetLength() == y.GetLength())
  35. {
  36. if (x < y) return true;
  37. }
  38. return false;
  39. }
  40. typedef map<CString, CIniFileSection>::iterator CIniI;
  41. typedef map<CString, CString, SortDummy>::iterator SI;
  42. typedef map<CString, int, SortDummy>::iterator SII;
  43. //////////////////////////////////////////////////////////////////////
  44. // Konstruktion/Destruktion
  45. //////////////////////////////////////////////////////////////////////
  46. CIniFile::CIniFile()
  47. {
  48. Clear();
  49. }
  50. CIniFile::~CIniFile()
  51. {
  52. sections.clear();
  53. }
  54. WORD CIniFile::LoadFile(const CString& filename, BOOL bNoSpaces)
  55. {
  56. return LoadFile(std::string(filename.GetString()), bNoSpaces);
  57. }
  58. WORD CIniFile::LoadFile(const std::string& filename, BOOL bNoSpaces)
  59. {
  60. Clear();
  61. if (filename.size() == NULL) return 1;
  62. m_filename = filename;
  63. return(InsertFile(filename, NULL, bNoSpaces));
  64. }
  65. void CIniFile::Clear()
  66. {
  67. sections.clear();
  68. }
  69. CIniFileSection::CIniFileSection()
  70. {
  71. values.clear();
  72. value_orig_pos.clear();
  73. };
  74. CIniFileSection::~CIniFileSection()
  75. {
  76. values.clear();
  77. value_orig_pos.clear();
  78. };
  79. WORD CIniFile::InsertFile(const CString& filename, const char* Section, BOOL bNoSpaces)
  80. {
  81. return InsertFile(std::string(filename.GetString()), Section, bNoSpaces);
  82. }
  83. WORD CIniFile::InsertFile(const std::string& filename, const char* Section, BOOL bNoSpaces)
  84. {
  85. if (filename.size() == 0)
  86. return 1;
  87. fstream file;
  88. file.open(filename, ios::in);
  89. if (!file.good())
  90. return 2;
  91. //char cSec[256];
  92. //char cLine[4096];
  93. //memset(cSec, 0, 256);
  94. //memset(cLine, 0, 4096);
  95. CString cSec;
  96. std::string cLine;
  97. const auto npos = std::string::npos;
  98. while (!file.eof())
  99. {
  100. std::getline(file, cLine);
  101. // strip to left side of newline or comment
  102. cLine.erase(std::find_if(cLine.begin(), cLine.end(), [](const char c) { return c == '\r' || c == '\n' || c == ';'; }), cLine.end());
  103. const auto openBracket = cLine.find('[');
  104. const auto closeBracket = cLine.find(']');
  105. const auto equals = cLine.find('=');
  106. if (openBracket != npos && closeBracket != npos && openBracket < closeBracket && (equals == npos || equals > openBracket))
  107. {
  108. if ((Section != nullptr) && cSec == Section)
  109. return 0; // the section we want to insert is finished
  110. cSec = cLine.substr(openBracket + 1, closeBracket - openBracket - 1).c_str();
  111. }
  112. else if (equals != npos && !cSec.IsEmpty())
  113. {
  114. if (Section == NULL || cSec == Section)
  115. {
  116. // a value is set and we have a valid current section!
  117. CString name = cLine.substr(0, equals).c_str();
  118. CString value = cLine.substr(equals + 1, cLine.size() - equals - 1).c_str();
  119. int cuValueIndex = sections[cSec].values.size();
  120. if (bNoSpaces)
  121. {
  122. name.Trim();
  123. value.Trim();
  124. }
  125. sections[cSec].values[name] = value;
  126. sections[cSec].value_orig_pos[name] = cuValueIndex;
  127. }
  128. }
  129. }
  130. file.close();
  131. return 0;
  132. }
  133. const CIniFileSection* CIniFile::GetSection(std::size_t index) const
  134. {
  135. if (index > sections.size() - 1)
  136. return NULL;
  137. auto i = sections.cbegin();
  138. for (auto e = 0;e < index;e++)
  139. i++;
  140. return &i->second;
  141. }
  142. CIniFileSection* CIniFile::GetSection(std::size_t index)
  143. {
  144. if (index > sections.size() - 1)
  145. return NULL;
  146. CIniI i = sections.begin();
  147. for (auto e = 0;e < index;e++)
  148. i++;
  149. return &i->second;
  150. }
  151. const CIniFileSection* CIniFile::GetSection(const CString& section) const
  152. {
  153. auto it = sections.find(section);
  154. if (it == sections.end())
  155. return nullptr;
  156. return &it->second;
  157. }
  158. CIniFileSection* CIniFile::GetSection(const CString& section)
  159. {
  160. auto it = sections.find(section);
  161. if (it == sections.end())
  162. return nullptr;
  163. return &it->second;
  164. }
  165. const CString* CIniFileSection::GetValue(std::size_t index) const noexcept
  166. {
  167. if (index > values.size() - 1)
  168. return NULL;
  169. auto i = values.begin();
  170. for (auto e = 0;e < index;e++)
  171. i++;
  172. return &i->second;
  173. }
  174. CString* CIniFileSection::GetValue(std::size_t index) noexcept
  175. {
  176. if (index > values.size() - 1)
  177. return NULL;
  178. auto i = values.begin();
  179. for (auto e = 0;e < index;e++)
  180. i++;
  181. return &i->second;
  182. }
  183. CString CIniFileSection::GetValueByName(const CString& valueName, const CString& defaultValue) const
  184. {
  185. auto it = values.find(valueName);
  186. return (it == values.end()) ? defaultValue : it->second;
  187. }
  188. const CString* CIniFile::GetSectionName(std::size_t index) const noexcept
  189. {
  190. if (index > sections.size() - 1)
  191. return NULL;
  192. auto i = sections.cbegin();
  193. for (auto e = 0; e < index; ++e)
  194. i++;
  195. return &(i->first);
  196. }
  197. CString& CIniFileSection::AccessValueByName(const CString& valueName)
  198. {
  199. return values[valueName];
  200. }
  201. const CString* CIniFileSection::GetValueName(std::size_t index) const noexcept
  202. {
  203. if (index > values.size() - 1)
  204. return NULL;
  205. auto i = values.begin();
  206. for (auto e = 0; e < index; ++e)
  207. i++;
  208. return &(i->first);
  209. }
  210. BOOL CIniFile::SaveFile(const CString& filename) const
  211. {
  212. return SaveFile(std::string(filename.GetString()));
  213. }
  214. BOOL CIniFile::SaveFile(const std::string& Filename) const
  215. {
  216. fstream file;
  217. file.open(Filename, ios::out | ios::trunc);
  218. int i;
  219. for (i = 0;i < sections.size();i++)
  220. {
  221. file << "[" << (LPCTSTR)*GetSectionName(i) << "]" << endl;
  222. int e;
  223. for (e = 0;e < GetSection(i)->values.size();e++)
  224. {
  225. file << (LPCTSTR) * (GetSection(i)->GetValueName(e)) << "=" << (LPCTSTR)*GetSection(i)->GetValue(e) << endl;
  226. }
  227. file << endl;
  228. }
  229. file << endl;
  230. return TRUE;
  231. }
  232. int CIniFileSection::FindValue(CString sval) const noexcept
  233. {
  234. int i;
  235. auto it = values.cbegin();
  236. for (i = 0;i < values.size();i++)
  237. {
  238. if (sval == it->second)
  239. return i;
  240. it++;
  241. }
  242. return -1;
  243. }
  244. int CIniFileSection::FindName(CString sval) const noexcept
  245. {
  246. int i;
  247. auto it = values.cbegin();
  248. for (i = 0;i < values.size();i++)
  249. {
  250. if (sval == it->first)
  251. return i;
  252. it++;
  253. }
  254. return -1;
  255. }
  256. void CIniFile::DeleteLeadingSpaces(BOOL bValueNames, BOOL bValues)
  257. {
  258. int i;
  259. for (i = 0;i < sections.size();i++)
  260. {
  261. CIniFileSection& sec = *GetSection(i);
  262. int e;
  263. for (e = 0;e < sec.values.size();e++)
  264. {
  265. if (bValues) sec.GetValue(e)->TrimLeft();
  266. if (bValueNames)
  267. {
  268. CString value = *sec.GetValue(e);
  269. CString name = *sec.GetValueName(e);
  270. sec.values.erase(name);
  271. name.TrimLeft();
  272. sec.values[name] = value;
  273. }
  274. }
  275. }
  276. }
  277. void CIniFile::DeleteEndingSpaces(BOOL bValueNames, BOOL bValues)
  278. {
  279. int i;
  280. for (i = 0;i < sections.size();i++)
  281. {
  282. CIniFileSection& sec = *GetSection(i);
  283. int e;
  284. for (e = 0;e < sec.values.size();e++)
  285. {
  286. if (bValues) sec.GetValue(e)->TrimRight();
  287. if (bValueNames)
  288. {
  289. //CString& name=(CString&)*sec.GetValueName(e);
  290. //name.TrimRight();
  291. CString value = *sec.GetValue(e);
  292. CString name = *sec.GetValueName(e);
  293. sec.values.erase(name);
  294. name.TrimRight();
  295. sec.values[name] = value;
  296. }
  297. }
  298. }
  299. }
  300. CString CIniFile::GetValueByName(const CString& sectionName, const CString& valueName, const CString& defaultValue) const
  301. {
  302. auto section = GetSection(sectionName);
  303. if (!section)
  304. return defaultValue;
  305. return section->GetValueByName(valueName, defaultValue);
  306. }
  307. int CIniFileSection::GetValueOrigPos(int index) const noexcept
  308. {
  309. if (index > value_orig_pos.size() - 1)
  310. return -1;
  311. auto i = value_orig_pos.cbegin();
  312. for (int e = 0;e < index;e++)
  313. i++;
  314. return i->second;
  315. }