Cuberite
A lightweight, fast and extensible game server for Minecraft
IniFile.cpp
Go to the documentation of this file.
1 // IniFile.cpp: Implementation of the CIniFile class.
2 // Written by: Adam Clauss
3 // Email: cabadam@houston.rr.com
4 // You may use this class / code as you wish in your programs. Feel free to distribute it, and
5 // email suggested changes to me.
6 //
7 // Rewritten by: Shane Hill
8 // Date: 2001-08-21
9 // Email: Shane.Hill@dsto.defence.gov.au
10 // Reason: Remove dependancy on MFC. Code should compile on any
11 // platform.
13 
14 /*
15 !! MODIFIED BY FAKETRUTH and xoft !!
16 */
17 
18 #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
19 
20 // C++ Includes
21 #include <fstream>
22 
23 // C Includes
24 #include <ctype.h>
25 
26 // Local Includes
27 #include "IniFile.h"
28 
29 #if defined(WIN32)
30  #define iniEOL endl
31 #else
32  #define iniEOL '\r' << endl
33 #endif
34 
35 using namespace std;
36 
37 
38 
39 
40 
42  m_IsCaseInsensitive(true)
43 {
44 }
45 
46 
47 
48 
49 
50 bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
51 {
52 
53  m_Filename = a_FileName;
54 
55  // Normally you would use ifstream, but the SGI CC compiler has
56  // a few bugs with ifstream. So ... fstream used.
57  fstream f;
58  AString line;
59  AString keyname, valuename, value;
60  AString::size_type pLeft, pRight;
61  bool IsFromExampleRedirect = false;
62 
63 
64  f.open((a_FileName).c_str(), ios::in);
65  if (f.fail())
66  {
67  f.clear();
68  if (a_AllowExampleRedirect)
69  {
70  // Retry with the .example.ini file instead of .ini:
71  AString ExPath(a_FileName.substr(0, a_FileName.length() - 4));
72  ExPath.append(".example.ini");
73  f.open((ExPath).c_str(), ios::in);
74  if (f.fail())
75  {
76  return false;
77  }
78  IsFromExampleRedirect = true;
79  }
80  else
81  {
82  return false;
83  }
84  }
85 
86  bool IsFirstLine = true;
87 
88  while (getline(f, line))
89  {
90  // To be compatible with Win32, check for existence of '\r'.
91  // Win32 files have the '\r' and Unix files don't at the end of a line.
92  // Note that the '\r' will be written to INI files from
93  // Unix so that the created INI file can be read under Win32
94  // without change.
95 
96  // Removes UTF-8 Byte Order Markers (BOM) if, present.
97  if (IsFirstLine)
98  {
99  RemoveBom(line);
100  IsFirstLine = false;
101  }
102 
103  size_t lineLength = line.length();
104  if (lineLength == 0)
105  {
106  continue;
107  }
108  if (line[lineLength - 1] == '\r')
109  {
110  line = line.substr(0, lineLength - 1);
111  }
112 
113  if (line.length() == 0)
114  {
115  continue;
116  }
117 
118  // Check that the user hasn't opened a binary file by checking the first
119  // character of each line!
120  if (!isprint(line[0]))
121  {
122  printf("%s: Binary-check failed on char %d\n", __FUNCTION__, line[0]);
123  f.close();
124  return false;
125  }
126  if ((pLeft = line.find_first_of(";#[=")) == AString::npos)
127  {
128  continue;
129  }
130 
131  switch (line[pLeft])
132  {
133  case '[':
134  {
135  if (
136  ((pRight = line.find_last_of("]")) != AString::npos) &&
137  (pRight > pLeft)
138  )
139  {
140  keyname = line.substr(pLeft + 1, pRight - pLeft - 1);
141  AddKeyName(keyname);
142  }
143  break;
144  }
145 
146  case '=':
147  {
148  valuename = line.substr(0, pLeft);
149  value = TrimString(line.substr(pLeft + 1));
150  ReplaceString(value, "\\n", "\n");
151  AddValue(keyname, valuename, value);
152  break;
153  }
154 
155  case ';':
156  case '#':
157  {
158  if (m_Names.empty())
159  {
160  AddHeaderComment(line.substr(pLeft + 1));
161  }
162  else
163  {
164  AddKeyComment(keyname, line.substr(pLeft + 1));
165  }
166  break;
167  }
168  } // switch (line[pLeft])
169  } // while (getline())
170 
171  f.close();
172  if (m_Keys.empty() && m_Names.empty() && m_Comments.empty())
173  {
174  // File be empty or unreadable, equivalent to nonexistant
175  return false;
176  }
177 
178  if (IsFromExampleRedirect)
179  {
180  WriteFile(a_FileName);
181  }
182 
183  return true;
184 }
185 
186 
187 
188 
189 
190 bool cIniFile::WriteFile(const AString & a_FileName) const
191 {
192  // Normally you would use ofstream, but the SGI CC compiler has
193  // a few bugs with ofstream. So ... fstream used.
194  fstream f;
195  AString writevalue;
196 
197  f.open((a_FileName).c_str(), ios::out);
198  if (f.fail())
199  {
200  return false;
201  }
202 
203  // Write header comments.
204  size_t NumComments = m_Comments.size();
205  for (size_t commentID = 0; commentID < NumComments; ++commentID)
206  {
207  f << ';' << m_Comments[commentID] << iniEOL;
208  }
209  if (NumComments > 0)
210  {
211  f << iniEOL;
212  }
213 
214  // Write keys and values.
215  for (size_t keyID = 0; keyID < m_Keys.size(); ++keyID)
216  {
217  f << '[' << m_Names[keyID] << ']' << iniEOL;
218 
219  // Comments.
220  for (size_t commentID = 0; commentID < m_Keys[keyID].m_Comments.size(); ++commentID)
221  {
222  f << ';' << m_Keys[keyID].m_Comments[commentID] << iniEOL;
223  }
224 
225  // Values.
226  for (size_t valueID = 0; valueID < m_Keys[keyID].m_Names.size(); ++valueID)
227  {
228  writevalue = m_Keys[keyID].m_Values[valueID];
229  ReplaceString(writevalue, "\n", "\\n");
230  f << m_Keys[keyID].m_Names[valueID] << '=' << writevalue << iniEOL;
231  }
232  f << iniEOL;
233  }
234  f.close();
235 
236  return true;
237 }
238 
239 
240 
241 
242 
243 int cIniFile::FindKey(const AString & a_KeyName) const
244 {
245  AString CaseKeyName = CheckCase(a_KeyName);
246  for (size_t keyID = 0; keyID < m_Names.size(); ++keyID)
247  {
248  if (CheckCase(m_Names[keyID]) == CaseKeyName)
249  {
250  return static_cast<int>(keyID);
251  }
252  }
253  return noID;
254 }
255 
256 
257 
258 
259 
260 int cIniFile::FindValue(const int keyID, const AString & a_ValueName) const
261 {
262  if (!m_Keys.size() || (keyID >= static_cast<int>(m_Keys.size())))
263  {
264  return noID;
265  }
266 
267  AString CaseValueName = CheckCase(a_ValueName);
268  for (size_t valueID = 0; valueID < m_Keys[static_cast<size_t>(keyID)].m_Names.size(); ++valueID)
269  {
270  if (CheckCase(m_Keys[static_cast<size_t>(keyID)].m_Names[valueID]) == CaseValueName)
271  {
272  return int(valueID);
273  }
274  }
275  return noID;
276 }
277 
278 
279 
280 
281 
282 int cIniFile::AddKeyName(const AString & keyname)
283 {
284  m_Names.resize(m_Names.size() + 1, keyname);
285  m_Keys.resize(m_Keys.size() + 1);
286  return static_cast<int>(m_Names.size()) - 1;
287 }
288 
289 
290 
291 
292 
293 AString cIniFile::GetKeyName(const int keyID) const
294 {
295  if (keyID < static_cast<int>(m_Names.size()))
296  {
297  return m_Names[static_cast<size_t>(keyID)];
298  }
299  else
300  {
301  return "";
302  }
303 }
304 
305 
306 
307 
308 
309 int cIniFile::GetNumValues(const int keyID) const
310 {
311  if (keyID < static_cast<int>(m_Keys.size()))
312  {
313  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size());
314  }
315  return 0;
316 }
317 
318 
319 
320 
321 
322 int cIniFile::GetNumValues(const AString & keyname) const
323 {
324  int keyID = FindKey(keyname);
325  if (keyID == noID)
326  {
327  return 0;
328  }
329  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size());
330 }
331 
332 
333 
334 
335 
336 AString cIniFile::GetValueName(const int keyID, const int valueID) const
337 {
338  if ((keyID < static_cast<int>(m_Keys.size())) && (valueID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size())))
339  {
340  return m_Keys[static_cast<size_t>(keyID)].m_Names[static_cast<size_t>(valueID)];
341  }
342  return "";
343 }
344 
345 
346 
347 
348 
349 AString cIniFile::GetValueName(const AString & keyname, const int valueID) const
350 {
351  int keyID = FindKey(keyname);
352  if (keyID == noID)
353  {
354  return "";
355  }
356  return GetValueName(keyID, valueID);
357 }
358 
359 
360 
361 
362 
363 void cIniFile::AddValue(const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value)
364 {
365  int keyID = FindKey(a_KeyName);
366  if (keyID == noID)
367  {
368  keyID = int(AddKeyName(a_KeyName));
369  }
370 
371  m_Keys[static_cast<size_t>(keyID)].m_Names.push_back(a_ValueName);
372  m_Keys[static_cast<size_t>(keyID)].m_Values.push_back(a_Value);
373 }
374 
375 
376 
377 
378 
379 void cIniFile::AddValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value)
380 {
381  AddValue(a_KeyName, a_ValueName, fmt::format(FMT_STRING("{}"), a_Value));
382 }
383 
384 
385 
386 
387 
388 void cIniFile::AddValueF(const AString & a_KeyName, const AString & a_ValueName, const double a_Value)
389 {
390  AddValue(a_KeyName, a_ValueName, fmt::format(FMT_STRING("{}"), a_Value));
391 }
392 
393 
394 
395 
396 
397 bool cIniFile::SetValue(const int keyID, const int valueID, const AString & value)
398 {
399  if ((static_cast<size_t>(keyID) >= m_Keys.size()) || (static_cast<size_t>(valueID) >= m_Keys[static_cast<size_t>(keyID)].m_Names.size()))
400  {
401  return false;
402  }
403  m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)] = value;
404  return true;
405 }
406 
407 
408 
409 
410 
411 bool cIniFile::SetValue(const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists)
412 {
413  int keyID = FindKey(a_KeyName);
414  if (keyID == noID)
415  {
416  if (!a_CreateIfNotExists)
417  {
418  return false;
419  }
420  keyID = AddKeyName(a_KeyName);
421  }
422 
423  int valueID = FindValue(keyID, a_ValueName);
424  if (valueID == noID)
425  {
426  if (!a_CreateIfNotExists)
427  {
428  return false;
429  }
430  m_Keys[static_cast<size_t>(keyID)].m_Names.push_back(a_ValueName);
431  m_Keys[static_cast<size_t>(keyID)].m_Values.push_back(a_Value);
432  }
433  else
434  {
435  m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)] = a_Value;
436  }
437 
438  return true;
439 }
440 
441 
442 
443 
444 
445 bool cIniFile::SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists)
446 {
447  return SetValue(a_KeyName, a_ValueName, fmt::format(FMT_STRING("{}"), a_Value), a_CreateIfNotExists);
448 }
449 
450 
451 
452 
453 
454 bool cIniFile::SetValueI(const AString & a_Keyname, const AString & a_ValueName, const Int64 a_Value, const bool a_CreateIfNotExists)
455 {
456  return SetValue(a_Keyname, a_ValueName, fmt::format(FMT_STRING("{}"), a_Value), a_CreateIfNotExists);
457 }
458 
459 
460 
461 
462 
463 bool cIniFile::SetValueF(const AString & a_KeyName, const AString & a_ValueName, double const a_Value, const bool a_CreateIfNotExists)
464 {
465  return SetValue(a_KeyName, a_ValueName, fmt::format(FMT_STRING("{}"), a_Value), a_CreateIfNotExists);
466 }
467 
468 
469 
470 
471 
472 AString cIniFile::GetValue(const int keyID, const int valueID, const AString & defValue) const
473 {
474  if ((keyID < static_cast<int>(m_Keys.size())) && (valueID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size())))
475  {
476  return m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)];
477  }
478  return defValue;
479 }
480 
481 
482 
483 
484 
485 AString cIniFile::GetValue(const AString & keyname, const AString & valuename, const AString & defValue) const
486 {
487  int keyID = FindKey(keyname);
488  if (keyID == noID)
489  {
490  return defValue;
491  }
492 
493  int valueID = FindValue(int(keyID), valuename);
494  if (valueID == noID)
495  {
496  return defValue;
497  }
498 
499  return m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)];
500 }
501 
502 
503 
504 
505 
506 int cIniFile::GetValueI(const AString & keyname, const AString & valuename, const int defValue) const
507 {
508  auto Data = fmt::format(FMT_STRING("{}"), defValue);
509  return atoi(GetValue(keyname, valuename, Data).c_str());
510 }
511 
512 
513 
514 
515 
516 double cIniFile::GetValueF(const AString & keyname, const AString & valuename, double const defValue) const
517 {
518  auto Data = fmt::format(FMT_STRING("{}"), defValue);
519  return atof(GetValue(keyname, valuename, Data).c_str());
520 }
521 
522 
523 
524 
525 
526 AString cIniFile::GetValueSet(const AString & keyname, const AString & valuename, const AString & defValue)
527 {
528  int keyID = FindKey(keyname);
529  if (keyID == noID)
530  {
531  SetValue(keyname, valuename, defValue);
532  return defValue;
533  }
534 
535  int valueID = FindValue(int(keyID), valuename);
536  if (valueID == noID)
537  {
538  SetValue(keyname, valuename, defValue);
539  return defValue;
540  }
541 
542  return m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)];
543 }
544 
545 
546 
547 
548 
549 double cIniFile::GetValueSetF(const AString & keyname, const AString & valuename, const double defValue)
550 {
551  auto Data = fmt::format(FMT_STRING("{}"), defValue);
552  return atof(GetValueSet(keyname, valuename, Data).c_str());
553 }
554 
555 
556 
557 
558 
559 int cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, const int defValue)
560 {
561  auto Data = fmt::format(FMT_STRING("{}"), defValue);
562  return atoi(GetValueSet(keyname, valuename, Data).c_str());
563 }
564 
565 
566 
567 
568 
569 Int64 cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, const Int64 defValue)
570 {
571  auto Data = fmt::format(FMT_STRING("{}"), defValue);
572  AString resultstring = GetValueSet(keyname, valuename, Data);
573  Int64 result = defValue;
574 #ifdef _WIN32
575  sscanf_s(resultstring.c_str(), "%lld", &result);
576 #else
577  sscanf(resultstring.c_str(), "%lld", &result);
578 #endif
579  return result;
580 }
581 
582 
583 
584 
585 
586 bool cIniFile::DeleteValueByID(const int keyID, const int valueID)
587 {
588  if ((keyID < static_cast<int>(m_Keys.size())) && (valueID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size())))
589  {
590  // This looks strange, but is neccessary.
591  vector<AString>::iterator npos = m_Keys[static_cast<size_t>(keyID)].m_Names.begin() + valueID;
592  vector<AString>::iterator vpos = m_Keys[static_cast<size_t>(keyID)].m_Values.begin() + valueID;
593  m_Keys[static_cast<size_t>(keyID)].m_Names.erase(npos, npos + 1);
594  m_Keys[static_cast<size_t>(keyID)].m_Values.erase(vpos, vpos + 1);
595  return true;
596  }
597  return false;
598 }
599 
600 
601 
602 
603 
604 bool cIniFile::DeleteValue(const AString & keyname, const AString & valuename)
605 {
606  int keyID = FindKey(keyname);
607  if (keyID == noID)
608  {
609  return false;
610  }
611 
612  int valueID = FindValue(int(keyID), valuename);
613  if (valueID == noID)
614  {
615  return false;
616  }
617 
618  return DeleteValueByID(keyID, valueID);
619 }
620 
621 
622 
623 
624 
625 bool cIniFile::DeleteKey(const AString & keyname)
626 {
627  int keyID = FindKey(keyname);
628  if (keyID == noID)
629  {
630  return false;
631  }
632 
633  vector<AString>::iterator npos = m_Names.begin() + keyID;
634  vector<key>::iterator kpos = m_Keys.begin() + keyID;
635  m_Names.erase(npos, npos + 1);
636  m_Keys.erase(kpos, kpos + 1);
637 
638  return true;
639 }
640 
641 
642 
643 
644 
645 void cIniFile::Clear(void)
646 {
647  m_Names.clear();
648  m_Keys.clear();
649  m_Comments.clear();
650 }
651 
652 
653 
654 
655 
656 bool cIniFile::HasValue(const AString & a_KeyName, const AString & a_ValueName) const
657 {
658  // Find the key:
659  int keyID = FindKey(a_KeyName);
660  if (keyID == noID)
661  {
662  return false;
663  }
664 
665  // Find the value:
666  int valueID = FindValue(keyID, a_ValueName);
667  return (valueID != noID);
668 }
669 
670 
671 
672 
673 
674 void cIniFile::AddHeaderComment(const AString & comment)
675 {
676  m_Comments.push_back(comment);
677  // comments.resize(comments.size() + 1, comment);
678 }
679 
680 
681 
682 
683 
684 AString cIniFile::GetHeaderComment(const int commentID) const
685 {
686  if (commentID < static_cast<int>(m_Comments.size()))
687  {
688  return m_Comments[static_cast<size_t>(commentID)];
689  }
690  return "";
691 }
692 
693 
694 
695 
696 
697 bool cIniFile::DeleteHeaderComment(int commentID)
698 {
699  if (commentID < static_cast<int>(m_Comments.size()))
700  {
701  vector<AString>::iterator cpos = m_Comments.begin() + commentID;
702  m_Comments.erase(cpos, cpos + 1);
703  return true;
704  }
705  return false;
706 }
707 
708 
709 
710 
711 
712 int cIniFile::GetNumKeyComments(const int keyID) const
713 {
714  if (keyID < static_cast<int>(m_Keys.size()))
715  {
716  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size());
717  }
718  return 0;
719 }
720 
721 
722 
723 
724 
725 int cIniFile::GetNumKeyComments(const AString & keyname) const
726 {
727  int keyID = FindKey(keyname);
728  if (keyID == noID)
729  {
730  return 0;
731  }
732  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size());
733 }
734 
735 
736 
737 
738 
739 bool cIniFile::AddKeyComment(const int keyID, const AString & comment)
740 {
741  if (keyID < static_cast<int>(m_Keys.size()))
742  {
743  m_Keys[static_cast<size_t>(keyID)].m_Comments.resize(m_Keys[static_cast<size_t>(keyID)].m_Comments.size() + 1, comment);
744  return true;
745  }
746  return false;
747 }
748 
749 
750 
751 
752 
753 bool cIniFile::AddKeyComment(const AString & keyname, const AString & comment)
754 {
755  int keyID = FindKey(keyname);
756  if (keyID == noID)
757  {
758  return false;
759  }
760  return AddKeyComment(keyID, comment);
761 }
762 
763 
764 
765 
766 
767 AString cIniFile::GetKeyComment(const int keyID, const int commentID) const
768 {
769  if ((keyID < static_cast<int>(m_Keys.size())) && (commentID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size())))
770  {
771  return m_Keys[static_cast<size_t>(keyID)].m_Comments[static_cast<size_t>(commentID)];
772  }
773  return "";
774 }
775 
776 
777 
778 
779 
780 AString cIniFile::GetKeyComment(const AString & keyname, const int commentID) const
781 {
782  int keyID = FindKey(keyname);
783  if (keyID == noID)
784  {
785  return "";
786  }
787  return GetKeyComment(int(keyID), commentID);
788 }
789 
790 
791 
792 
793 
794 bool cIniFile::DeleteKeyComment(const int keyID, const int commentID)
795 {
796  if ((keyID < static_cast<int>(m_Keys.size())) && (commentID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size())))
797  {
798  vector<AString>::iterator cpos = m_Keys[static_cast<size_t>(keyID)].m_Comments.begin() + commentID;
799  m_Keys[static_cast<size_t>(keyID)].m_Comments.erase(cpos, cpos + 1);
800  return true;
801  }
802  return false;
803 }
804 
805 
806 
807 
808 
809 bool cIniFile::DeleteKeyComment(const AString & keyname, const int commentID)
810 {
811  int keyID = FindKey(keyname);
812  if (keyID == noID)
813  {
814  return false;
815  }
816  return DeleteKeyComment(int(keyID), commentID);
817 }
818 
819 
820 
821 
822 
823 bool cIniFile::DeleteKeyComments(const int keyID)
824 {
825  if (keyID < static_cast<int>(m_Keys.size()))
826  {
827  m_Keys[static_cast<size_t>(keyID)].m_Comments.clear();
828  return true;
829  }
830  return false;
831 }
832 
833 
834 
835 
836 
838 {
839  int keyID = FindKey(keyname);
840  if (keyID == noID)
841  {
842  return false;
843  }
844  return DeleteKeyComments(static_cast<int>(keyID));
845 }
846 
847 
848 
849 
850 
852 {
853  if (!m_IsCaseInsensitive)
854  {
855  return s;
856  }
857  AString res(s);
858  size_t len = res.length();
859  for (size_t i = 0; i < len; i++)
860  {
861  res[i] = static_cast<char>(tolower(res[i]));
862  }
863  return res;
864 }
865 
866 
867 
868 
869 
870 void cIniFile::RemoveBom(AString & a_line) const
871 {
872  // The BOM sequence for UTF-8 is 0xEF, 0xBB, 0xBF
873  static unsigned const char BOM[] = { 0xEF, 0xBB, 0xBF };
874 
875  // The BOM sequence, if present, is always th e first three characters of the input.
876  const AString ref = a_line.substr(0, 3);
877 
878  // If any of the first three chars do not match, return and do nothing.
879  for (size_t i = 0; i < 3; ++i)
880  {
881  if (static_cast<unsigned char>(ref[i]) != BOM[i])
882  {
883  return;
884  }
885  }
886 
887  // First three characters match; erase them.
888  a_line.erase(0, 3);
889 }
890 
891 
892 
893 
894 
895 bool cIniFile::KeyExists(AString a_keyname) const
896 {
897  return FindKey(a_keyname) != noID;
898 }
899 
900 
901 
902 
903 
904 std::vector<std::pair<AString, AString>> cIniFile::GetValues(AString a_keyName)
905 {
906  std::vector<std::pair<AString, AString>> ret;
907  int keyID = FindKey(a_keyName);
908  if (keyID == noID)
909  {
910  return ret;
911  }
912  for (size_t valueID = 0; valueID < m_Keys[static_cast<size_t>(keyID)].m_Names.size(); ++valueID)
913  {
914  ret.emplace_back(m_Keys[static_cast<size_t>(keyID)].m_Names[valueID], m_Keys[static_cast<size_t>(keyID)].m_Values[valueID]);
915  }
916  return ret;
917 }
918 
919 
920 
921 
922 
924  cSettingsRepositoryInterface & a_Settings,
925  const AString & a_KeyName,
926  const AString & a_PortsValueName,
927  const AString & a_OldIPv4ValueName,
928  const AString & a_OldIPv6ValueName,
929  const AString & a_DefaultValue
930 )
931 {
932  // Read the regular value, but don't use the default (in order to detect missing value for upgrade):
933 
934  AStringVector Ports;
935 
936  for (const auto & pair : a_Settings.GetValues(a_KeyName))
937  {
938  if (pair.first != a_PortsValueName)
939  {
940  continue;
941  }
942  AStringVector temp = StringSplitAndTrim(pair.second, ";,");
943  Ports.insert(Ports.end(), temp.begin(), temp.end());
944  }
945 
946  if (Ports.empty())
947  {
948  // Historically there were two separate entries for IPv4 and IPv6, merge them and migrate:
949  AString Ports4 = a_Settings.GetValue(a_KeyName, a_OldIPv4ValueName, a_DefaultValue);
950  AString Ports6 = a_Settings.GetValue(a_KeyName, a_OldIPv6ValueName);
951  Ports = MergeStringVectors(StringSplitAndTrim(Ports4, ";,"), StringSplitAndTrim(Ports6, ";,"));
952  a_Settings.DeleteValue(a_KeyName, a_OldIPv4ValueName);
953  a_Settings.DeleteValue(a_KeyName, a_OldIPv6ValueName);
954 
955  // If those weren't present or were empty, use the default:"
956  if (Ports.empty())
957  {
958  Ports = StringSplitAndTrim(a_DefaultValue, ";,");
959  }
960  a_Settings.SetValue(a_KeyName, a_PortsValueName, StringsConcat(Ports, ','));
961  }
962 
963  return Ports;
964 }
965 
966 
967 
signed long long Int64
Definition: Globals.h:151
AStringVector ReadUpgradeIniPorts(cSettingsRepositoryInterface &a_Settings, const AString &a_KeyName, const AString &a_PortsValueName, const AString &a_OldIPv4ValueName, const AString &a_OldIPv6ValueName, const AString &a_DefaultValue)
Reads the list of ports from the INI file, possibly upgrading from IPv4 / IPv6-specific values into n...
Definition: IniFile.cpp:923
#define iniEOL
Definition: IniFile.cpp:32
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
AString TrimString(const AString &str)
Trims whitespace at both ends of the string.
void ReplaceString(AString &iHayStack, const AString &iNeedle, const AString &iReplaceWith)
Replaces each occurence of iNeedle in iHayStack with iReplaceWith.
AString StringsConcat(const AStringVector &a_Strings, char a_Separator)
Concatenates the specified strings into a single string, separated by the specified separator charact...
AStringVector MergeStringVectors(const AStringVector &a_Strings1, const AStringVector &a_Strings2)
Merges the two vectors of strings, removing duplicate entries from the second vector.
std::vector< AString > AStringVector
Definition: StringUtils.h:12
std::string AString
Definition: StringUtils.h:11
Definition: FastNBT.h:132
AString GetHeaderComment(const int commentID) const
Returns a header comment, or empty string if out of range.
Definition: IniFile.cpp:684
void RemoveBom(AString &a_line) const
Removes the UTF-8 BOMs (Byte order makers), if present.
Definition: IniFile.cpp:870
bool DeleteValueByID(const int keyID, const int valueID)
Definition: IniFile.cpp:586
AString m_Filename
Definition: IniFile.h:45
bool HasValue(const AString &a_KeyName, const AString &a_ValueName) const override
Returns true iff the specified value exists.
Definition: IniFile.cpp:656
int AddKeyName(const AString &keyname) override
Add a key name.
Definition: IniFile.cpp:282
AString GetKeyName(const int keyID) const
Definition: IniFile.cpp:293
bool DeleteKeyComments(const int keyID)
Definition: IniFile.cpp:823
int FindKey(const AString &keyname) const
Returns index of specified key, or noID if not found.
Definition: IniFile.cpp:243
AString GetValue(const AString &keyname, const AString &valuename, const AString &defValue="") const override
Get the value at the specified key and value, returns defValue on failure.
Definition: IniFile.cpp:485
bool WriteFile(const AString &a_FileName) const
Writes data stored in class to the specified ini file.
Definition: IniFile.cpp:190
bool m_IsCaseInsensitive
Definition: IniFile.h:43
bool AddKeyComment(const int keyID, const AString &comment)
Add a key comment.
Definition: IniFile.cpp:739
std::vector< AString > m_Comments
Definition: IniFile.h:56
int GetNumValues(const AString &keyname) const
Definition: IniFile.cpp:322
bool DeleteValue(const AString &keyname, const AString &valuename) override
Deletes the specified key, value pair.
Definition: IniFile.cpp:604
bool ReadFile(const AString &a_FileName, bool a_AllowExampleRedirect=true)
Reads the contents of the specified ini file If the file doesn't exist and a_AllowExampleRedirect is ...
Definition: IniFile.cpp:50
bool SetValueF(const AString &a_KeyName, const AString &a_ValueName, const double a_Value, const bool a_CreateIfNotExists=true)
Definition: IniFile.cpp:463
virtual bool KeyExists(const AString a_keyName) const override
Returns true iff the specified key exists.
Definition: IniFile.cpp:895
void Clear(void)
Deletes all stored ini data (but doesn't touch the file)
Definition: IniFile.cpp:645
@ noID
Definition: IniFile.h:72
virtual std::vector< std::pair< AString, AString > > GetValues(AString a_keyName) override
returns a vector containing a name, value pair for each value under the key
Definition: IniFile.cpp:904
AString GetValueName(const AString &keyname, const int valueID) const
Definition: IniFile.cpp:349
void AddValue(const AString &a_KeyName, const AString &a_ValueName, const AString &a_Value) override
Adds a new value to the specified key.
Definition: IniFile.cpp:363
int GetValueI(const AString &keyname, const AString &valuename, const int defValue=0) const
Definition: IniFile.cpp:506
bool DeleteKeyComment(const int keyID, const int commentID)
Definition: IniFile.cpp:794
void AddHeaderComment(const AString &comment)
Adds a header comment.
Definition: IniFile.cpp:674
int GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:559
bool DeleteKey(const AString &keyname)
Definition: IniFile.cpp:625
cIniFile(void)
Creates a new instance with no data.
Definition: IniFile.cpp:41
void AddValueF(const AString &a_KeyName, const AString &a_ValueName, const double a_Value)
Definition: IniFile.cpp:388
bool SetValueI(const AString &a_KeyName, const AString &a_ValueName, const int a_Value, const bool a_CreateIfNotExists=true) override
Definition: IniFile.cpp:445
bool SetValue(const int keyID, const int valueID, const AString &value)
Definition: IniFile.cpp:397
AString GetValueSet(const AString &keyname, const AString &valuename, const AString &defValue="") override
Gets the value; if not found, write the default to the repository.
Definition: IniFile.cpp:526
std::vector< AString > m_Names
Definition: IniFile.h:55
bool DeleteHeaderComment(int commentID)
Deletes a header comment.
Definition: IniFile.cpp:697
void AddValueI(const AString &a_KeyName, const AString &a_ValueName, const int a_Value)
Definition: IniFile.cpp:379
int GetNumKeyComments(const int keyID) const
Get number of key comments.
Definition: IniFile.cpp:712
double GetValueSetF(const AString &keyname, const AString &valuename, const double defValue=0.0)
Definition: IniFile.cpp:549
double GetValueF(const AString &keyname, const AString &valuename, const double defValue=0) const
Definition: IniFile.cpp:516
std::vector< key > m_Keys
Definition: IniFile.h:54
AString CheckCase(const AString &s) const
If the object is case-insensitive, returns s as lowercase; otherwise returns s as-is.
Definition: IniFile.cpp:851
int FindValue(const int keyID, const AString &valuename) const
Returns index of specified value, in the specified key, or noID if not found.
Definition: IniFile.cpp:260
AString GetKeyComment(const int keyID, const int commentID) const
Return a key comment.
Definition: IniFile.cpp:767
virtual bool DeleteValue(const AString &keyname, const AString &valuename)=0
Deletes the specified key, value pair.
virtual std::vector< std::pair< AString, AString > > GetValues(AString a_keyName)=0
returns a vector containing a name, value pair for each value under the key
virtual AString GetValue(const AString &keyname, const AString &valuename, const AString &defValue="") const =0
Get the value at the specified key and value, returns defValue on failure.
virtual bool SetValue(const AString &a_KeyName, const AString &a_ValueName, const AString &a_Value, const bool a_CreateIfNotExists=true)=0
Overwrites the value of the key, value pair Specify the optional parameter as false if you do not wan...