SimpleIni.h
Go to the documentation of this file.
1 
194 #ifndef INCLUDED_SimpleIni_h
195 #define INCLUDED_SimpleIni_h
196 
197 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
198 # pragma once
199 #endif
200 
201 // Disable these warnings in MSVC:
202 // 4127 "conditional expression is constant" as the conversion classes trigger
203 // it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
204 // be optimized away in a release build.
205 // 4503 'insert' : decorated name length exceeded, name was truncated
206 // 4702 "unreachable code" as the MS STL header causes it in release mode.
207 // Again, the code causing the warning will be cleaned up by the compiler.
208 // 4786 "identifier truncated to 256 characters" as this is thrown hundreds
209 // of times VC6 as soon as STL is used.
210 #ifdef _MSC_VER
211 # pragma warning (push)
212 # pragma warning (disable: 4127 4503 4702 4786)
213 #endif
214 
215 #include <cstring>
216 #include <string>
217 #include <map>
218 #include <list>
219 #include <algorithm>
220 #include <stdio.h>
221 
222 #ifdef SI_SUPPORT_IOSTREAMS
223 # include <iostream>
224 #endif // SI_SUPPORT_IOSTREAMS
225 
226 #ifdef _DEBUG
227 # ifndef assert
228 # include <cassert>
229 # endif
230 # define SI_ASSERT(x) assert(x)
231 #else
232 # define SI_ASSERT(x)
233 #endif
234 
235 enum SI_Error {
236  SI_OK = 0,
239 
240  // note: test for any error with (retval < 0)
241  SI_FAIL = -1,
242  SI_NOMEM = -2,
243  SI_FILE = -3
244 };
245 
246 #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
247 
248 #ifdef _WIN32
249 # define SI_NEWLINE_A "\r\n"
250 # define SI_NEWLINE_W L"\r\n"
251 #else // !_WIN32
252 # define SI_NEWLINE_A "\n"
253 # define SI_NEWLINE_W L"\n"
254 #endif // _WIN32
255 
256 #if defined(SI_CONVERT_ICU)
257 # include <unicode/ustring.h>
258 #endif
259 
260 #if defined(_WIN32)
261 # define SI_HAS_WIDE_FILE
262 # define SI_WCHAR_T wchar_t
263 #elif defined(SI_CONVERT_ICU)
264 # define SI_HAS_WIDE_FILE
265 # define SI_WCHAR_T UChar
266 #endif
267 
268 
269 // ---------------------------------------------------------------------------
270 // MAIN TEMPLATE CLASS
271 // ---------------------------------------------------------------------------
272 
292 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
294 {
295 public:
297  struct Entry {
298  const SI_CHAR * pItem;
299  const SI_CHAR * pComment;
300  int nOrder;
301 
302  Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0)
303  : pItem(a_pszItem)
304  , pComment(NULL)
305  , nOrder(a_nOrder)
306  { }
307  Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder)
308  : pItem(a_pszItem)
309  , pComment(a_pszComment)
310  , nOrder(a_nOrder)
311  { }
312  Entry(const Entry & rhs) { operator=(rhs); }
313  Entry & operator=(const Entry & rhs) {
314  pItem = rhs.pItem;
315  pComment = rhs.pComment;
316  nOrder = rhs.nOrder;
317  return *this;
318  }
319 
320 #if defined(_MSC_VER) && _MSC_VER <= 1200
321 
322  bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
323  bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
324 #endif
325 
327  struct KeyOrder {
328  using result_type = bool;
331  bool operator()(const Entry & lhs, const Entry & rhs) const {
332  const static SI_STRLESS isLess = SI_STRLESS();
333  return isLess(lhs.pItem, rhs.pItem);
334  }
335  };
336 
338  struct LoadOrder {
339  using result_type = bool;
342  bool operator()(const Entry & lhs, const Entry & rhs) const {
343  if (lhs.nOrder != rhs.nOrder) {
344  return lhs.nOrder < rhs.nOrder;
345  }
346  return KeyOrder()(lhs.pItem, rhs.pItem);
347  }
348  };
349  };
350 
352  typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder> TKeyVal;
353 
355  typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder> TSection;
356 
360  typedef std::list<Entry> TNamesDepend;
361 
365  class OutputWriter {
366  public:
368  virtual ~OutputWriter() { }
369  virtual void Write(const char * a_pBuf) = 0;
370  private:
371  OutputWriter(const OutputWriter &); // disable
372  OutputWriter & operator=(const OutputWriter &); // disable
373  };
374 
376  class FileWriter : public OutputWriter {
377  FILE * m_file;
378  public:
379  FileWriter(FILE * a_file) : m_file(a_file) { }
380  void Write(const char * a_pBuf) {
381  fputs(a_pBuf, m_file);
382  }
383  private:
384  FileWriter(const FileWriter &); // disable
385  FileWriter & operator=(const FileWriter &); // disable
386  };
387 
389  class StringWriter : public OutputWriter {
390  std::string & m_string;
391  public:
392  StringWriter(std::string & a_string) : m_string(a_string) { }
393  void Write(const char * a_pBuf) {
394  m_string.append(a_pBuf);
395  }
396  private:
397  StringWriter(const StringWriter &); // disable
398  StringWriter & operator=(const StringWriter &); // disable
399  };
400 
401 #ifdef SI_SUPPORT_IOSTREAMS
402 
403  class StreamWriter : public OutputWriter {
404  std::ostream & m_ostream;
405  public:
406  StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { }
407  void Write(const char * a_pBuf) {
408  m_ostream << a_pBuf;
409  }
410  private:
411  StreamWriter(const StreamWriter &); // disable
412  StreamWriter & operator=(const StreamWriter &); // disable
413  };
414 #endif // SI_SUPPORT_IOSTREAMS
415 
419  class Converter : private SI_CONVERTER {
420  public:
421  Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
422  m_scratch.resize(1024);
423  }
424  Converter(const Converter & rhs) { operator=(rhs); }
425  Converter & operator=(const Converter & rhs) {
426  m_scratch = rhs.m_scratch;
427  return *this;
428  }
429  bool ConvertToStore(const SI_CHAR * a_pszString) {
430  size_t uLen = SI_CONVERTER::SizeToStore(a_pszString);
431  if (uLen == (size_t)(-1)) {
432  return false;
433  }
434  while (uLen > m_scratch.size()) {
435  m_scratch.resize(m_scratch.size() * 2);
436  }
437  return SI_CONVERTER::ConvertToStore(
438  a_pszString,
439  const_cast<char*>(m_scratch.data()),
440  m_scratch.size());
441  }
442  const char * Data() { return m_scratch.data(); }
443  private:
444  std::string m_scratch;
445  };
446 
447 public:
448  /*-----------------------------------------------------------------------*/
449 
457  bool a_bIsUtf8 = false,
458  bool a_bMultiKey = false,
459  bool a_bMultiLine = false
460  );
461 
464 
466  void Reset();
467 
469  bool IsEmpty() const { return m_data.empty(); }
470 
471  /*-----------------------------------------------------------------------*/
488  void SetUnicode(bool a_bIsUtf8 = true) {
489  if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
490  }
491 
493  bool IsUnicode() const { return m_bStoreIsUtf8; }
494 
513  void SetMultiKey(bool a_bAllowMultiKey = true) {
514  m_bAllowMultiKey = a_bAllowMultiKey;
515  }
516 
518  bool IsMultiKey() const { return m_bAllowMultiKey; }
519 
527  void SetMultiLine(bool a_bAllowMultiLine = true) {
528  m_bAllowMultiLine = a_bAllowMultiLine;
529  }
530 
532  bool IsMultiLine() const { return m_bAllowMultiLine; }
533 
540  void SetSpaces(bool a_bSpaces = true) {
541  m_bSpaces = a_bSpaces;
542  }
543 
545  bool UsingSpaces() const { return m_bSpaces; }
546 
547  /*-----------------------------------------------------------------------*/
560  const char * a_pszFile
561  );
562 
563 #ifdef SI_HAS_WIDE_FILE
564 
571  const SI_WCHAR_T * a_pwszFile
572  );
573 #endif // SI_HAS_WIDE_FILE
574 
583  FILE * a_fpFile
584  );
585 
586 #ifdef SI_SUPPORT_IOSTREAMS
587 
594  std::istream & a_istream
595  );
596 #endif // SI_SUPPORT_IOSTREAMS
597 
604  SI_Error LoadData(const std::string & a_strData) {
605  return LoadData(a_strData.c_str(), a_strData.size());
606  }
607 
616  const char * a_pData,
617  size_t a_uDataLen
618  );
619 
620  /*-----------------------------------------------------------------------*/
637  const char * a_pszFile,
638  bool a_bAddSignature = true
639  ) const;
640 
641 #ifdef SI_HAS_WIDE_FILE
642 
653  const SI_WCHAR_T * a_pwszFile,
654  bool a_bAddSignature = true
655  ) const;
656 #endif // _WIN32
657 
671  FILE * a_pFile,
672  bool a_bAddSignature = false
673  ) const;
674 
706  SI_Error Save(
707  OutputWriter & a_oOutput,
708  bool a_bAddSignature = false
709  ) const;
710 
711 #ifdef SI_SUPPORT_IOSTREAMS
712 
723  SI_Error Save(
724  std::ostream & a_ostream,
725  bool a_bAddSignature = false
726  ) const
727  {
728  StreamWriter writer(a_ostream);
729  return Save(writer, a_bAddSignature);
730  }
731 #endif // SI_SUPPORT_IOSTREAMS
732 
745  std::string & a_sBuffer,
746  bool a_bAddSignature = false
747  ) const
748  {
749  StringWriter writer(a_sBuffer);
750  return Save(writer, a_bAddSignature);
751  }
752 
753  /*-----------------------------------------------------------------------*/
771  void GetAllSections(
772  TNamesDepend & a_names
773  ) const;
774 
792  bool GetAllKeys(
793  const SI_CHAR * a_pSection,
794  TNamesDepend & a_names
795  ) const;
796 
813  bool GetAllValues(
814  const SI_CHAR * a_pSection,
815  const SI_CHAR * a_pKey,
816  TNamesDepend & a_values
817  ) const;
818 
828  int GetSectionSize(
829  const SI_CHAR * a_pSection
830  ) const;
831 
846  const TKeyVal * GetSection(
847  const SI_CHAR * a_pSection
848  ) const;
849 
867  const SI_CHAR * GetValue(
868  const SI_CHAR * a_pSection,
869  const SI_CHAR * a_pKey,
870  const SI_CHAR * a_pDefault = NULL,
871  bool * a_pHasMultiple = NULL
872  ) const;
873 
887  long GetLongValue(
888  const SI_CHAR * a_pSection,
889  const SI_CHAR * a_pKey,
890  long a_nDefault = 0,
891  bool * a_pHasMultiple = NULL
892  ) const;
893 
907  double GetDoubleValue(
908  const SI_CHAR * a_pSection,
909  const SI_CHAR * a_pKey,
910  double a_nDefault = 0,
911  bool * a_pHasMultiple = NULL
912  ) const;
913 
932  bool GetBoolValue(
933  const SI_CHAR * a_pSection,
934  const SI_CHAR * a_pKey,
935  bool a_bDefault = false,
936  bool * a_pHasMultiple = NULL
937  ) const;
938 
969  const SI_CHAR * a_pSection,
970  const SI_CHAR * a_pKey,
971  const SI_CHAR * a_pValue,
972  const SI_CHAR * a_pComment = NULL,
973  bool a_bForceReplace = false
974  )
975  {
976  return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true);
977  }
978 
1003  const SI_CHAR * a_pSection,
1004  const SI_CHAR * a_pKey,
1005  long a_nValue,
1006  const SI_CHAR * a_pComment = NULL,
1007  bool a_bUseHex = false,
1008  bool a_bForceReplace = false
1009  );
1010 
1032  const SI_CHAR * a_pSection,
1033  const SI_CHAR * a_pKey,
1034  double a_nValue,
1035  const SI_CHAR * a_pComment = NULL,
1036  bool a_bForceReplace = false
1037  );
1038 
1060  const SI_CHAR * a_pSection,
1061  const SI_CHAR * a_pKey,
1062  bool a_bValue,
1063  const SI_CHAR * a_pComment = NULL,
1064  bool a_bForceReplace = false
1065  );
1066 
1085  bool Delete(
1086  const SI_CHAR * a_pSection,
1087  const SI_CHAR * a_pKey,
1088  bool a_bRemoveEmpty = false
1089  );
1090 
1091  /*-----------------------------------------------------------------------*/
1101  return Converter(m_bStoreIsUtf8);
1102  }
1103 
1104  /*-----------------------------------------------------------------------*/
1107 private:
1108  // copying is not permitted
1109  CSimpleIniTempl(const CSimpleIniTempl &); // disabled
1110  CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled
1111 
1115  SI_CHAR *& a_pData,
1116  bool a_bCopyStrings
1117  );
1118 
1123  bool FindEntry(
1124  SI_CHAR *& a_pData,
1125  const SI_CHAR *& a_pSection,
1126  const SI_CHAR *& a_pKey,
1127  const SI_CHAR *& a_pVal,
1128  const SI_CHAR *& a_pComment
1129  ) const;
1130 
1154  const SI_CHAR * a_pSection,
1155  const SI_CHAR * a_pKey,
1156  const SI_CHAR * a_pValue,
1157  const SI_CHAR * a_pComment,
1158  bool a_bForceReplace,
1159  bool a_bCopyStrings
1160  );
1161 
1163  inline bool IsSpace(SI_CHAR ch) const {
1164  return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
1165  }
1166 
1168  inline bool IsComment(SI_CHAR ch) const {
1169  return (ch == ';' || ch == '#');
1170  }
1171 
1172 
1174  inline void SkipNewLine(SI_CHAR *& a_pData) const {
1175  a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1;
1176  }
1177 
1179  SI_Error CopyString(const SI_CHAR *& a_pString);
1180 
1182  void DeleteString(const SI_CHAR * a_pString);
1183 
1185  bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const {
1186  const static SI_STRLESS isLess = SI_STRLESS();
1187  return isLess(a_pLeft, a_pRight);
1188  }
1189 
1190  bool IsMultiLineTag(const SI_CHAR * a_pData) const;
1191  bool IsMultiLineData(const SI_CHAR * a_pData) const;
1192  bool LoadMultiLineText(
1193  SI_CHAR *& a_pData,
1194  const SI_CHAR *& a_pVal,
1195  const SI_CHAR * a_pTagName,
1196  bool a_bAllowBlankLinesInComment = false
1197  ) const;
1198  bool IsNewLineChar(SI_CHAR a_c) const;
1199 
1200  bool OutputMultiLineText(
1201  OutputWriter & a_oOutput,
1202  Converter & a_oConverter,
1203  const SI_CHAR * a_pText
1204  ) const;
1205 
1206 private:
1212  SI_CHAR * m_pData;
1213 
1218  size_t m_uDataLen;
1219 
1221  const SI_CHAR * m_pFileComment;
1222 
1225 
1231 
1234 
1237 
1240 
1243 
1248 };
1249 
1250 // ---------------------------------------------------------------------------
1251 // IMPLEMENTATION
1252 // ---------------------------------------------------------------------------
1253 
1254 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1256  bool a_bIsUtf8,
1257  bool a_bAllowMultiKey,
1258  bool a_bAllowMultiLine
1259  )
1260  : m_pData(0)
1261  , m_uDataLen(0)
1262  , m_pFileComment(NULL)
1263  , m_bStoreIsUtf8(a_bIsUtf8)
1264  , m_bAllowMultiKey(a_bAllowMultiKey)
1265  , m_bAllowMultiLine(a_bAllowMultiLine)
1266  , m_bSpaces(true)
1267  , m_nOrder(0)
1268 { }
1269 
1270 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1272 {
1273  Reset();
1274 }
1275 
1276 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1277 void
1279 {
1280  // remove all data
1281  delete[] m_pData;
1282  m_pData = NULL;
1283  m_uDataLen = 0;
1284  m_pFileComment = NULL;
1285  if (!m_data.empty()) {
1286  m_data.erase(m_data.begin(), m_data.end());
1287  }
1288 
1289  // remove all strings
1290  if (!m_strings.empty()) {
1291  typename TNamesDepend::iterator i = m_strings.begin();
1292  for (; i != m_strings.end(); ++i) {
1293  delete[] const_cast<SI_CHAR*>(i->pItem);
1294  }
1295  m_strings.erase(m_strings.begin(), m_strings.end());
1296  }
1297 }
1298 
1299 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1300 SI_Error
1302  const char * a_pszFile
1303  )
1304 {
1305  FILE * fp = NULL;
1306 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1307  fopen_s(&fp, a_pszFile, "rb");
1308 #else // !__STDC_WANT_SECURE_LIB__
1309  fp = fopen(a_pszFile, "rb");
1310 #endif // __STDC_WANT_SECURE_LIB__
1311  if (!fp) {
1312  return SI_FILE;
1313  }
1314  SI_Error rc = LoadFile(fp);
1315  fclose(fp);
1316  return rc;
1317 }
1318 
1319 #ifdef SI_HAS_WIDE_FILE
1320 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1321 SI_Error
1323  const SI_WCHAR_T * a_pwszFile
1324  )
1325 {
1326 #ifdef _WIN32
1327  FILE * fp = NULL;
1328 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1329  _wfopen_s(&fp, a_pwszFile, L"rb");
1330 #else // !__STDC_WANT_SECURE_LIB__
1331  fp = _wfopen(a_pwszFile, L"rb");
1332 #endif // __STDC_WANT_SECURE_LIB__
1333  if (!fp) return SI_FILE;
1334  SI_Error rc = LoadFile(fp);
1335  fclose(fp);
1336  return rc;
1337 #else // !_WIN32 (therefore SI_CONVERT_ICU)
1338  char szFile[256];
1339  u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
1340  return LoadFile(szFile);
1341 #endif // _WIN32
1342 }
1343 #endif // SI_HAS_WIDE_FILE
1344 
1345 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1346 SI_Error
1348  FILE * a_fpFile
1349  )
1350 {
1351  // load the raw file data
1352  int retval = fseek(a_fpFile, 0, SEEK_END);
1353  if (retval != 0) {
1354  return SI_FILE;
1355  }
1356  long lSize = ftell(a_fpFile);
1357  if (lSize < 0) {
1358  return SI_FILE;
1359  }
1360  if (lSize == 0) {
1361  return SI_OK;
1362  }
1363  char * pData = new char[lSize];
1364  if (!pData) {
1365  return SI_NOMEM;
1366  }
1367  fseek(a_fpFile, 0, SEEK_SET);
1368  size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
1369  if (uRead != (size_t) lSize) {
1370  delete[] pData;
1371  return SI_FILE;
1372  }
1373 
1374  // convert the raw data to unicode
1375  SI_Error rc = LoadData(pData, uRead);
1376  delete[] pData;
1377  return rc;
1378 }
1379 
1380 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1381 SI_Error
1383  const char * a_pData,
1384  size_t a_uDataLen
1385  )
1386 {
1387  SI_CONVERTER converter(m_bStoreIsUtf8);
1388 
1389  if (a_uDataLen == 0) {
1390  return SI_OK;
1391  }
1392 
1393  // consume the UTF-8 BOM if it exists
1394  if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
1395  if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
1396  a_pData += 3;
1397  a_uDataLen -= 3;
1398  }
1399  }
1400 
1401  // determine the length of the converted data
1402  size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
1403  if (uLen == (size_t)(-1)) {
1404  return SI_FAIL;
1405  }
1406 
1407  // allocate memory for the data, ensure that there is a NULL
1408  // terminator wherever the converted data ends
1409  SI_CHAR * pData = new SI_CHAR[uLen+1];
1410  if (!pData) {
1411  return SI_NOMEM;
1412  }
1413  memset(pData, 0, sizeof(SI_CHAR)*(uLen+1));
1414 
1415  // convert the data
1416  if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
1417  delete[] pData;
1418  return SI_FAIL;
1419  }
1420 
1421  // parse it
1422  const static SI_CHAR empty = 0;
1423  SI_CHAR * pWork = pData;
1424  const SI_CHAR * pSection = &empty;
1425  const SI_CHAR * pItem = NULL;
1426  const SI_CHAR * pVal = NULL;
1427  const SI_CHAR * pComment = NULL;
1428 
1429  // We copy the strings if we are loading data into this class when we
1430  // already have stored some.
1431  bool bCopyStrings = (m_pData != NULL);
1432 
1433  // find a file comment if it exists, this is a comment that starts at the
1434  // beginning of the file and continues until the first blank line.
1435  SI_Error rc = FindFileComment(pWork, bCopyStrings);
1436  if (rc < 0) return rc;
1437 
1438  // add every entry in the file to the data table
1439  while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
1440  rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings);
1441  if (rc < 0) return rc;
1442  }
1443 
1444  // store these strings if we didn't copy them
1445  if (bCopyStrings) {
1446  delete[] pData;
1447  }
1448  else {
1449  m_pData = pData;
1450  m_uDataLen = uLen+1;
1451  }
1452 
1453  return SI_OK;
1454 }
1455 
1456 #ifdef SI_SUPPORT_IOSTREAMS
1457 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1458 SI_Error
1460  std::istream & a_istream
1461  )
1462 {
1463  std::string strData;
1464  char szBuf[512];
1465  do {
1466  a_istream.get(szBuf, sizeof(szBuf), '\0');
1467  strData.append(szBuf);
1468  }
1469  while (a_istream.good());
1470  return LoadData(strData);
1471 }
1472 #endif // SI_SUPPORT_IOSTREAMS
1473 
1474 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1475 SI_Error
1477  SI_CHAR *& a_pData,
1478  bool a_bCopyStrings
1479  )
1480 {
1481  // there can only be a single file comment
1482  if (m_pFileComment) {
1483  return SI_OK;
1484  }
1485 
1486  // Load the file comment as multi-line text, this will modify all of
1487  // the newline characters to be single \n chars
1488  if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
1489  return SI_OK;
1490  }
1491 
1492  // copy the string if necessary
1493  if (a_bCopyStrings) {
1494  SI_Error rc = CopyString(m_pFileComment);
1495  if (rc < 0) return rc;
1496  }
1497 
1498  return SI_OK;
1499 }
1500 
1501 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1502 bool
1504  SI_CHAR *& a_pData,
1505  const SI_CHAR *& a_pSection,
1506  const SI_CHAR *& a_pKey,
1507  const SI_CHAR *& a_pVal,
1508  const SI_CHAR *& a_pComment
1509  ) const
1510 {
1511  a_pComment = NULL;
1512 
1513  SI_CHAR * pTrail = NULL;
1514  while (*a_pData) {
1515  // skip spaces and empty lines
1516  while (*a_pData && IsSpace(*a_pData)) {
1517  ++a_pData;
1518  }
1519  if (!*a_pData) {
1520  break;
1521  }
1522 
1523  // skip processing of comment lines but keep a pointer to
1524  // the start of the comment.
1525  if (IsComment(*a_pData)) {
1526  LoadMultiLineText(a_pData, a_pComment, NULL, true);
1527  continue;
1528  }
1529 
1530  // process section names
1531  if (*a_pData == '[') {
1532  // skip leading spaces
1533  ++a_pData;
1534  while (*a_pData && IsSpace(*a_pData)) {
1535  ++a_pData;
1536  }
1537 
1538  // find the end of the section name (it may contain spaces)
1539  // and convert it to lowercase as necessary
1540  a_pSection = a_pData;
1541  while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
1542  ++a_pData;
1543  }
1544 
1545  // if it's an invalid line, just skip it
1546  if (*a_pData != ']') {
1547  continue;
1548  }
1549 
1550  // remove trailing spaces from the section
1551  pTrail = a_pData - 1;
1552  while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1553  --pTrail;
1554  }
1555  ++pTrail;
1556  *pTrail = 0;
1557 
1558  // skip to the end of the line
1559  ++a_pData; // safe as checked that it == ']' above
1560  while (*a_pData && !IsNewLineChar(*a_pData)) {
1561  ++a_pData;
1562  }
1563 
1564  a_pKey = NULL;
1565  a_pVal = NULL;
1566  return true;
1567  }
1568 
1569  // find the end of the key name (it may contain spaces)
1570  // and convert it to lowercase as necessary
1571  a_pKey = a_pData;
1572  while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
1573  ++a_pData;
1574  }
1575 
1576  // if it's an invalid line, just skip it
1577  if (*a_pData != '=') {
1578  continue;
1579  }
1580 
1581  // empty keys are invalid
1582  if (a_pKey == a_pData) {
1583  while (*a_pData && !IsNewLineChar(*a_pData)) {
1584  ++a_pData;
1585  }
1586  continue;
1587  }
1588 
1589  // remove trailing spaces from the key
1590  pTrail = a_pData - 1;
1591  while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1592  --pTrail;
1593  }
1594  ++pTrail;
1595  *pTrail = 0;
1596 
1597  // skip leading whitespace on the value
1598  ++a_pData; // safe as checked that it == '=' above
1599  while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1600  ++a_pData;
1601  }
1602 
1603  // find the end of the value which is the end of this line
1604  a_pVal = a_pData;
1605  while (*a_pData && !IsNewLineChar(*a_pData)) {
1606  ++a_pData;
1607  }
1608 
1609  // remove trailing spaces from the value
1610  pTrail = a_pData - 1;
1611  if (*a_pData) { // prepare for the next round
1612  SkipNewLine(a_pData);
1613  }
1614  while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1615  --pTrail;
1616  }
1617  ++pTrail;
1618  *pTrail = 0;
1619 
1620  // check for multi-line entries
1621  if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1622  // skip the "<<<" to get the tag that will end the multiline
1623  const SI_CHAR * pTagName = a_pVal + 3;
1624  return LoadMultiLineText(a_pData, a_pVal, pTagName);
1625  }
1626 
1627  // return the standard entry
1628  return true;
1629  }
1630 
1631  return false;
1632 }
1633 
1634 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1635 bool
1637  const SI_CHAR * a_pVal
1638  ) const
1639 {
1640  // check for the "<<<" prefix for a multi-line entry
1641  if (*a_pVal++ != '<') return false;
1642  if (*a_pVal++ != '<') return false;
1643  if (*a_pVal++ != '<') return false;
1644  return true;
1645 }
1646 
1647 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1648 bool
1650  const SI_CHAR * a_pData
1651  ) const
1652 {
1653  // data is multi-line if it has any of the following features:
1654  // * whitespace prefix
1655  // * embedded newlines
1656  // * whitespace suffix
1657 
1658  // empty string
1659  if (!*a_pData) {
1660  return false;
1661  }
1662 
1663  // check for prefix
1664  if (IsSpace(*a_pData)) {
1665  return true;
1666  }
1667 
1668  // embedded newlines
1669  while (*a_pData) {
1670  if (IsNewLineChar(*a_pData)) {
1671  return true;
1672  }
1673  ++a_pData;
1674  }
1675 
1676  // check for suffix
1677  if (IsSpace(*--a_pData)) {
1678  return true;
1679  }
1680 
1681  return false;
1682 }
1683 
1684 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1685 bool
1687  SI_CHAR a_c
1688  ) const
1689 {
1690  return (a_c == '\n' || a_c == '\r');
1691 }
1692 
1693 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1694 bool
1696  SI_CHAR *& a_pData,
1697  const SI_CHAR *& a_pVal,
1698  const SI_CHAR * a_pTagName,
1699  bool a_bAllowBlankLinesInComment
1700  ) const
1701 {
1702  // we modify this data to strip all newlines down to a single '\n'
1703  // character. This means that on Windows we need to strip out some
1704  // characters which will make the data shorter.
1705  // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
1706  // LINE1-LINE1\nLINE2-LINE2\0
1707  // The pDataLine entry is the pointer to the location in memory that
1708  // the current line needs to start to run following the existing one.
1709  // This may be the same as pCurrLine in which case no move is needed.
1710  SI_CHAR * pDataLine = a_pData;
1711  SI_CHAR * pCurrLine;
1712 
1713  // value starts at the current line
1714  a_pVal = a_pData;
1715 
1716  // find the end tag. This tag must start in column 1 and be
1717  // followed by a newline. No whitespace removal is done while
1718  // searching for this tag.
1719  SI_CHAR cEndOfLineChar = *a_pData;
1720  for(;;) {
1721  // if we are loading comments then we need a comment character as
1722  // the first character on every line
1723  if (!a_pTagName && !IsComment(*a_pData)) {
1724  // if we aren't allowing blank lines then we're done
1725  if (!a_bAllowBlankLinesInComment) {
1726  break;
1727  }
1728 
1729  // if we are allowing blank lines then we only include them
1730  // in this comment if another comment follows, so read ahead
1731  // to find out.
1732  SI_CHAR * pCurr = a_pData;
1733  int nNewLines = 0;
1734  while (IsSpace(*pCurr)) {
1735  if (IsNewLineChar(*pCurr)) {
1736  ++nNewLines;
1737  SkipNewLine(pCurr);
1738  }
1739  else {
1740  ++pCurr;
1741  }
1742  }
1743 
1744  // we have a comment, add the blank lines to the output
1745  // and continue processing from here
1746  if (IsComment(*pCurr)) {
1747  for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
1748  a_pData = pCurr;
1749  continue;
1750  }
1751 
1752  // the comment ends here
1753  break;
1754  }
1755 
1756  // find the end of this line
1757  pCurrLine = a_pData;
1758  while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1759 
1760  // move this line down to the location that it should be if necessary
1761  if (pDataLine < pCurrLine) {
1762  size_t nLen = (size_t) (a_pData - pCurrLine);
1763  memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR));
1764  pDataLine[nLen] = '\0';
1765  }
1766 
1767  // end the line with a NULL
1768  cEndOfLineChar = *a_pData;
1769  *a_pData = 0;
1770 
1771  // if are looking for a tag then do the check now. This is done before
1772  // checking for end of the data, so that if we have the tag at the end
1773  // of the data then the tag is removed correctly.
1774  if (a_pTagName &&
1775  (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
1776  {
1777  break;
1778  }
1779 
1780  // if we are at the end of the data then we just automatically end
1781  // this entry and return the current data.
1782  if (!cEndOfLineChar) {
1783  return true;
1784  }
1785 
1786  // otherwise we need to process this newline to ensure that it consists
1787  // of just a single \n character.
1788  pDataLine += (a_pData - pCurrLine);
1789  *a_pData = cEndOfLineChar;
1790  SkipNewLine(a_pData);
1791  *pDataLine++ = '\n';
1792  }
1793 
1794  // if we didn't find a comment at all then return false
1795  if (a_pVal == a_pData) {
1796  a_pVal = NULL;
1797  return false;
1798  }
1799 
1800  // the data (which ends at the end of the last line) needs to be
1801  // null-terminated BEFORE before the newline character(s). If the
1802  // user wants a new line in the multi-line data then they need to
1803  // add an empty line before the tag.
1804  *--pDataLine = '\0';
1805 
1806  // if looking for a tag and if we aren't at the end of the data,
1807  // then move a_pData to the start of the next line.
1808  if (a_pTagName && cEndOfLineChar) {
1809  SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1810  *a_pData = cEndOfLineChar;
1811  SkipNewLine(a_pData);
1812  }
1813 
1814  return true;
1815 }
1816 
1817 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1818 SI_Error
1820  const SI_CHAR *& a_pString
1821  )
1822 {
1823  size_t uLen = 0;
1824  if (sizeof(SI_CHAR) == sizeof(char)) {
1825  uLen = strlen((const char *)a_pString);
1826  }
1827  else if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
1828  uLen = wcslen((const wchar_t *)a_pString);
1829  }
1830  else {
1831  for ( ; a_pString[uLen]; ++uLen) /*loop*/ ;
1832  }
1833  ++uLen; // NULL character
1834  SI_CHAR * pCopy = new SI_CHAR[uLen];
1835  if (!pCopy) {
1836  return SI_NOMEM;
1837  }
1838  memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen);
1839  m_strings.push_back(pCopy);
1840  a_pString = pCopy;
1841  return SI_OK;
1842 }
1843 
1844 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1845 SI_Error
1847  const SI_CHAR * a_pSection,
1848  const SI_CHAR * a_pKey,
1849  const SI_CHAR * a_pValue,
1850  const SI_CHAR * a_pComment,
1851  bool a_bForceReplace,
1852  bool a_bCopyStrings
1853  )
1854 {
1855  SI_Error rc;
1856  bool bInserted = false;
1857 
1858  SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1859 
1860  // if we are copying strings then make a copy of the comment now
1861  // because we will need it when we add the entry.
1862  if (a_bCopyStrings && a_pComment) {
1863  rc = CopyString(a_pComment);
1864  if (rc < 0) return rc;
1865  }
1866 
1867  // create the section entry if necessary
1868  typename TSection::iterator iSection = m_data.find(a_pSection);
1869  if (iSection == m_data.end()) {
1870  // if the section doesn't exist then we need a copy as the
1871  // string needs to last beyond the end of this function
1872  if (a_bCopyStrings) {
1873  rc = CopyString(a_pSection);
1874  if (rc < 0) return rc;
1875  }
1876 
1877  // only set the comment if this is a section only entry
1878  Entry oSection(a_pSection, ++m_nOrder);
1879  if (a_pComment && (!a_pKey || !a_pValue)) {
1880  oSection.pComment = a_pComment;
1881  }
1882 
1883  typename TSection::value_type oEntry(oSection, TKeyVal());
1884  typedef typename TSection::iterator SectionIterator;
1885  std::pair<SectionIterator,bool> i = m_data.insert(oEntry);
1886  iSection = i.first;
1887  bInserted = true;
1888  }
1889  if (!a_pKey || !a_pValue) {
1890  // section only entries are specified with pItem and pVal as NULL
1891  return bInserted ? SI_INSERTED : SI_UPDATED;
1892  }
1893 
1894  // check for existence of the key
1895  TKeyVal & keyval = iSection->second;
1896  typename TKeyVal::iterator iKey = keyval.find(a_pKey);
1897 
1898  // remove all existing entries but save the load order and
1899  // comment of the first entry
1900  int nLoadOrder = ++m_nOrder;
1901  if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
1902  const SI_CHAR * pComment = NULL;
1903  while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
1904  if (iKey->first.nOrder < nLoadOrder) {
1905  nLoadOrder = iKey->first.nOrder;
1906  pComment = iKey->first.pComment;
1907  }
1908  ++iKey;
1909  }
1910  if (pComment) {
1911  DeleteString(a_pComment);
1912  a_pComment = pComment;
1913  CopyString(a_pComment);
1914  }
1915  Delete(a_pSection, a_pKey);
1916  iKey = keyval.end();
1917  }
1918 
1919  // make string copies if necessary
1920  bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
1921  if (a_bCopyStrings) {
1922  if (bForceCreateNewKey || iKey == keyval.end()) {
1923  // if the key doesn't exist then we need a copy as the
1924  // string needs to last beyond the end of this function
1925  // because we will be inserting the key next
1926  rc = CopyString(a_pKey);
1927  if (rc < 0) return rc;
1928  }
1929 
1930  // we always need a copy of the value
1931  rc = CopyString(a_pValue);
1932  if (rc < 0) return rc;
1933  }
1934 
1935  // create the key entry
1936  if (iKey == keyval.end() || bForceCreateNewKey) {
1937  Entry oKey(a_pKey, nLoadOrder);
1938  if (a_pComment) {
1939  oKey.pComment = a_pComment;
1940  }
1941  typename TKeyVal::value_type oEntry(oKey, static_cast<const SI_CHAR *>(NULL));
1942  iKey = keyval.insert(oEntry);
1943  bInserted = true;
1944  }
1945  iKey->second = a_pValue;
1946  return bInserted ? SI_INSERTED : SI_UPDATED;
1947 }
1948 
1949 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1950 const SI_CHAR *
1952  const SI_CHAR * a_pSection,
1953  const SI_CHAR * a_pKey,
1954  const SI_CHAR * a_pDefault,
1955  bool * a_pHasMultiple
1956  ) const
1957 {
1958  if (a_pHasMultiple) {
1959  *a_pHasMultiple = false;
1960  }
1961  if (!a_pSection || !a_pKey) {
1962  return a_pDefault;
1963  }
1964  typename TSection::const_iterator iSection = m_data.find(a_pSection);
1965  if (iSection == m_data.end()) {
1966  return a_pDefault;
1967  }
1968  typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
1969  if (iKeyVal == iSection->second.end()) {
1970  return a_pDefault;
1971  }
1972 
1973  // check for multiple entries with the same key
1974  if (m_bAllowMultiKey && a_pHasMultiple) {
1975  typename TKeyVal::const_iterator iTemp = iKeyVal;
1976  if (++iTemp != iSection->second.end()) {
1977  if (!IsLess(a_pKey, iTemp->first.pItem)) {
1978  *a_pHasMultiple = true;
1979  }
1980  }
1981  }
1982 
1983  return iKeyVal->second;
1984 }
1985 
1986 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1987 long
1989  const SI_CHAR * a_pSection,
1990  const SI_CHAR * a_pKey,
1991  long a_nDefault,
1992  bool * a_pHasMultiple
1993  ) const
1994 {
1995  // return the default if we don't have a value
1996  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
1997  if (!pszValue || !*pszValue) return a_nDefault;
1998 
1999  // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
2000  char szValue[64] = { 0 };
2001  SI_CONVERTER c(m_bStoreIsUtf8);
2002  if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
2003  return a_nDefault;
2004  }
2005 
2006  // handle the value as hex if prefaced with "0x"
2007  long nValue = a_nDefault;
2008  char * pszSuffix = szValue;
2009  if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
2010  if (!szValue[2]) return a_nDefault;
2011  nValue = strtol(&szValue[2], &pszSuffix, 16);
2012  }
2013  else {
2014  nValue = strtol(szValue, &pszSuffix, 10);
2015  }
2016 
2017  // any invalid strings will return the default value
2018  if (*pszSuffix) {
2019  return a_nDefault;
2020  }
2021 
2022  return nValue;
2023 }
2024 
2025 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2026 SI_Error
2028  const SI_CHAR * a_pSection,
2029  const SI_CHAR * a_pKey,
2030  long a_nValue,
2031  const SI_CHAR * a_pComment,
2032  bool a_bUseHex,
2033  bool a_bForceReplace
2034  )
2035 {
2036  // use SetValue to create sections
2037  if (!a_pSection || !a_pKey) return SI_FAIL;
2038 
2039  // convert to an ASCII string
2040  char szInput[64];
2041 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2042  sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
2043 #else // !__STDC_WANT_SECURE_LIB__
2044  sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
2045 #endif // __STDC_WANT_SECURE_LIB__
2046 
2047  // convert to output text
2048  SI_CHAR szOutput[64];
2049  SI_CONVERTER c(m_bStoreIsUtf8);
2050  c.ConvertFromStore(szInput, strlen(szInput) + 1,
2051  szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
2052 
2053  // actually add it
2054  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2055 }
2056 
2057 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2058 double
2060  const SI_CHAR * a_pSection,
2061  const SI_CHAR * a_pKey,
2062  double a_nDefault,
2063  bool * a_pHasMultiple
2064  ) const
2065 {
2066  // return the default if we don't have a value
2067  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2068  if (!pszValue || !*pszValue) return a_nDefault;
2069 
2070  // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
2071  char szValue[64] = { 0 };
2072  SI_CONVERTER c(m_bStoreIsUtf8);
2073  if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
2074  return a_nDefault;
2075  }
2076 
2077  char * pszSuffix = NULL;
2078  double nValue = strtod(szValue, &pszSuffix);
2079 
2080  // any invalid strings will return the default value
2081  if (!pszSuffix || *pszSuffix) {
2082  return a_nDefault;
2083  }
2084 
2085  return nValue;
2086 }
2087 
2088 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2089 SI_Error
2091  const SI_CHAR * a_pSection,
2092  const SI_CHAR * a_pKey,
2093  double a_nValue,
2094  const SI_CHAR * a_pComment,
2095  bool a_bForceReplace
2096  )
2097 {
2098  // use SetValue to create sections
2099  if (!a_pSection || !a_pKey) return SI_FAIL;
2100 
2101  // convert to an ASCII string
2102  char szInput[64];
2103 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2104  sprintf_s(szInput, "%f", a_nValue);
2105 #else // !__STDC_WANT_SECURE_LIB__
2106  sprintf(szInput, "%f", a_nValue);
2107 #endif // __STDC_WANT_SECURE_LIB__
2108 
2109  // convert to output text
2110  SI_CHAR szOutput[64];
2111  SI_CONVERTER c(m_bStoreIsUtf8);
2112  c.ConvertFromStore(szInput, strlen(szInput) + 1,
2113  szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
2114 
2115  // actually add it
2116  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2117 }
2118 
2119 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2120 bool
2122  const SI_CHAR * a_pSection,
2123  const SI_CHAR * a_pKey,
2124  bool a_bDefault,
2125  bool * a_pHasMultiple
2126  ) const
2127 {
2128  // return the default if we don't have a value
2129  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2130  if (!pszValue || !*pszValue) return a_bDefault;
2131 
2132  // we only look at the minimum number of characters
2133  switch (pszValue[0]) {
2134  case 't': case 'T': // true
2135  case 'y': case 'Y': // yes
2136  case '1': // 1 (one)
2137  return true;
2138 
2139  case 'f': case 'F': // false
2140  case 'n': case 'N': // no
2141  case '0': // 0 (zero)
2142  return false;
2143 
2144  case 'o': case 'O':
2145  if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on
2146  if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off
2147  break;
2148  }
2149 
2150  // no recognized value, return the default
2151  return a_bDefault;
2152 }
2153 
2154 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2155 SI_Error
2157  const SI_CHAR * a_pSection,
2158  const SI_CHAR * a_pKey,
2159  bool a_bValue,
2160  const SI_CHAR * a_pComment,
2161  bool a_bForceReplace
2162  )
2163 {
2164  // use SetValue to create sections
2165  if (!a_pSection || !a_pKey) return SI_FAIL;
2166 
2167  // convert to an ASCII string
2168  const char * pszInput = a_bValue ? "true" : "false";
2169 
2170  // convert to output text
2171  SI_CHAR szOutput[64];
2172  SI_CONVERTER c(m_bStoreIsUtf8);
2173  c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
2174  szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
2175 
2176  // actually add it
2177  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2178 }
2179 
2180 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2181 bool
2183  const SI_CHAR * a_pSection,
2184  const SI_CHAR * a_pKey,
2185  TNamesDepend & a_values
2186  ) const
2187 {
2188  a_values.clear();
2189 
2190  if (!a_pSection || !a_pKey) {
2191  return false;
2192  }
2193  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2194  if (iSection == m_data.end()) {
2195  return false;
2196  }
2197  typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2198  if (iKeyVal == iSection->second.end()) {
2199  return false;
2200  }
2201 
2202  // insert all values for this key
2203  a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2204  if (m_bAllowMultiKey) {
2205  ++iKeyVal;
2206  while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
2207  a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2208  ++iKeyVal;
2209  }
2210  }
2211 
2212  return true;
2213 }
2214 
2215 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2216 int
2218  const SI_CHAR * a_pSection
2219  ) const
2220 {
2221  if (!a_pSection) {
2222  return -1;
2223  }
2224 
2225  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2226  if (iSection == m_data.end()) {
2227  return -1;
2228  }
2229  const TKeyVal & section = iSection->second;
2230 
2231  // if multi-key isn't permitted then the section size is
2232  // the number of keys that we have.
2233  if (!m_bAllowMultiKey || section.empty()) {
2234  return (int) section.size();
2235  }
2236 
2237  // otherwise we need to count them
2238  int nCount = 0;
2239  const SI_CHAR * pLastKey = NULL;
2240  typename TKeyVal::const_iterator iKeyVal = section.begin();
2241  for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
2242  if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2243  ++nCount;
2244  pLastKey = iKeyVal->first.pItem;
2245  }
2246  }
2247  return nCount;
2248 }
2249 
2250 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2253  const SI_CHAR * a_pSection
2254  ) const
2255 {
2256  if (a_pSection) {
2257  typename TSection::const_iterator i = m_data.find(a_pSection);
2258  if (i != m_data.end()) {
2259  return &(i->second);
2260  }
2261  }
2262  return 0;
2263 }
2264 
2265 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2266 void
2268  TNamesDepend & a_names
2269  ) const
2270 {
2271  a_names.clear();
2272  typename TSection::const_iterator i = m_data.begin();
2273  for (int n = 0; i != m_data.end(); ++i, ++n ) {
2274  a_names.push_back(i->first);
2275  }
2276 }
2277 
2278 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2279 bool
2281  const SI_CHAR * a_pSection,
2282  TNamesDepend & a_names
2283  ) const
2284 {
2285  a_names.clear();
2286 
2287  if (!a_pSection) {
2288  return false;
2289  }
2290 
2291  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2292  if (iSection == m_data.end()) {
2293  return false;
2294  }
2295 
2296  const TKeyVal & section = iSection->second;
2297  const SI_CHAR * pLastKey = NULL;
2298  typename TKeyVal::const_iterator iKeyVal = section.begin();
2299  for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) {
2300  if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2301  a_names.push_back(iKeyVal->first);
2302  pLastKey = iKeyVal->first.pItem;
2303  }
2304  }
2305 
2306  return true;
2307 }
2308 
2309 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2310 SI_Error
2312  const char * a_pszFile,
2313  bool a_bAddSignature
2314  ) const
2315 {
2316  FILE * fp = NULL;
2317 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2318  fopen_s(&fp, a_pszFile, "wb");
2319 #else // !__STDC_WANT_SECURE_LIB__
2320  fp = fopen(a_pszFile, "wb");
2321 #endif // __STDC_WANT_SECURE_LIB__
2322  if (!fp) return SI_FILE;
2323  SI_Error rc = SaveFile(fp, a_bAddSignature);
2324  fclose(fp);
2325  return rc;
2326 }
2327 
2328 #ifdef SI_HAS_WIDE_FILE
2329 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2330 SI_Error
2332  const SI_WCHAR_T * a_pwszFile,
2333  bool a_bAddSignature
2334  ) const
2335 {
2336 #ifdef _WIN32
2337  FILE * fp = NULL;
2338 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2339  _wfopen_s(&fp, a_pwszFile, L"wb");
2340 #else // !__STDC_WANT_SECURE_LIB__
2341  fp = _wfopen(a_pwszFile, L"wb");
2342 #endif // __STDC_WANT_SECURE_LIB__
2343  if (!fp) return SI_FILE;
2344  SI_Error rc = SaveFile(fp, a_bAddSignature);
2345  fclose(fp);
2346  return rc;
2347 #else // !_WIN32 (therefore SI_CONVERT_ICU)
2348  char szFile[256];
2349  u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
2350  return SaveFile(szFile, a_bAddSignature);
2351 #endif // _WIN32
2352 }
2353 #endif // SI_HAS_WIDE_FILE
2354 
2355 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2356 SI_Error
2358  FILE * a_pFile,
2359  bool a_bAddSignature
2360  ) const
2361 {
2362  FileWriter writer(a_pFile);
2363  return Save(writer, a_bAddSignature);
2364 }
2365 
2366 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2367 SI_Error
2369  OutputWriter & a_oOutput,
2370  bool a_bAddSignature
2371  ) const
2372 {
2373  Converter convert(m_bStoreIsUtf8);
2374 
2375  // add the UTF-8 signature if it is desired
2376  if (m_bStoreIsUtf8 && a_bAddSignature) {
2377  a_oOutput.Write(SI_UTF8_SIGNATURE);
2378  }
2379 
2380  // get all of the sections sorted in load order
2381  TNamesDepend oSections;
2382  GetAllSections(oSections);
2383 #if defined(_MSC_VER) && _MSC_VER <= 1200
2384  oSections.sort();
2385 #elif defined(__BORLANDC__)
2386  oSections.sort(Entry::LoadOrder());
2387 #else
2388  oSections.sort(typename Entry::LoadOrder());
2389 #endif
2390 
2391  // write the file comment if we have one
2392  bool bNeedNewLine = false;
2393  if (m_pFileComment) {
2394  if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
2395  return SI_FAIL;
2396  }
2397  bNeedNewLine = true;
2398  }
2399 
2400  // iterate through our sections and output the data
2401  typename TNamesDepend::const_iterator iSection = oSections.begin();
2402  for ( ; iSection != oSections.end(); ++iSection ) {
2403  // write out the comment if there is one
2404  if (iSection->pComment) {
2405  if (bNeedNewLine) {
2406  a_oOutput.Write(SI_NEWLINE_A);
2407  a_oOutput.Write(SI_NEWLINE_A);
2408  }
2409  if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
2410  return SI_FAIL;
2411  }
2412  bNeedNewLine = false;
2413  }
2414 
2415  if (bNeedNewLine) {
2416  a_oOutput.Write(SI_NEWLINE_A);
2417  a_oOutput.Write(SI_NEWLINE_A);
2418  bNeedNewLine = false;
2419  }
2420 
2421  // write the section (unless there is no section name)
2422  if (*iSection->pItem) {
2423  if (!convert.ConvertToStore(iSection->pItem)) {
2424  return SI_FAIL;
2425  }
2426  a_oOutput.Write("[");
2427  a_oOutput.Write(convert.Data());
2428  a_oOutput.Write("]");
2429  a_oOutput.Write(SI_NEWLINE_A);
2430  }
2431 
2432  // get all of the keys sorted in load order
2433  TNamesDepend oKeys;
2434  GetAllKeys(iSection->pItem, oKeys);
2435 #if defined(_MSC_VER) && _MSC_VER <= 1200
2436  oKeys.sort();
2437 #elif defined(__BORLANDC__)
2438  oKeys.sort(Entry::LoadOrder());
2439 #else
2440  oKeys.sort(typename Entry::LoadOrder());
2441 #endif
2442 
2443  // write all keys and values
2444  typename TNamesDepend::const_iterator iKey = oKeys.begin();
2445  for ( ; iKey != oKeys.end(); ++iKey) {
2446  // get all values for this key
2447  TNamesDepend oValues;
2448  GetAllValues(iSection->pItem, iKey->pItem, oValues);
2449 
2450  typename TNamesDepend::const_iterator iValue = oValues.begin();
2451  for ( ; iValue != oValues.end(); ++iValue) {
2452  // write out the comment if there is one
2453  if (iValue->pComment) {
2454  a_oOutput.Write(SI_NEWLINE_A);
2455  if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
2456  return SI_FAIL;
2457  }
2458  }
2459 
2460  // write the key
2461  if (!convert.ConvertToStore(iKey->pItem)) {
2462  return SI_FAIL;
2463  }
2464  a_oOutput.Write(convert.Data());
2465 
2466  // write the value
2467  if (!convert.ConvertToStore(iValue->pItem)) {
2468  return SI_FAIL;
2469  }
2470  a_oOutput.Write(m_bSpaces ? " = " : "=");
2471  if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
2472  // multi-line data needs to be processed specially to ensure
2473  // that we use the correct newline format for the current system
2474  a_oOutput.Write("<<<END_OF_TEXT" SI_NEWLINE_A);
2475  if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
2476  return SI_FAIL;
2477  }
2478  a_oOutput.Write("END_OF_TEXT");
2479  }
2480  else {
2481  a_oOutput.Write(convert.Data());
2482  }
2483  a_oOutput.Write(SI_NEWLINE_A);
2484  }
2485  }
2486 
2487  bNeedNewLine = true;
2488  }
2489 
2490  return SI_OK;
2491 }
2492 
2493 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2494 bool
2496  OutputWriter & a_oOutput,
2497  Converter & a_oConverter,
2498  const SI_CHAR * a_pText
2499  ) const
2500 {
2501  const SI_CHAR * pEndOfLine;
2502  SI_CHAR cEndOfLineChar = *a_pText;
2503  while (cEndOfLineChar) {
2504  // find the end of this line
2505  pEndOfLine = a_pText;
2506  for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ;
2507  cEndOfLineChar = *pEndOfLine;
2508 
2509  // temporarily null terminate, convert and output the line
2510  *const_cast<SI_CHAR*>(pEndOfLine) = 0;
2511  if (!a_oConverter.ConvertToStore(a_pText)) {
2512  return false;
2513  }
2514  *const_cast<SI_CHAR*>(pEndOfLine) = cEndOfLineChar;
2515  a_pText += (pEndOfLine - a_pText) + 1;
2516  a_oOutput.Write(a_oConverter.Data());
2517  a_oOutput.Write(SI_NEWLINE_A);
2518  }
2519  return true;
2520 }
2521 
2522 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2523 bool
2525  const SI_CHAR * a_pSection,
2526  const SI_CHAR * a_pKey,
2527  bool a_bRemoveEmpty
2528  )
2529 {
2530  if (!a_pSection) {
2531  return false;
2532  }
2533 
2534  typename TSection::iterator iSection = m_data.find(a_pSection);
2535  if (iSection == m_data.end()) {
2536  return false;
2537  }
2538 
2539  // remove a single key if we have a keyname
2540  if (a_pKey) {
2541  typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
2542  if (iKeyVal == iSection->second.end()) {
2543  return false;
2544  }
2545 
2546  // remove any copied strings and then the key
2547  typename TKeyVal::iterator iDelete;
2548  do {
2549  iDelete = iKeyVal++;
2550 
2551  DeleteString(iDelete->first.pItem);
2552  DeleteString(iDelete->second);
2553  iSection->second.erase(iDelete);
2554  }
2555  while (iKeyVal != iSection->second.end()
2556  && !IsLess(a_pKey, iKeyVal->first.pItem));
2557 
2558  // done now if the section is not empty or we are not pruning away
2559  // the empty sections. Otherwise let it fall through into the section
2560  // deletion code
2561  if (!a_bRemoveEmpty || !iSection->second.empty()) {
2562  return true;
2563  }
2564  }
2565  else {
2566  // delete all copied strings from this section. The actual
2567  // entries will be removed when the section is removed.
2568  typename TKeyVal::iterator iKeyVal = iSection->second.begin();
2569  for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
2570  DeleteString(iKeyVal->first.pItem);
2571  DeleteString(iKeyVal->second);
2572  }
2573  }
2574 
2575  // delete the section itself
2576  DeleteString(iSection->first.pItem);
2577  m_data.erase(iSection);
2578 
2579  return true;
2580 }
2581 
2582 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2583 void
2585  const SI_CHAR * a_pString
2586  )
2587 {
2588  // strings may exist either inside the data block, or they will be
2589  // individually allocated and stored in m_strings. We only physically
2590  // delete those stored in m_strings.
2591  if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
2592  typename TNamesDepend::iterator i = m_strings.begin();
2593  for (;i != m_strings.end(); ++i) {
2594  if (a_pString == i->pItem) {
2595  delete[] const_cast<SI_CHAR*>(i->pItem);
2596  m_strings.erase(i);
2597  break;
2598  }
2599  }
2600  }
2601 }
2602 
2603 // ---------------------------------------------------------------------------
2604 // CONVERSION FUNCTIONS
2605 // ---------------------------------------------------------------------------
2606 
2607 // Defines the conversion classes for different libraries. Before including
2608 // SimpleIni.h, set the converter that you wish you use by defining one of the
2609 // following symbols.
2610 //
2611 // SI_CONVERT_GENERIC Use the Unicode reference conversion library in
2612 // the accompanying files ConvertUTF.h/c
2613 // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
2614 // ICU headers on include path and icuuc.lib
2615 // SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
2616 
2617 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2618 # ifdef _WIN32
2619 # define SI_CONVERT_WIN32
2620 # else
2621 # define SI_CONVERT_GENERIC
2622 # endif
2623 #endif
2624 
2630 template<class SI_CHAR>
2632  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
2633  long cmp;
2634  for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
2635  cmp = (long) *pLeft - (long) *pRight;
2636  if (cmp != 0) {
2637  return cmp < 0;
2638  }
2639  }
2640  return *pRight != 0;
2641  }
2642 };
2643 
2650 template<class SI_CHAR>
2652  inline SI_CHAR locase(SI_CHAR ch) const {
2653  return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a');
2654  }
2655  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
2656  long cmp;
2657  for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
2658  cmp = (long) locase(*pLeft) - (long) locase(*pRight);
2659  if (cmp != 0) {
2660  return cmp < 0;
2661  }
2662  }
2663  return *pRight != 0;
2664  }
2665 };
2666 
2670 template<class SI_CHAR>
2673 protected:
2675 public:
2676  SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
2677 
2678  /* copy and assignment */
2679  SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); }
2682  return *this;
2683  }
2684 
2699  const char * a_pInputData,
2700  size_t a_uInputDataLen)
2701  {
2702  (void)a_pInputData;
2703  SI_ASSERT(a_uInputDataLen != (size_t) -1);
2704 
2705  // ASCII/MBCS/UTF-8 needs no conversion
2706  return a_uInputDataLen;
2707  }
2708 
2723  const char * a_pInputData,
2724  size_t a_uInputDataLen,
2725  SI_CHAR * a_pOutputData,
2726  size_t a_uOutputDataSize)
2727  {
2728  // ASCII/MBCS/UTF-8 needs no conversion
2729  if (a_uInputDataLen > a_uOutputDataSize) {
2730  return false;
2731  }
2732  memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2733  return true;
2734  }
2735 
2746  size_t SizeToStore(
2747  const SI_CHAR * a_pInputData)
2748  {
2749  // ASCII/MBCS/UTF-8 needs no conversion
2750  return strlen((const char *)a_pInputData) + 1;
2751  }
2752 
2767  const SI_CHAR * a_pInputData,
2768  char * a_pOutputData,
2769  size_t a_uOutputDataSize)
2770  {
2771  // calc input string length (SI_CHAR type and size independent)
2772  size_t uInputLen = strlen((const char *)a_pInputData) + 1;
2773  if (uInputLen > a_uOutputDataSize) {
2774  return false;
2775  }
2776 
2777  // ascii/UTF-8 needs no conversion
2778  memcpy(a_pOutputData, a_pInputData, uInputLen);
2779  return true;
2780  }
2781 };
2782 
2783 
2784 // ---------------------------------------------------------------------------
2785 // SI_CONVERT_GENERIC
2786 // ---------------------------------------------------------------------------
2787 #ifdef SI_CONVERT_GENERIC
2788 
2789 #define SI_Case SI_GenericCase
2790 #define SI_NoCase SI_GenericNoCase
2791 
2792 #include <wchar.h>
2793 #include "ConvertUTF.h"
2794 
2799 template<class SI_CHAR>
2802 protected:
2804 public:
2805  SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
2806 
2807  /* copy and assignment */
2808  SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
2811  return *this;
2812  }
2813 
2828  const char * a_pInputData,
2829  size_t a_uInputDataLen)
2830  {
2831  SI_ASSERT(a_uInputDataLen != (size_t) -1);
2832 
2833  if (m_bStoreIsUtf8) {
2834  // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
2835  // so we just return the same number of characters required as for
2836  // the source text.
2837  return a_uInputDataLen;
2838  }
2839  else {
2840  return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
2841  }
2842  }
2843 
2858  const char * a_pInputData,
2859  size_t a_uInputDataLen,
2860  SI_CHAR * a_pOutputData,
2861  size_t a_uOutputDataSize)
2862  {
2863  if (m_bStoreIsUtf8) {
2864  // This uses the Unicode reference implementation to do the
2865  // conversion from UTF-8 to wchar_t. The required files are
2866  // ConvertUTF.h and ConvertUTF.c which should be included in
2867  // the distribution but are publically available from unicode.org
2868  // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
2869  ConversionResult retval;
2870  const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
2871  if (sizeof(wchar_t) == sizeof(UTF32)) {
2872  UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
2873  retval = ConvertUTF8toUTF32(
2874  &pUtf8, pUtf8 + a_uInputDataLen,
2875  &pUtf32, pUtf32 + a_uOutputDataSize,
2877  }
2878  else if (sizeof(wchar_t) == sizeof(UTF16)) {
2879  UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
2880  retval = ConvertUTF8toUTF16(
2881  &pUtf8, pUtf8 + a_uInputDataLen,
2882  &pUtf16, pUtf16 + a_uOutputDataSize,
2884  }
2885  return retval == conversionOK;
2886  }
2887  else {
2888  size_t retval = mbstowcs(a_pOutputData,
2889  a_pInputData, a_uOutputDataSize);
2890  return retval != (size_t)(-1);
2891  }
2892  }
2893 
2904  size_t SizeToStore(
2905  const SI_CHAR * a_pInputData)
2906  {
2907  if (m_bStoreIsUtf8) {
2908  // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
2909  size_t uLen = 0;
2910  while (a_pInputData[uLen]) {
2911  ++uLen;
2912  }
2913  return (6 * uLen) + 1;
2914  }
2915  else {
2916  size_t uLen = wcstombs(NULL, a_pInputData, 0);
2917  if (uLen == (size_t)(-1)) {
2918  return uLen;
2919  }
2920  return uLen + 1; // include NULL terminator
2921  }
2922  }
2923 
2938  const SI_CHAR * a_pInputData,
2939  char * a_pOutputData,
2940  size_t a_uOutputDataSize
2941  )
2942  {
2943  if (m_bStoreIsUtf8) {
2944  // calc input string length (SI_CHAR type and size independent)
2945  size_t uInputLen = 0;
2946  while (a_pInputData[uInputLen]) {
2947  ++uInputLen;
2948  }
2949  ++uInputLen; // include the NULL char
2950 
2951  // This uses the Unicode reference implementation to do the
2952  // conversion from wchar_t to UTF-8. The required files are
2953  // ConvertUTF.h and ConvertUTF.c which should be included in
2954  // the distribution but are publically available from unicode.org
2955  // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
2956  ConversionResult retval;
2957  UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
2958  if (sizeof(wchar_t) == sizeof(UTF32)) {
2959  const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
2960  retval = ConvertUTF32toUTF8(
2961  &pUtf32, pUtf32 + uInputLen,
2962  &pUtf8, pUtf8 + a_uOutputDataSize,
2964  }
2965  else if (sizeof(wchar_t) == sizeof(UTF16)) {
2966  const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
2967  retval = ConvertUTF16toUTF8(
2968  &pUtf16, pUtf16 + uInputLen,
2969  &pUtf8, pUtf8 + a_uOutputDataSize,
2971  }
2972  return retval == conversionOK;
2973  }
2974  else {
2975  size_t retval = wcstombs(a_pOutputData,
2976  a_pInputData, a_uOutputDataSize);
2977  return retval != (size_t) -1;
2978  }
2979  }
2980 };
2981 
2982 #endif // SI_CONVERT_GENERIC
2983 
2984 
2985 // ---------------------------------------------------------------------------
2986 // SI_CONVERT_ICU
2987 // ---------------------------------------------------------------------------
2988 #ifdef SI_CONVERT_ICU
2989 
2990 #define SI_Case SI_GenericCase
2991 #define SI_NoCase SI_GenericNoCase
2992 
2993 #include <unicode/ucnv.h>
2994 
2998 template<class SI_CHAR>
2999 class SI_ConvertW {
3000  const char * m_pEncoding;
3001  UConverter * m_pConverter;
3002 protected:
3003  SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { }
3004 public:
3005  SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) {
3006  m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL;
3007  }
3008 
3009  /* copy and assignment */
3010  SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
3011  SI_ConvertW & operator=(const SI_ConvertW & rhs) {
3012  m_pEncoding = rhs.m_pEncoding;
3013  m_pConverter = NULL;
3014  return *this;
3015  }
3016  ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); }
3017 
3031  size_t SizeFromStore(
3032  const char * a_pInputData,
3033  size_t a_uInputDataLen)
3034  {
3035  SI_ASSERT(a_uInputDataLen != (size_t) -1);
3036 
3037  UErrorCode nError;
3038 
3039  if (!m_pConverter) {
3040  nError = U_ZERO_ERROR;
3041  m_pConverter = ucnv_open(m_pEncoding, &nError);
3042  if (U_FAILURE(nError)) {
3043  return (size_t) -1;
3044  }
3045  }
3046 
3047  nError = U_ZERO_ERROR;
3048  int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
3049  a_pInputData, (int32_t) a_uInputDataLen, &nError);
3050  if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3051  return (size_t) -1;
3052  }
3053 
3054  return (size_t) nLen;
3055  }
3056 
3070  bool ConvertFromStore(
3071  const char * a_pInputData,
3072  size_t a_uInputDataLen,
3073  UChar * a_pOutputData,
3074  size_t a_uOutputDataSize)
3075  {
3076  UErrorCode nError;
3077 
3078  if (!m_pConverter) {
3079  nError = U_ZERO_ERROR;
3080  m_pConverter = ucnv_open(m_pEncoding, &nError);
3081  if (U_FAILURE(nError)) {
3082  return false;
3083  }
3084  }
3085 
3086  nError = U_ZERO_ERROR;
3087  ucnv_toUChars(m_pConverter,
3088  a_pOutputData, (int32_t) a_uOutputDataSize,
3089  a_pInputData, (int32_t) a_uInputDataLen, &nError);
3090  if (U_FAILURE(nError)) {
3091  return false;
3092  }
3093 
3094  return true;
3095  }
3096 
3107  size_t SizeToStore(
3108  const UChar * a_pInputData)
3109  {
3110  UErrorCode nError;
3111 
3112  if (!m_pConverter) {
3113  nError = U_ZERO_ERROR;
3114  m_pConverter = ucnv_open(m_pEncoding, &nError);
3115  if (U_FAILURE(nError)) {
3116  return (size_t) -1;
3117  }
3118  }
3119 
3120  nError = U_ZERO_ERROR;
3121  int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
3122  a_pInputData, -1, &nError);
3123  if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3124  return (size_t) -1;
3125  }
3126 
3127  return (size_t) nLen + 1;
3128  }
3129 
3143  bool ConvertToStore(
3144  const UChar * a_pInputData,
3145  char * a_pOutputData,
3146  size_t a_uOutputDataSize)
3147  {
3148  UErrorCode nError;
3149 
3150  if (!m_pConverter) {
3151  nError = U_ZERO_ERROR;
3152  m_pConverter = ucnv_open(m_pEncoding, &nError);
3153  if (U_FAILURE(nError)) {
3154  return false;
3155  }
3156  }
3157 
3158  nError = U_ZERO_ERROR;
3159  ucnv_fromUChars(m_pConverter,
3160  a_pOutputData, (int32_t) a_uOutputDataSize,
3161  a_pInputData, -1, &nError);
3162  if (U_FAILURE(nError)) {
3163  return false;
3164  }
3165 
3166  return true;
3167  }
3168 };
3169 
3170 #endif // SI_CONVERT_ICU
3171 
3172 
3173 // ---------------------------------------------------------------------------
3174 // SI_CONVERT_WIN32
3175 // ---------------------------------------------------------------------------
3176 #ifdef SI_CONVERT_WIN32
3177 
3178 #define SI_Case SI_GenericCase
3179 
3180 // Windows CE doesn't have errno or MBCS libraries
3181 #ifdef _WIN32_WCE
3182 # ifndef SI_NO_MBCS
3183 # define SI_NO_MBCS
3184 # endif
3185 #endif
3186 
3187 #include <windows.h>
3188 #ifdef SI_NO_MBCS
3189 # define SI_NoCase SI_GenericNoCase
3190 #else // !SI_NO_MBCS
3191 
3199 #include <mbstring.h>
3200 template<class SI_CHAR>
3201 struct SI_NoCase {
3202  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
3203  if (sizeof(SI_CHAR) == sizeof(char)) {
3204  return _mbsicmp((const unsigned char *)pLeft,
3205  (const unsigned char *)pRight) < 0;
3206  }
3207  if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
3208  return _wcsicmp((const wchar_t *)pLeft,
3209  (const wchar_t *)pRight) < 0;
3210  }
3211  return SI_GenericNoCase<SI_CHAR>()(pLeft, pRight);
3212  }
3213 };
3214 #endif // SI_NO_MBCS
3215 
3222 template<class SI_CHAR>
3223 class SI_ConvertW {
3224  UINT m_uCodePage;
3225 protected:
3226  SI_ConvertW() { }
3227 public:
3228  SI_ConvertW(bool a_bStoreIsUtf8) {
3229  m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
3230  }
3231 
3232  /* copy and assignment */
3233  SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
3234  SI_ConvertW & operator=(const SI_ConvertW & rhs) {
3235  m_uCodePage = rhs.m_uCodePage;
3236  return *this;
3237  }
3238 
3252  size_t SizeFromStore(
3253  const char * a_pInputData,
3254  size_t a_uInputDataLen)
3255  {
3256  SI_ASSERT(a_uInputDataLen != (size_t) -1);
3257 
3258  int retval = MultiByteToWideChar(
3259  m_uCodePage, 0,
3260  a_pInputData, (int) a_uInputDataLen,
3261  0, 0);
3262  return (size_t)(retval > 0 ? retval : -1);
3263  }
3264 
3278  bool ConvertFromStore(
3279  const char * a_pInputData,
3280  size_t a_uInputDataLen,
3281  SI_CHAR * a_pOutputData,
3282  size_t a_uOutputDataSize)
3283  {
3284  int nSize = MultiByteToWideChar(
3285  m_uCodePage, 0,
3286  a_pInputData, (int) a_uInputDataLen,
3287  (wchar_t *) a_pOutputData, (int) a_uOutputDataSize);
3288  return (nSize > 0);
3289  }
3290 
3301  size_t SizeToStore(
3302  const SI_CHAR * a_pInputData)
3303  {
3304  int retval = WideCharToMultiByte(
3305  m_uCodePage, 0,
3306  (const wchar_t *) a_pInputData, -1,
3307  0, 0, 0, 0);
3308  return (size_t) (retval > 0 ? retval : -1);
3309  }
3310 
3324  bool ConvertToStore(
3325  const SI_CHAR * a_pInputData,
3326  char * a_pOutputData,
3327  size_t a_uOutputDataSize)
3328  {
3329  int retval = WideCharToMultiByte(
3330  m_uCodePage, 0,
3331  (const wchar_t *) a_pInputData, -1,
3332  a_pOutputData, (int) a_uOutputDataSize, 0, 0);
3333  return retval > 0;
3334  }
3335 };
3336 
3337 #endif // SI_CONVERT_WIN32
3338 
3339 
3340 // ---------------------------------------------------------------------------
3341 // TYPE DEFINITIONS
3342 // ---------------------------------------------------------------------------
3343 
3344 typedef CSimpleIniTempl<char,
3345  SI_NoCase<char>,SI_ConvertA<char> > CSimpleIniA;
3346 typedef CSimpleIniTempl<char,
3348 
3349 #if defined(SI_CONVERT_ICU)
3350 typedef CSimpleIniTempl<UChar,
3351  SI_NoCase<UChar>,SI_ConvertW<UChar> > CSimpleIniW;
3352 typedef CSimpleIniTempl<UChar,
3353  SI_Case<UChar>,SI_ConvertW<UChar> > CSimpleIniCaseW;
3354 #else
3355 typedef CSimpleIniTempl<wchar_t,
3356  SI_NoCase<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniW;
3357 typedef CSimpleIniTempl<wchar_t,
3359 #endif
3360 
3361 #ifdef _UNICODE
3362 # define CSimpleIni CSimpleIniW
3363 # define CSimpleIniCase CSimpleIniCaseW
3364 # define SI_NEWLINE SI_NEWLINE_W
3365 #else // !_UNICODE
3366 # define CSimpleIni CSimpleIniA
3367 # define CSimpleIniCase CSimpleIniCaseA
3368 # define SI_NEWLINE SI_NEWLINE_A
3369 #endif // _UNICODE
3370 
3371 #ifdef _MSC_VER
3372 # pragma warning (pop)
3373 #endif
3374 
3375 #endif // INCLUDED_SimpleIni_h
3376 
CSimpleIniTempl::FileWriter::Write
void Write(const char *a_pBuf)
Definition: SimpleIni.h:380
CSimpleIniTempl::StringWriter
Definition: SimpleIni.h:389
SI_ConvertA::operator=
SI_ConvertA & operator=(const SI_ConvertA &rhs)
Definition: SimpleIni.h:2680
CSimpleIniTempl::m_bAllowMultiKey
bool m_bAllowMultiKey
Definition: SimpleIni.h:1236
CSimpleIniTempl::operator=
CSimpleIniTempl & operator=(const CSimpleIniTempl &)
SI_ConvertW::m_bStoreIsUtf8
bool m_bStoreIsUtf8
Definition: SimpleIni.h:2801
CSimpleIniTempl::IsSpace
bool IsSpace(SI_CHAR ch) const
Definition: SimpleIni.h:1163
CSimpleIniTempl::Entry::pComment
const SI_CHAR * pComment
Definition: SimpleIni.h:299
SI_ConvertW::SizeFromStore
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Definition: SimpleIni.h:2827
CSimpleIniTempl::SetMultiKey
void SetMultiKey(bool a_bAllowMultiKey=true)
Definition: SimpleIni.h:513
conversionOK
@ conversionOK
Definition: ConvertUTF.h:103
CSimpleIniCaseW
CSimpleIniTempl< wchar_t, SI_Case< wchar_t >, SI_ConvertW< wchar_t > > CSimpleIniCaseW
Definition: SimpleIni.h:3358
CSimpleIniTempl::SetUnicode
void SetUnicode(bool a_bIsUtf8=true)
Definition: SimpleIni.h:488
SI_FAIL
@ SI_FAIL
Generic failure.
Definition: SimpleIni.h:241
SI_ASSERT
#define SI_ASSERT(x)
Definition: SimpleIni.h:232
CSimpleIniTempl::IsMultiLine
bool IsMultiLine() const
Definition: SimpleIni.h:532
CSimpleIniTempl::IsMultiLineData
bool IsMultiLineData(const SI_CHAR *a_pData) const
Definition: SimpleIni.h:1649
CSimpleIniTempl::FindFileComment
SI_Error FindFileComment(SI_CHAR *&a_pData, bool a_bCopyStrings)
Definition: SimpleIni.h:1476
ConvertUTF8toUTF16
ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
Definition: ConvertUTF.c:336
CSimpleIniW
CSimpleIniTempl< wchar_t, SI_NoCase< wchar_t >, SI_ConvertW< wchar_t > > CSimpleIniW
Definition: SimpleIni.h:3356
SI_GenericNoCase
Definition: SimpleIni.h:2651
CSimpleIniTempl::FileWriter::operator=
FileWriter & operator=(const FileWriter &)
CSimpleIniTempl::StringWriter::operator=
StringWriter & operator=(const StringWriter &)
CSimpleIniTempl::Converter
Definition: SimpleIni.h:419
operator>
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bool operator>(const bfloat16 &a, const bfloat16 &b)
c
Scalar Scalar * c
ConversionResult
ConversionResult
Definition: ConvertUTF.h:102
CSimpleIniA
CSimpleIniTempl< char, SI_NoCase< char >, SI_ConvertA< char > > CSimpleIniA
Definition: SimpleIni.h:3345
ConvertUTF8toUTF32
ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd, UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
Definition: ConvertUTF.c:462
CSimpleIniTempl::m_pData
SI_CHAR * m_pData
Definition: SimpleIni.h:1212
CSimpleIniTempl::Converter::Data
const char * Data()
Definition: SimpleIni.h:442
SI_ConvertW::SI_ConvertW
SI_ConvertW()
Definition: SimpleIni.h:2803
CSimpleIniTempl::GetAllSections
void GetAllSections(TNamesDepend &a_names) const
Definition: SimpleIni.h:2267
SI_NEWLINE_A
#define SI_NEWLINE_A
Definition: SimpleIni.h:252
CSimpleIniTempl
Definition: SimpleIni.h:293
CSimpleIniTempl::Entry::operator=
Entry & operator=(const Entry &rhs)
Definition: SimpleIni.h:313
CSimpleIniTempl::OutputWriter::operator=
OutputWriter & operator=(const OutputWriter &)
CSimpleIniTempl::UsingSpaces
bool UsingSpaces() const
Definition: SimpleIni.h:545
CSimpleIniTempl::IsEmpty
bool IsEmpty() const
Definition: SimpleIni.h:469
CSimpleIniTempl::GetConverter
Converter GetConverter() const
Definition: SimpleIni.h:1100
CSimpleIniTempl::IsComment
bool IsComment(SI_CHAR ch) const
Definition: SimpleIni.h:1168
SI_ConvertA::SI_ConvertA
SI_ConvertA(bool a_bStoreIsUtf8)
Definition: SimpleIni.h:2676
SI_ConvertA::ConvertFromStore
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Definition: SimpleIni.h:2722
CSimpleIniTempl::Reset
void Reset()
Definition: SimpleIni.h:1278
CSimpleIniTempl::IsMultiLineTag
bool IsMultiLineTag(const SI_CHAR *a_pData) const
Definition: SimpleIni.h:1636
SI_ConvertW::operator=
SI_ConvertW & operator=(const SI_ConvertW &rhs)
Definition: SimpleIni.h:2809
true
#define true
Definition: ConvertUTF.c:57
CSimpleIniTempl::Entry::LoadOrder::operator()
bool operator()(const Entry &lhs, const Entry &rhs) const
Definition: SimpleIni.h:342
CSimpleIniTempl::SetBoolValue
SI_Error SetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bValue, const SI_CHAR *a_pComment=NULL, bool a_bForceReplace=false)
Definition: SimpleIni.h:2156
SI_NOMEM
@ SI_NOMEM
Out of memory error.
Definition: SimpleIni.h:242
CSimpleIniTempl::FileWriter
Definition: SimpleIni.h:376
ConvertUTF16toUTF8
ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
Definition: ConvertUTF.c:214
CSimpleIniTempl::DeleteString
void DeleteString(const SI_CHAR *a_pString)
Definition: SimpleIni.h:2584
SI_UTF8_SIGNATURE
#define SI_UTF8_SIGNATURE
Definition: SimpleIni.h:246
CSimpleIniTempl::OutputWriter::OutputWriter
OutputWriter()
Definition: SimpleIni.h:367
SI_ConvertW::ConvertFromStore
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Definition: SimpleIni.h:2857
CSimpleIniTempl::SaveFile
SI_Error SaveFile(const char *a_pszFile, bool a_bAddSignature=true) const
Definition: SimpleIni.h:2311
CSimpleIniTempl::Converter::m_scratch
std::string m_scratch
Definition: SimpleIni.h:444
CSimpleIniTempl::FindEntry
bool FindEntry(SI_CHAR *&a_pData, const SI_CHAR *&a_pSection, const SI_CHAR *&a_pKey, const SI_CHAR *&a_pVal, const SI_CHAR *&a_pComment) const
Definition: SimpleIni.h:1503
n
int n
SI_FILE
@ SI_FILE
File error (see errno for detail error)
Definition: SimpleIni.h:243
CSimpleIniTempl::m_bAllowMultiLine
bool m_bAllowMultiLine
Definition: SimpleIni.h:1239
CSimpleIniTempl::IsMultiKey
bool IsMultiKey() const
Definition: SimpleIni.h:518
CSimpleIniTempl::Save
SI_Error Save(std::string &a_sBuffer, bool a_bAddSignature=false) const
Definition: SimpleIni.h:744
CSimpleIniTempl::Entry::Entry
Entry(const SI_CHAR *a_pszItem=NULL, int a_nOrder=0)
Definition: SimpleIni.h:302
CSimpleIniTempl::IsLess
bool IsLess(const SI_CHAR *a_pLeft, const SI_CHAR *a_pRight) const
Definition: SimpleIni.h:1185
CSimpleIniTempl::OutputMultiLineText
bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter, const SI_CHAR *a_pText) const
Definition: SimpleIni.h:2495
SI_ConvertW::SI_ConvertW
SI_ConvertW(const SI_ConvertW &rhs)
Definition: SimpleIni.h:2808
SI_ConvertA::SI_ConvertA
SI_ConvertA()
Definition: SimpleIni.h:2674
SI_GenericNoCase::locase
SI_CHAR locase(SI_CHAR ch) const
Definition: SimpleIni.h:2652
SI_ConvertW
Definition: SimpleIni.h:2800
CSimpleIniTempl::FileWriter::FileWriter
FileWriter(FILE *a_file)
Definition: SimpleIni.h:379
CSimpleIniTempl::OutputWriter::~OutputWriter
virtual ~OutputWriter()
Definition: SimpleIni.h:368
CSimpleIniTempl::FileWriter::m_file
FILE * m_file
Definition: SimpleIni.h:377
CSimpleIniTempl::m_bSpaces
bool m_bSpaces
Definition: SimpleIni.h:1242
CSimpleIniCaseA
CSimpleIniTempl< char, SI_Case< char >, SI_ConvertA< char > > CSimpleIniCaseA
Definition: SimpleIni.h:3347
CSimpleIniTempl::m_nOrder
int m_nOrder
Definition: SimpleIni.h:1247
IsSpace
bool IsSpace(char ch)
CSimpleIniTempl::Entry::LoadOrder::result_type
bool result_type
Definition: SimpleIni.h:339
SI_GenericCase::operator()
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
Definition: SimpleIni.h:2632
SI_ConvertA::SizeToStore
size_t SizeToStore(const SI_CHAR *a_pInputData)
Definition: SimpleIni.h:2746
UTF8
unsigned char UTF8
Definition: ConvertUTF.h:92
CSimpleIniTempl::StringWriter::StringWriter
StringWriter(std::string &a_string)
Definition: SimpleIni.h:392
CSimpleIniTempl::Entry
Definition: SimpleIni.h:297
CSimpleIniTempl::GetAllKeys
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Definition: SimpleIni.h:2280
CSimpleIniTempl::Converter::Converter
Converter(const Converter &rhs)
Definition: SimpleIni.h:424
CSimpleIniTempl::Converter::Converter
Converter(bool a_bStoreIsUtf8)
Definition: SimpleIni.h:421
CSimpleIniTempl::SetValue
SI_Error SetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, const SI_CHAR *a_pComment=NULL, bool a_bForceReplace=false)
Definition: SimpleIni.h:968
CSimpleIniTempl::m_bStoreIsUtf8
bool m_bStoreIsUtf8
Definition: SimpleIni.h:1233
CSimpleIniTempl::m_data
TSection m_data
Definition: SimpleIni.h:1224
CSimpleIniTempl::LoadFile
SI_Error LoadFile(const char *a_pszFile)
Definition: SimpleIni.h:1301
CSimpleIniTempl::~CSimpleIniTempl
~CSimpleIniTempl()
Definition: SimpleIni.h:1271
CSimpleIniTempl::TKeyVal
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
Definition: SimpleIni.h:352
SI_OK
@ SI_OK
No error.
Definition: SimpleIni.h:236
CSimpleIniTempl::GetBoolValue
bool GetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bDefault=false, bool *a_pHasMultiple=NULL) const
Definition: SimpleIni.h:2121
CSimpleIniTempl::OutputWriter
Definition: SimpleIni.h:365
lenientConversion
@ lenientConversion
Definition: ConvertUTF.h:111
CSimpleIniTempl::Delete
bool Delete(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bRemoveEmpty=false)
Definition: SimpleIni.h:2524
CSimpleIniTempl::Save
SI_Error Save(OutputWriter &a_oOutput, bool a_bAddSignature=false) const
Definition: SimpleIni.h:2368
size_t
std::size_t size_t
SI_ConvertA::SI_ConvertA
SI_ConvertA(const SI_ConvertA &rhs)
Definition: SimpleIni.h:2679
UTF16
unsigned short UTF16
Definition: ConvertUTF.h:91
ConvertUTF32toUTF8
ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd, UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
Definition: ConvertUTF.c:409
CSimpleIniTempl::Converter::ConvertToStore
bool ConvertToStore(const SI_CHAR *a_pszString)
Definition: SimpleIni.h:429
CSimpleIniTempl::Entry::KeyOrder::result_type
bool result_type
Definition: SimpleIni.h:328
CSimpleIniTempl::StringWriter::Write
void Write(const char *a_pBuf)
Definition: SimpleIni.h:393
CSimpleIniTempl::GetSection
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Definition: SimpleIni.h:2252
CSimpleIniTempl::Entry::Entry
Entry(const SI_CHAR *a_pszItem, const SI_CHAR *a_pszComment, int a_nOrder)
Definition: SimpleIni.h:307
operator<
bool operator<(const benchmark_t &b1, const benchmark_t &b2)
SI_Error
SI_Error
Definition: SimpleIni.h:235
Write
int Write(int fd, const void *buf, unsigned int count)
CSimpleIniTempl::GetValue
const SI_CHAR * GetValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pDefault=NULL, bool *a_pHasMultiple=NULL) const
Definition: SimpleIni.h:1951
empty
SI_ConvertA::m_bStoreIsUtf8
bool m_bStoreIsUtf8
Definition: SimpleIni.h:2672
SI_ConvertA
Definition: SimpleIni.h:2671
ConvertUTF.h
CSimpleIniTempl::SetDoubleValue
SI_Error SetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nValue, const SI_CHAR *a_pComment=NULL, bool a_bForceReplace=false)
Definition: SimpleIni.h:2090
CSimpleIniTempl::m_uDataLen
size_t m_uDataLen
Definition: SimpleIni.h:1218
CSimpleIniTempl::GetDoubleValue
double GetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nDefault=0, bool *a_pHasMultiple=NULL) const
Definition: SimpleIni.h:2059
CSimpleIniTempl::StringWriter::m_string
std::string & m_string
Definition: SimpleIni.h:390
CSimpleIniTempl::GetLongValue
long GetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nDefault=0, bool *a_pHasMultiple=NULL) const
Definition: SimpleIni.h:1988
CSimpleIniTempl::CopyString
SI_Error CopyString(const SI_CHAR *&a_pString)
Definition: SimpleIni.h:1819
CSimpleIniTempl::Entry::KeyOrder
Definition: SimpleIni.h:327
CSimpleIniTempl::LoadData
SI_Error LoadData(const std::string &a_strData)
Definition: SimpleIni.h:604
CSimpleIniTempl::GetSectionSize
int GetSectionSize(const SI_CHAR *a_pSection) const
Definition: SimpleIni.h:2217
SI_ConvertA::ConvertToStore
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Definition: SimpleIni.h:2766
SI_INSERTED
@ SI_INSERTED
A new value was inserted.
Definition: SimpleIni.h:238
SI_ConvertW::SizeToStore
size_t SizeToStore(const SI_CHAR *a_pInputData)
Definition: SimpleIni.h:2904
SI_ConvertW::SI_ConvertW
SI_ConvertW(bool a_bStoreIsUtf8)
Definition: SimpleIni.h:2805
SI_ConvertW::ConvertToStore
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Definition: SimpleIni.h:2937
CSimpleIniTempl::AddEntry
SI_Error AddEntry(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, const SI_CHAR *a_pComment, bool a_bForceReplace, bool a_bCopyStrings)
Definition: SimpleIni.h:1846
CSimpleIniTempl::IsUnicode
bool IsUnicode() const
Definition: SimpleIni.h:493
SI_GenericNoCase::operator()
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
Definition: SimpleIni.h:2655
operator()
internal::enable_if< symbolic::is_symbolic< IndexType >::value, CoeffReturnType >::type operator()(const IndexType &id) EIGEN_INDEXED_VIEW_METHOD_CONST
SI_NoCase
#define SI_NoCase
Definition: SimpleIni.h:2790
CSimpleIniTempl::SkipNewLine
void SkipNewLine(SI_CHAR *&a_pData) const
Definition: SimpleIni.h:1174
CSimpleIniTempl::IsNewLineChar
bool IsNewLineChar(SI_CHAR a_c) const
Definition: SimpleIni.h:1686
CSimpleIniTempl::m_pFileComment
const SI_CHAR * m_pFileComment
Definition: SimpleIni.h:1221
CSimpleIniTempl::m_strings
TNamesDepend m_strings
Definition: SimpleIni.h:1230
SI_GenericCase
Definition: SimpleIni.h:2631
NULL
#define NULL
SI_UPDATED
@ SI_UPDATED
An existing value was updated.
Definition: SimpleIni.h:237
CSimpleIniTempl::TNamesDepend
std::list< Entry > TNamesDepend
Definition: SimpleIni.h:360
CSimpleIniTempl::TSection
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
Definition: SimpleIni.h:355
CSimpleIniTempl::GetAllValues
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Definition: SimpleIni.h:2182
UTF32
unsigned int UTF32
Definition: ConvertUTF.h:90
CSimpleIniTempl::Entry::LoadOrder
Definition: SimpleIni.h:338
SI_ConvertA::SizeFromStore
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Definition: SimpleIni.h:2698
CSimpleIniTempl::LoadMultiLineText
bool LoadMultiLineText(SI_CHAR *&a_pData, const SI_CHAR *&a_pVal, const SI_CHAR *a_pTagName, bool a_bAllowBlankLinesInComment=false) const
Definition: SimpleIni.h:1695
CSimpleIniTempl::SetSpaces
void SetSpaces(bool a_bSpaces=true)
Definition: SimpleIni.h:540
CSimpleIniTempl::SetLongValue
SI_Error SetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nValue, const SI_CHAR *a_pComment=NULL, bool a_bUseHex=false, bool a_bForceReplace=false)
Definition: SimpleIni.h:2027
CSimpleIniTempl::Entry::Entry
Entry(const Entry &rhs)
Definition: SimpleIni.h:312
i
int i
CSimpleIniTempl::CSimpleIniTempl
CSimpleIniTempl(bool a_bIsUtf8=false, bool a_bMultiKey=false, bool a_bMultiLine=false)
Definition: SimpleIni.h:1255
int32_t
::int32_t int32_t
CSimpleIniTempl::SetMultiLine
void SetMultiLine(bool a_bAllowMultiLine=true)
Definition: SimpleIni.h:527
CSimpleIniTempl::Entry::nOrder
int nOrder
Definition: SimpleIni.h:300
lhs
YYCODETYPE lhs
Definition: sqlite3.c:116033
CSimpleIniTempl::Entry::pItem
const SI_CHAR * pItem
Definition: SimpleIni.h:298
CSimpleIniTempl::Converter::operator=
Converter & operator=(const Converter &rhs)
Definition: SimpleIni.h:425
CSimpleIniTempl::Entry::KeyOrder::operator()
bool operator()(const Entry &lhs, const Entry &rhs) const
Definition: SimpleIni.h:331
CSimpleIniTempl::OutputWriter::Write
virtual void Write(const char *a_pBuf)=0


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Jul 1 2024 02:42:33