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((FILE_IO_PREFIX + 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((FILE_IO_PREFIX + 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  AddValue(keyname, valuename, value);
151  break;
152  }
153 
154  case ';':
155  case '#':
156  {
157  if (m_Names.empty())
158  {
159  AddHeaderComment(line.substr(pLeft + 1));
160  }
161  else
162  {
163  AddKeyComment(keyname, line.substr(pLeft + 1));
164  }
165  break;
166  }
167  } // switch (line[pLeft])
168  } // while (getline())
169 
170  f.close();
171  if (m_Keys.empty() && m_Names.empty() && m_Comments.empty())
172  {
173  // File be empty or unreadable, equivalent to nonexistant
174  return false;
175  }
176 
177  if (IsFromExampleRedirect)
178  {
179  WriteFile(FILE_IO_PREFIX + a_FileName);
180  }
181 
182  return true;
183 }
184 
185 
186 
187 
188 
189 bool cIniFile::WriteFile(const AString & a_FileName) const
190 {
191  // Normally you would use ofstream, but the SGI CC compiler has
192  // a few bugs with ofstream. So ... fstream used.
193  fstream f;
194 
195  f.open((FILE_IO_PREFIX + a_FileName).c_str(), ios::out);
196  if (f.fail())
197  {
198  return false;
199  }
200 
201  // Write header comments.
202  size_t NumComments = m_Comments.size();
203  for (size_t commentID = 0; commentID < NumComments; ++commentID)
204  {
205  f << ';' << m_Comments[commentID] << iniEOL;
206  }
207  if (NumComments > 0)
208  {
209  f << iniEOL;
210  }
211 
212  // Write keys and values.
213  for (size_t keyID = 0; keyID < m_Keys.size(); ++keyID)
214  {
215  f << '[' << m_Names[keyID] << ']' << iniEOL;
216 
217  // Comments.
218  for (size_t commentID = 0; commentID < m_Keys[keyID].m_Comments.size(); ++commentID)
219  {
220  f << ';' << m_Keys[keyID].m_Comments[commentID] << iniEOL;
221  }
222 
223  // Values.
224  for (size_t valueID = 0; valueID < m_Keys[keyID].m_Names.size(); ++valueID)
225  {
226  f << m_Keys[keyID].m_Names[valueID] << '=' << m_Keys[keyID].m_Values[valueID] << iniEOL;
227  }
228  f << iniEOL;
229  }
230  f.close();
231 
232  return true;
233 }
234 
235 
236 
237 
238 
239 int cIniFile::FindKey(const AString & a_KeyName) const
240 {
241  AString CaseKeyName = CheckCase(a_KeyName);
242  for (size_t keyID = 0; keyID < m_Names.size(); ++keyID)
243  {
244  if (CheckCase(m_Names[keyID]) == CaseKeyName)
245  {
246  return static_cast<int>(keyID);
247  }
248  }
249  return noID;
250 }
251 
252 
253 
254 
255 
256 int cIniFile::FindValue(const int keyID, const AString & a_ValueName) const
257 {
258  if (!m_Keys.size() || (keyID >= static_cast<int>(m_Keys.size())))
259  {
260  return noID;
261  }
262 
263  AString CaseValueName = CheckCase(a_ValueName);
264  for (size_t valueID = 0; valueID < m_Keys[static_cast<size_t>(keyID)].m_Names.size(); ++valueID)
265  {
266  if (CheckCase(m_Keys[static_cast<size_t>(keyID)].m_Names[valueID]) == CaseValueName)
267  {
268  return int(valueID);
269  }
270  }
271  return noID;
272 }
273 
274 
275 
276 
277 
278 int cIniFile::AddKeyName(const AString & keyname)
279 {
280  m_Names.resize(m_Names.size() + 1, keyname);
281  m_Keys.resize(m_Keys.size() + 1);
282  return static_cast<int>(m_Names.size()) - 1;
283 }
284 
285 
286 
287 
288 
289 AString cIniFile::GetKeyName(const int keyID) const
290 {
291  if (keyID < static_cast<int>(m_Names.size()))
292  {
293  return m_Names[static_cast<size_t>(keyID)];
294  }
295  else
296  {
297  return "";
298  }
299 }
300 
301 
302 
303 
304 
305 int cIniFile::GetNumValues(const int keyID) const
306 {
307  if (keyID < static_cast<int>(m_Keys.size()))
308  {
309  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size());
310  }
311  return 0;
312 }
313 
314 
315 
316 
317 
318 int cIniFile::GetNumValues(const AString & keyname) const
319 {
320  int keyID = FindKey(keyname);
321  if (keyID == noID)
322  {
323  return 0;
324  }
325  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size());
326 }
327 
328 
329 
330 
331 
332 AString cIniFile::GetValueName(const int keyID, const int valueID) const
333 {
334  if ((keyID < static_cast<int>(m_Keys.size())) && (valueID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size())))
335  {
336  return m_Keys[static_cast<size_t>(keyID)].m_Names[static_cast<size_t>(valueID)];
337  }
338  return "";
339 }
340 
341 
342 
343 
344 
345 AString cIniFile::GetValueName(const AString & keyname, const int valueID) const
346 {
347  int keyID = FindKey(keyname);
348  if (keyID == noID)
349  {
350  return "";
351  }
352  return GetValueName(keyID, valueID);
353 }
354 
355 
356 
357 
358 
359 void cIniFile::AddValue(const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value)
360 {
361  int keyID = FindKey(a_KeyName);
362  if (keyID == noID)
363  {
364  keyID = int(AddKeyName(a_KeyName));
365  }
366 
367  m_Keys[static_cast<size_t>(keyID)].m_Names.push_back(a_ValueName);
368  m_Keys[static_cast<size_t>(keyID)].m_Values.push_back(a_Value);
369 }
370 
371 
372 
373 
374 
375 void cIniFile::AddValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value)
376 {
377  AddValue(a_KeyName, a_ValueName, Printf("%d", a_Value));
378 }
379 
380 
381 
382 
383 
384 void cIniFile::AddValueF(const AString & a_KeyName, const AString & a_ValueName, const double a_Value)
385 {
386  AddValue(a_KeyName, a_ValueName, Printf("%f", a_Value));
387 }
388 
389 
390 
391 
392 
393 bool cIniFile::SetValue(const int keyID, const int valueID, const AString & value)
394 {
395  if ((static_cast<size_t>(keyID) >= m_Keys.size()) || (static_cast<size_t>(valueID) >= m_Keys[static_cast<size_t>(keyID)].m_Names.size()))
396  {
397  return false;
398  }
399  m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)] = value;
400  return true;
401 }
402 
403 
404 
405 
406 
407 bool cIniFile::SetValue(const AString & a_KeyName, const AString & a_ValueName, const AString & a_Value, const bool a_CreateIfNotExists)
408 {
409  int keyID = FindKey(a_KeyName);
410  if (keyID == noID)
411  {
412  if (!a_CreateIfNotExists)
413  {
414  return false;
415  }
416  keyID = AddKeyName(a_KeyName);
417  }
418 
419  int valueID = FindValue(keyID, a_ValueName);
420  if (valueID == noID)
421  {
422  if (!a_CreateIfNotExists)
423  {
424  return false;
425  }
426  m_Keys[static_cast<size_t>(keyID)].m_Names.push_back(a_ValueName);
427  m_Keys[static_cast<size_t>(keyID)].m_Values.push_back(a_Value);
428  }
429  else
430  {
431  m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)] = a_Value;
432  }
433 
434  return true;
435 }
436 
437 
438 
439 
440 
441 bool cIniFile::SetValueI(const AString & a_KeyName, const AString & a_ValueName, const int a_Value, const bool a_CreateIfNotExists)
442 {
443  return SetValue(a_KeyName, a_ValueName, Printf("%d", a_Value), a_CreateIfNotExists);
444 }
445 
446 
447 
448 
449 
450 bool cIniFile::SetValueI(const AString & a_Keyname, const AString & a_ValueName, const Int64 a_Value, const bool a_CreateIfNotExists)
451 {
452  return SetValue(a_Keyname, a_ValueName, Printf("%lld", a_Value), a_CreateIfNotExists);
453 }
454 
455 
456 
457 
458 
459 bool cIniFile::SetValueF(const AString & a_KeyName, const AString & a_ValueName, double const a_Value, const bool a_CreateIfNotExists)
460 {
461  return SetValue(a_KeyName, a_ValueName, Printf("%f", a_Value), a_CreateIfNotExists);
462 }
463 
464 
465 
466 
467 
468 AString cIniFile::GetValue(const int keyID, const int valueID, const AString & defValue) const
469 {
470  if ((keyID < static_cast<int>(m_Keys.size())) && (valueID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size())))
471  {
472  return m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)];
473  }
474  return defValue;
475 }
476 
477 
478 
479 
480 
481 AString cIniFile::GetValue(const AString & keyname, const AString & valuename, const AString & defValue) const
482 {
483  int keyID = FindKey(keyname);
484  if (keyID == noID)
485  {
486  return defValue;
487  }
488 
489  int valueID = FindValue(int(keyID), valuename);
490  if (valueID == noID)
491  {
492  return defValue;
493  }
494 
495  return m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)];
496 }
497 
498 
499 
500 
501 
502 int cIniFile::GetValueI(const AString & keyname, const AString & valuename, const int defValue) const
503 {
504  AString Data;
505  Printf(Data, "%d", defValue);
506  return atoi(GetValue(keyname, valuename, Data).c_str());
507 }
508 
509 
510 
511 
512 
513 double cIniFile::GetValueF(const AString & keyname, const AString & valuename, double const defValue) const
514 {
515  AString Data;
516  Printf(Data, "%f", defValue);
517  return atof(GetValue(keyname, valuename, Data).c_str());
518 }
519 
520 
521 
522 
523 
524 AString cIniFile::GetValueSet(const AString & keyname, const AString & valuename, const AString & defValue)
525 {
526  int keyID = FindKey(keyname);
527  if (keyID == noID)
528  {
529  SetValue(keyname, valuename, defValue);
530  return defValue;
531  }
532 
533  int valueID = FindValue(int(keyID), valuename);
534  if (valueID == noID)
535  {
536  SetValue(keyname, valuename, defValue);
537  return defValue;
538  }
539 
540  return m_Keys[static_cast<size_t>(keyID)].m_Values[static_cast<size_t>(valueID)];
541 }
542 
543 
544 
545 
546 
547 double cIniFile::GetValueSetF(const AString & keyname, const AString & valuename, const double defValue)
548 {
549  AString Data;
550  Printf(Data, "%f", defValue);
551  return atof(GetValueSet(keyname, valuename, Data).c_str());
552 }
553 
554 
555 
556 
557 
558 int cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, const int defValue)
559 {
560  AString Data;
561  Printf(Data, "%d", 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  AString Data;
572  Printf(Data, "%lld", defValue);
573  AString resultstring = GetValueSet(keyname, valuename, Data);
574  Int64 result = defValue;
575 #ifdef _WIN32
576  sscanf_s(resultstring.c_str(), "%lld", &result);
577 #else
578  sscanf(resultstring.c_str(), "%lld", &result);
579 #endif
580  return result;
581 }
582 
583 
584 
585 
586 
587 bool cIniFile::DeleteValueByID(const int keyID, const int valueID)
588 {
589  if ((keyID < static_cast<int>(m_Keys.size())) && (valueID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Names.size())))
590  {
591  // This looks strange, but is neccessary.
592  vector<AString>::iterator npos = m_Keys[static_cast<size_t>(keyID)].m_Names.begin() + valueID;
593  vector<AString>::iterator vpos = m_Keys[static_cast<size_t>(keyID)].m_Values.begin() + valueID;
594  m_Keys[static_cast<size_t>(keyID)].m_Names.erase(npos, npos + 1);
595  m_Keys[static_cast<size_t>(keyID)].m_Values.erase(vpos, vpos + 1);
596  return true;
597  }
598  return false;
599 }
600 
601 
602 
603 
604 
605 bool cIniFile::DeleteValue(const AString & keyname, const AString & valuename)
606 {
607  int keyID = FindKey(keyname);
608  if (keyID == noID)
609  {
610  return false;
611  }
612 
613  int valueID = FindValue(int(keyID), valuename);
614  if (valueID == noID)
615  {
616  return false;
617  }
618 
619  return DeleteValueByID(keyID, valueID);
620 }
621 
622 
623 
624 
625 
626 bool cIniFile::DeleteKey(const AString & keyname)
627 {
628  int keyID = FindKey(keyname);
629  if (keyID == noID)
630  {
631  return false;
632  }
633 
634  vector<AString>::iterator npos = m_Names.begin() + keyID;
635  vector<key>::iterator kpos = m_Keys.begin() + keyID;
636  m_Names.erase(npos, npos + 1);
637  m_Keys.erase(kpos, kpos + 1);
638 
639  return true;
640 }
641 
642 
643 
644 
645 
646 void cIniFile::Clear(void)
647 {
648  m_Names.clear();
649  m_Keys.clear();
650  m_Comments.clear();
651 }
652 
653 
654 
655 
656 
657 bool cIniFile::HasValue(const AString & a_KeyName, const AString & a_ValueName) const
658 {
659  // Find the key:
660  int keyID = FindKey(a_KeyName);
661  if (keyID == noID)
662  {
663  return false;
664  }
665 
666  // Find the value:
667  int valueID = FindValue(keyID, a_ValueName);
668  return (valueID != noID);
669 }
670 
671 
672 
673 
674 
675 void cIniFile::AddHeaderComment(const AString & comment)
676 {
677  m_Comments.push_back(comment);
678  // comments.resize(comments.size() + 1, comment);
679 }
680 
681 
682 
683 
684 
685 AString cIniFile::GetHeaderComment(const int commentID) const
686 {
687  if (commentID < static_cast<int>(m_Comments.size()))
688  {
689  return m_Comments[static_cast<size_t>(commentID)];
690  }
691  return "";
692 }
693 
694 
695 
696 
697 
698 bool cIniFile::DeleteHeaderComment(int commentID)
699 {
700  if (commentID < static_cast<int>(m_Comments.size()))
701  {
702  vector<AString>::iterator cpos = m_Comments.begin() + commentID;
703  m_Comments.erase(cpos, cpos + 1);
704  return true;
705  }
706  return false;
707 }
708 
709 
710 
711 
712 
713 int cIniFile::GetNumKeyComments(const int keyID) const
714 {
715  if (keyID < static_cast<int>(m_Keys.size()))
716  {
717  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size());
718  }
719  return 0;
720 }
721 
722 
723 
724 
725 
726 int cIniFile::GetNumKeyComments(const AString & keyname) const
727 {
728  int keyID = FindKey(keyname);
729  if (keyID == noID)
730  {
731  return 0;
732  }
733  return static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size());
734 }
735 
736 
737 
738 
739 
740 bool cIniFile::AddKeyComment(const int keyID, const AString & comment)
741 {
742  if (keyID < static_cast<int>(m_Keys.size()))
743  {
744  m_Keys[static_cast<size_t>(keyID)].m_Comments.resize(m_Keys[static_cast<size_t>(keyID)].m_Comments.size() + 1, comment);
745  return true;
746  }
747  return false;
748 }
749 
750 
751 
752 
753 
754 bool cIniFile::AddKeyComment(const AString & keyname, const AString & comment)
755 {
756  int keyID = FindKey(keyname);
757  if (keyID == noID)
758  {
759  return false;
760  }
761  return AddKeyComment(keyID, comment);
762 }
763 
764 
765 
766 
767 
768 AString cIniFile::GetKeyComment(const int keyID, const int commentID) const
769 {
770  if ((keyID < static_cast<int>(m_Keys.size())) && (commentID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size())))
771  {
772  return m_Keys[static_cast<size_t>(keyID)].m_Comments[static_cast<size_t>(commentID)];
773  }
774  return "";
775 }
776 
777 
778 
779 
780 
781 AString cIniFile::GetKeyComment(const AString & keyname, const int commentID) const
782 {
783  int keyID = FindKey(keyname);
784  if (keyID == noID)
785  {
786  return "";
787  }
788  return GetKeyComment(int(keyID), commentID);
789 }
790 
791 
792 
793 
794 
795 bool cIniFile::DeleteKeyComment(const int keyID, const int commentID)
796 {
797  if ((keyID < static_cast<int>(m_Keys.size())) && (commentID < static_cast<int>(m_Keys[static_cast<size_t>(keyID)].m_Comments.size())))
798  {
799  vector<AString>::iterator cpos = m_Keys[static_cast<size_t>(keyID)].m_Comments.begin() + commentID;
800  m_Keys[static_cast<size_t>(keyID)].m_Comments.erase(cpos, cpos + 1);
801  return true;
802  }
803  return false;
804 }
805 
806 
807 
808 
809 
810 bool cIniFile::DeleteKeyComment(const AString & keyname, const int commentID)
811 {
812  int keyID = FindKey(keyname);
813  if (keyID == noID)
814  {
815  return false;
816  }
817  return DeleteKeyComment(int(keyID), commentID);
818 }
819 
820 
821 
822 
823 
824 bool cIniFile::DeleteKeyComments(const int keyID)
825 {
826  if (keyID < static_cast<int>(m_Keys.size()))
827  {
828  m_Keys[static_cast<size_t>(keyID)].m_Comments.clear();
829  return true;
830  }
831  return false;
832 }
833 
834 
835 
836 
837 
839 {
840  int keyID = FindKey(keyname);
841  if (keyID == noID)
842  {
843  return false;
844  }
845  return DeleteKeyComments(static_cast<int>(keyID));
846 }
847 
848 
849 
850 
851 
853 {
854  if (!m_IsCaseInsensitive)
855  {
856  return s;
857  }
858  AString res(s);
859  size_t len = res.length();
860  for (size_t i = 0; i < len; i++)
861  {
862  res[i] = static_cast<char>(tolower(res[i]));
863  }
864  return res;
865 }
866 
867 
868 
869 
870 
871 void cIniFile::RemoveBom(AString & a_line) const
872 {
873  // The BOM sequence for UTF-8 is 0xEF, 0xBB, 0xBF
874  static unsigned const char BOM[] = { 0xEF, 0xBB, 0xBF };
875 
876  // The BOM sequence, if present, is always th e first three characters of the input.
877  const AString ref = a_line.substr(0, 3);
878 
879  // If any of the first three chars do not match, return and do nothing.
880  for (size_t i = 0; i < 3; ++i)
881  {
882  if (static_cast<unsigned char>(ref[i]) != BOM[i])
883  {
884  return;
885  }
886  }
887 
888  // First three characters match; erase them.
889  a_line.erase(0, 3);
890 }
891 
892 
893 
894 
895 
896 bool cIniFile::KeyExists(AString a_keyname) const
897 {
898  return FindKey(a_keyname) != noID;
899 }
900 
901 
902 
903 
904 
905 std::vector<std::pair<AString, AString>> cIniFile::GetValues(AString a_keyName)
906 {
907  std::vector<std::pair<AString, AString>> ret;
908  int keyID = FindKey(a_keyName);
909  if (keyID == noID)
910  {
911  return ret;
912  }
913  for (size_t valueID = 0; valueID < m_Keys[static_cast<size_t>(keyID)].m_Names.size(); ++valueID)
914  {
915  ret.emplace_back(m_Keys[static_cast<size_t>(keyID)].m_Names[valueID], m_Keys[static_cast<size_t>(keyID)].m_Values[valueID]);
916  }
917  return ret;
918 }
919 
920 
921 
922 
923 
925  cSettingsRepositoryInterface & a_Settings,
926  const AString & a_KeyName,
927  const AString & a_PortsValueName,
928  const AString & a_OldIPv4ValueName,
929  const AString & a_OldIPv6ValueName,
930  const AString & a_DefaultValue
931 )
932 {
933  // Read the regular value, but don't use the default (in order to detect missing value for upgrade):
934 
935  AStringVector Ports;
936 
937  for (auto pair : a_Settings.GetValues(a_KeyName))
938  {
939  if (pair.first != a_PortsValueName)
940  {
941  continue;
942  }
943  AStringVector temp = StringSplitAndTrim(pair.second, ";,");
944  Ports.insert(Ports.end(), temp.begin(), temp.end());
945  }
946 
947  if (Ports.empty())
948  {
949  // Historically there were two separate entries for IPv4 and IPv6, merge them and migrate:
950  AString Ports4 = a_Settings.GetValue(a_KeyName, a_OldIPv4ValueName, a_DefaultValue);
951  AString Ports6 = a_Settings.GetValue(a_KeyName, a_OldIPv6ValueName);
952  Ports = MergeStringVectors(StringSplitAndTrim(Ports4, ";,"), StringSplitAndTrim(Ports6, ";,"));
953  a_Settings.DeleteValue(a_KeyName, a_OldIPv4ValueName);
954  a_Settings.DeleteValue(a_KeyName, a_OldIPv6ValueName);
955 
956  // If those weren't present or were empty, use the default:"
957  if (Ports.empty())
958  {
959  Ports = StringSplitAndTrim(a_DefaultValue, ";,");
960  }
961  a_Settings.SetValue(a_KeyName, a_PortsValueName, StringsConcat(Ports, ','));
962  }
963 
964  return Ports;
965 }
966 
967 
968 
Definition: FastNBT.h:131
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...
bool DeleteKeyComments(const int keyID)
Definition: IniFile.cpp:824
double GetValueSetF(const AString &keyname, const AString &valuename, const double defValue=0.0)
Definition: IniFile.cpp:547
void AddValueI(const AString &a_KeyName, const AString &a_ValueName, const int a_Value)
Definition: IniFile.cpp:375
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:905
AString StringsConcat(const AStringVector &a_Strings, char a_Separator)
Concatenates the specified strings into a single string, separated by the specified separator charact...
virtual bool DeleteValue(const AString &keyname, const AString &valuename)=0
Deletes the specified key, value pair.
#define FILE_IO_PREFIX
Definition: Globals.h:196
#define iniEOL
Definition: IniFile.cpp:32
bool m_IsCaseInsensitive
Definition: IniFile.h:39
int GetValueI(const AString &keyname, const AString &valuename, const int defValue=0) const
Definition: IniFile.cpp:502
AString m_Filename
Definition: IniFile.h:41
int GetNumValues(const AString &keyname) const
Definition: IniFile.cpp:318
bool DeleteKey(const AString &keyname)
Definition: IniFile.cpp:626
void AddValueF(const AString &a_KeyName, const AString &a_ValueName, const double a_Value)
Definition: IniFile.cpp:384
bool ReadFile(const AString &a_FileName, bool a_AllowExampleRedirect=true)
Reads the contents of the specified ini file If the file doesn&#39;t exist and a_AllowExampleRedirect is ...
Definition: IniFile.cpp:50
bool DeleteKeyComment(const int keyID, const int commentID)
Definition: IniFile.cpp:795
virtual bool KeyExists(const AString a_keyName) const override
Returns true iff the specified key exists.
Definition: IniFile.cpp:896
std::vector< AString > m_Names
Definition: IniFile.h:51
std::vector< AString > AStringVector
Definition: StringUtils.h:14
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.
int FindKey(const AString &keyname) const
Returns index of specified key, or noID if not found.
Definition: IniFile.cpp:239
AString GetKeyComment(const int keyID, const int commentID) const
Return a key comment.
Definition: IniFile.cpp:768
bool WriteFile(const AString &a_FileName) const
Writes data stored in class to the specified ini file.
Definition: IniFile.cpp:189
bool SetValue(const int keyID, const int valueID, const AString &value)
Definition: IniFile.cpp:393
AStringVector StringSplitAndTrim(const AString &str, const AString &delim)
Split the string at any of the listed delimiters and trim each value.
bool DeleteValue(const AString &keyname, const AString &valuename) override
Deletes the specified key, value pair.
Definition: IniFile.cpp:605
bool SetValueF(const AString &a_KeyName, const AString &a_ValueName, const double a_Value, const bool a_CreateIfNotExists=true)
Definition: IniFile.cpp:459
AString & Printf(AString &str, const char *format, fmt::ArgList args)
Output the formatted text into the string.
Definition: StringUtils.cpp:55
void AddHeaderComment(const AString &comment)
Adds a header comment.
Definition: IniFile.cpp:675
void Clear(void)
Deletes all stored ini data (but doesn&#39;t touch the file)
Definition: IniFile.cpp:646
AString GetHeaderComment(const int commentID) const
Returns a header comment, or empty string if out of range.
Definition: IniFile.cpp:685
AString GetValueName(const AString &keyname, const int valueID) const
Definition: IniFile.cpp:345
std::vector< AString > m_Comments
Definition: IniFile.h:52
AString GetKeyName(const int keyID) const
Definition: IniFile.cpp:289
int GetNumKeyComments(const int keyID) const
Get number of key comments.
Definition: IniFile.cpp:713
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:256
AString CheckCase(const AString &s) const
If the object is case-insensitive, returns s as lowercase; otherwise returns s as-is.
Definition: IniFile.cpp:852
int AddKeyName(const AString &keyname) override
Add a key name.
Definition: IniFile.cpp:278
AString TrimString(const AString &str)
Trims whitespace at both ends of the string.
bool DeleteValueByID(const int keyID, const int valueID)
Definition: IniFile.cpp:587
std::string AString
Definition: StringUtils.h:13
double GetValueF(const AString &keyname, const AString &valuename, const double defValue=0) const
Definition: IniFile.cpp:513
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
bool SetValueI(const AString &a_KeyName, const AString &a_ValueName, const int a_Value, const bool a_CreateIfNotExists=true) override
Definition: IniFile.cpp:441
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:359
int GetValueSetI(const AString &keyname, const AString &valuename, const int defValue=0) override
Definition: IniFile.cpp:558
bool DeleteHeaderComment(int commentID)
Deletes a header comment.
Definition: IniFile.cpp:698
void RemoveBom(AString &a_line) const
Removes the UTF-8 BOMs (Byte order makers), if present.
Definition: IniFile.cpp:871
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:924
std::vector< key > m_Keys
Definition: IniFile.h:50
bool HasValue(const AString &a_KeyName, const AString &a_ValueName) const override
Returns true iff the specified value exists.
Definition: IniFile.cpp:657
AStringVector MergeStringVectors(const AStringVector &a_Strings1, const AStringVector &a_Strings2)
Merges the two vectors of strings, removing duplicate entries from the second vector.
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:481
bool AddKeyComment(const int keyID, const AString &comment)
Add a key comment.
Definition: IniFile.cpp:740
cIniFile(void)
Creates a new instance with no data.
Definition: IniFile.cpp:41
signed long long Int64
Definition: Globals.h:107
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:524