SimpleIni  4.17
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:
296  typedef SI_CHAR SI_CHAR_T;
297 
299  struct Entry {
300  const SI_CHAR * pItem;
301  const SI_CHAR * pComment;
302  int nOrder;
303 
304  Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0)
305  : pItem(a_pszItem)
306  , pComment(NULL)
307  , nOrder(a_nOrder)
308  { }
309  Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder)
310  : pItem(a_pszItem)
311  , pComment(a_pszComment)
312  , nOrder(a_nOrder)
313  { }
314  Entry(const Entry & rhs) { operator=(rhs); }
315  Entry & operator=(const Entry & rhs) {
316  pItem = rhs.pItem;
317  pComment = rhs.pComment;
318  nOrder = rhs.nOrder;
319  return *this;
320  }
321 
322 #if defined(_MSC_VER) && _MSC_VER <= 1200
323 
324  bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
325  bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
326 #endif
327 
329  struct KeyOrder : std::binary_function<Entry, Entry, bool> {
330  bool operator()(const Entry & lhs, const Entry & rhs) const {
331  const static SI_STRLESS isLess = SI_STRLESS();
332  return isLess(lhs.pItem, rhs.pItem);
333  }
334  };
335 
337  struct LoadOrder : std::binary_function<Entry, Entry, bool> {
338  bool operator()(const Entry & lhs, const Entry & rhs) const {
339  if (lhs.nOrder != rhs.nOrder) {
340  return lhs.nOrder < rhs.nOrder;
341  }
342  return KeyOrder()(lhs.pItem, rhs.pItem);
343  }
344  };
345  };
346 
348  typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder> TKeyVal;
349 
351  typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder> TSection;
352 
356  typedef std::list<Entry> TNamesDepend;
357 
361  class OutputWriter {
362  public:
364  virtual ~OutputWriter() { }
365  virtual void Write(const char * a_pBuf) = 0;
366  private:
367  OutputWriter(const OutputWriter &); // disable
368  OutputWriter & operator=(const OutputWriter &); // disable
369  };
370 
372  class FileWriter : public OutputWriter {
373  FILE * m_file;
374  public:
375  FileWriter(FILE * a_file) : m_file(a_file) { }
376  void Write(const char * a_pBuf) {
377  fputs(a_pBuf, m_file);
378  }
379  private:
380  FileWriter(const FileWriter &); // disable
381  FileWriter & operator=(const FileWriter &); // disable
382  };
383 
385  class StringWriter : public OutputWriter {
386  std::string & m_string;
387  public:
388  StringWriter(std::string & a_string) : m_string(a_string) { }
389  void Write(const char * a_pBuf) {
390  m_string.append(a_pBuf);
391  }
392  private:
393  StringWriter(const StringWriter &); // disable
394  StringWriter & operator=(const StringWriter &); // disable
395  };
396 
397 #ifdef SI_SUPPORT_IOSTREAMS
398 
399  class StreamWriter : public OutputWriter {
400  std::ostream & m_ostream;
401  public:
402  StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { }
403  void Write(const char * a_pBuf) {
404  m_ostream << a_pBuf;
405  }
406  private:
407  StreamWriter(const StreamWriter &); // disable
408  StreamWriter & operator=(const StreamWriter &); // disable
409  };
410 #endif // SI_SUPPORT_IOSTREAMS
411 
415  class Converter : private SI_CONVERTER {
416  public:
417  using SI_CONVERTER::SizeToStore;
418  Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
419  m_scratch.resize(1024);
420  }
421  Converter(const Converter & rhs) { operator=(rhs); }
422  Converter & operator=(const Converter & rhs) {
423  m_scratch = rhs.m_scratch;
424  return *this;
425  }
426  bool ConvertToStore(const SI_CHAR * a_pszString) {
427  size_t uLen = SizeToStore(a_pszString);
428  if (uLen == (size_t)(-1)) {
429  return false;
430  }
431  while (uLen > m_scratch.size()) {
432  m_scratch.resize(m_scratch.size() * 2);
433  }
434  return SI_CONVERTER::ConvertToStore(
435  a_pszString,
436  const_cast<char*>(m_scratch.data()),
437  m_scratch.size());
438  }
439  const char * Data() { return m_scratch.data(); }
440  private:
441  std::string m_scratch;
442  };
443 
444 public:
445  /*-----------------------------------------------------------------------*/
446 
454  bool a_bIsUtf8 = false,
455  bool a_bMultiKey = false,
456  bool a_bMultiLine = false
457  );
458 
461 
463  void Reset();
464 
466  bool IsEmpty() const { return m_data.empty(); }
467 
468  /*-----------------------------------------------------------------------*/
485  void SetUnicode(bool a_bIsUtf8 = true) {
486  if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
487  }
488 
490  bool IsUnicode() const { return m_bStoreIsUtf8; }
491 
510  void SetMultiKey(bool a_bAllowMultiKey = true) {
511  m_bAllowMultiKey = a_bAllowMultiKey;
512  }
513 
515  bool IsMultiKey() const { return m_bAllowMultiKey; }
516 
524  void SetMultiLine(bool a_bAllowMultiLine = true) {
525  m_bAllowMultiLine = a_bAllowMultiLine;
526  }
527 
529  bool IsMultiLine() const { return m_bAllowMultiLine; }
530 
537  void SetSpaces(bool a_bSpaces = true) {
538  m_bSpaces = a_bSpaces;
539  }
540 
542  bool UsingSpaces() const { return m_bSpaces; }
543 
544  /*-----------------------------------------------------------------------*/
557  const char * a_pszFile
558  );
559 
560 #ifdef SI_HAS_WIDE_FILE
561 
568  const SI_WCHAR_T * a_pwszFile
569  );
570 #endif // SI_HAS_WIDE_FILE
571 
580  FILE * a_fpFile
581  );
582 
583 #ifdef SI_SUPPORT_IOSTREAMS
584 
591  std::istream & a_istream
592  );
593 #endif // SI_SUPPORT_IOSTREAMS
594 
601  SI_Error LoadData(const std::string & a_strData) {
602  return LoadData(a_strData.c_str(), a_strData.size());
603  }
604 
613  const char * a_pData,
614  size_t a_uDataLen
615  );
616 
617  /*-----------------------------------------------------------------------*/
634  const char * a_pszFile,
635  bool a_bAddSignature = true
636  ) const;
637 
638 #ifdef SI_HAS_WIDE_FILE
639 
650  const SI_WCHAR_T * a_pwszFile,
651  bool a_bAddSignature = true
652  ) const;
653 #endif // _WIN32
654 
668  FILE * a_pFile,
669  bool a_bAddSignature = false
670  ) const;
671 
703  SI_Error Save(
704  OutputWriter & a_oOutput,
705  bool a_bAddSignature = false
706  ) const;
707 
708 #ifdef SI_SUPPORT_IOSTREAMS
709 
721  std::ostream & a_ostream,
722  bool a_bAddSignature = false
723  ) const
724  {
725  StreamWriter writer(a_ostream);
726  return Save(writer, a_bAddSignature);
727  }
728 #endif // SI_SUPPORT_IOSTREAMS
729 
742  std::string & a_sBuffer,
743  bool a_bAddSignature = false
744  ) const
745  {
746  StringWriter writer(a_sBuffer);
747  return Save(writer, a_bAddSignature);
748  }
749 
750  /*-----------------------------------------------------------------------*/
768  void GetAllSections(
769  TNamesDepend & a_names
770  ) const;
771 
789  bool GetAllKeys(
790  const SI_CHAR * a_pSection,
791  TNamesDepend & a_names
792  ) const;
793 
810  bool GetAllValues(
811  const SI_CHAR * a_pSection,
812  const SI_CHAR * a_pKey,
813  TNamesDepend & a_values
814  ) const;
815 
825  int GetSectionSize(
826  const SI_CHAR * a_pSection
827  ) const;
828 
843  const TKeyVal * GetSection(
844  const SI_CHAR * a_pSection
845  ) const;
846 
864  const SI_CHAR * GetValue(
865  const SI_CHAR * a_pSection,
866  const SI_CHAR * a_pKey,
867  const SI_CHAR * a_pDefault = NULL,
868  bool * a_pHasMultiple = NULL
869  ) const;
870 
884  long GetLongValue(
885  const SI_CHAR * a_pSection,
886  const SI_CHAR * a_pKey,
887  long a_nDefault = 0,
888  bool * a_pHasMultiple = NULL
889  ) const;
890 
904  double GetDoubleValue(
905  const SI_CHAR * a_pSection,
906  const SI_CHAR * a_pKey,
907  double a_nDefault = 0,
908  bool * a_pHasMultiple = NULL
909  ) const;
910 
929  bool GetBoolValue(
930  const SI_CHAR * a_pSection,
931  const SI_CHAR * a_pKey,
932  bool a_bDefault = false,
933  bool * a_pHasMultiple = NULL
934  ) const;
935 
966  const SI_CHAR * a_pSection,
967  const SI_CHAR * a_pKey,
968  const SI_CHAR * a_pValue,
969  const SI_CHAR * a_pComment = NULL,
970  bool a_bForceReplace = false
971  )
972  {
973  return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true);
974  }
975 
1000  const SI_CHAR * a_pSection,
1001  const SI_CHAR * a_pKey,
1002  long a_nValue,
1003  const SI_CHAR * a_pComment = NULL,
1004  bool a_bUseHex = false,
1005  bool a_bForceReplace = false
1006  );
1007 
1029  const SI_CHAR * a_pSection,
1030  const SI_CHAR * a_pKey,
1031  double a_nValue,
1032  const SI_CHAR * a_pComment = NULL,
1033  bool a_bForceReplace = false
1034  );
1035 
1057  const SI_CHAR * a_pSection,
1058  const SI_CHAR * a_pKey,
1059  bool a_bValue,
1060  const SI_CHAR * a_pComment = NULL,
1061  bool a_bForceReplace = false
1062  );
1063 
1082  bool Delete(
1083  const SI_CHAR * a_pSection,
1084  const SI_CHAR * a_pKey,
1085  bool a_bRemoveEmpty = false
1086  );
1087 
1088  /*-----------------------------------------------------------------------*/
1098  return Converter(m_bStoreIsUtf8);
1099  }
1100 
1101  /*-----------------------------------------------------------------------*/
1104 private:
1105  // copying is not permitted
1106  CSimpleIniTempl(const CSimpleIniTempl &); // disabled
1107  CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled
1108 
1111  SI_Error FindFileComment(
1112  SI_CHAR *& a_pData,
1113  bool a_bCopyStrings
1114  );
1115 
1120  bool FindEntry(
1121  SI_CHAR *& a_pData,
1122  const SI_CHAR *& a_pSection,
1123  const SI_CHAR *& a_pKey,
1124  const SI_CHAR *& a_pVal,
1125  const SI_CHAR *& a_pComment
1126  ) const;
1127 
1150  SI_Error AddEntry(
1151  const SI_CHAR * a_pSection,
1152  const SI_CHAR * a_pKey,
1153  const SI_CHAR * a_pValue,
1154  const SI_CHAR * a_pComment,
1155  bool a_bForceReplace,
1156  bool a_bCopyStrings
1157  );
1158 
1160  inline bool IsSpace(SI_CHAR ch) const {
1161  return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
1162  }
1163 
1165  inline bool IsComment(SI_CHAR ch) const {
1166  return (ch == ';' || ch == '#');
1167  }
1168 
1169 
1171  inline void SkipNewLine(SI_CHAR *& a_pData) const {
1172  a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1;
1173  }
1174 
1176  SI_Error CopyString(const SI_CHAR *& a_pString);
1177 
1179  void DeleteString(const SI_CHAR * a_pString);
1180 
1182  bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const {
1183  const static SI_STRLESS isLess = SI_STRLESS();
1184  return isLess(a_pLeft, a_pRight);
1185  }
1186 
1187  bool IsMultiLineTag(const SI_CHAR * a_pData) const;
1188  bool IsMultiLineData(const SI_CHAR * a_pData) const;
1189  bool LoadMultiLineText(
1190  SI_CHAR *& a_pData,
1191  const SI_CHAR *& a_pVal,
1192  const SI_CHAR * a_pTagName,
1193  bool a_bAllowBlankLinesInComment = false
1194  ) const;
1195  bool IsNewLineChar(SI_CHAR a_c) const;
1196 
1197  bool OutputMultiLineText(
1198  OutputWriter & a_oOutput,
1199  Converter & a_oConverter,
1200  const SI_CHAR * a_pText
1201  ) const;
1202 
1203 private:
1209  SI_CHAR * m_pData;
1210 
1215  size_t m_uDataLen;
1216 
1218  const SI_CHAR * m_pFileComment;
1219 
1221  TSection m_data;
1222 
1227  TNamesDepend m_strings;
1228 
1230  bool m_bStoreIsUtf8;
1231 
1233  bool m_bAllowMultiKey;
1234 
1236  bool m_bAllowMultiLine;
1237 
1239  bool m_bSpaces;
1240 
1244  int m_nOrder;
1245 };
1246 
1247 // ---------------------------------------------------------------------------
1248 // IMPLEMENTATION
1249 // ---------------------------------------------------------------------------
1250 
1251 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1253  bool a_bIsUtf8,
1254  bool a_bAllowMultiKey,
1255  bool a_bAllowMultiLine
1256  )
1257  : m_pData(0)
1258  , m_uDataLen(0)
1259  , m_pFileComment(NULL)
1260  , m_bStoreIsUtf8(a_bIsUtf8)
1261  , m_bAllowMultiKey(a_bAllowMultiKey)
1262  , m_bAllowMultiLine(a_bAllowMultiLine)
1263  , m_bSpaces(true)
1264  , m_nOrder(0)
1265 { }
1266 
1267 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1269 {
1270  Reset();
1271 }
1272 
1273 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1274 void
1276 {
1277  // remove all data
1278  delete[] m_pData;
1279  m_pData = NULL;
1280  m_uDataLen = 0;
1281  m_pFileComment = NULL;
1282  if (!m_data.empty()) {
1283  m_data.erase(m_data.begin(), m_data.end());
1284  }
1285 
1286  // remove all strings
1287  if (!m_strings.empty()) {
1288  typename TNamesDepend::iterator i = m_strings.begin();
1289  for (; i != m_strings.end(); ++i) {
1290  delete[] const_cast<SI_CHAR*>(i->pItem);
1291  }
1292  m_strings.erase(m_strings.begin(), m_strings.end());
1293  }
1294 }
1295 
1296 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1297 SI_Error
1299  const char * a_pszFile
1300  )
1301 {
1302  FILE * fp = NULL;
1303 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1304  fopen_s(&fp, a_pszFile, "rb");
1305 #else // !__STDC_WANT_SECURE_LIB__
1306  fp = fopen(a_pszFile, "rb");
1307 #endif // __STDC_WANT_SECURE_LIB__
1308  if (!fp) {
1309  return SI_FILE;
1310  }
1311  SI_Error rc = LoadFile(fp);
1312  fclose(fp);
1313  return rc;
1314 }
1315 
1316 #ifdef SI_HAS_WIDE_FILE
1317 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1318 SI_Error
1320  const SI_WCHAR_T * a_pwszFile
1321  )
1322 {
1323 #ifdef _WIN32
1324  FILE * fp = NULL;
1325 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1326  _wfopen_s(&fp, a_pwszFile, L"rb");
1327 #else // !__STDC_WANT_SECURE_LIB__
1328  fp = _wfopen(a_pwszFile, L"rb");
1329 #endif // __STDC_WANT_SECURE_LIB__
1330  if (!fp) return SI_FILE;
1331  SI_Error rc = LoadFile(fp);
1332  fclose(fp);
1333  return rc;
1334 #else // !_WIN32 (therefore SI_CONVERT_ICU)
1335  char szFile[256];
1336  u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
1337  return LoadFile(szFile);
1338 #endif // _WIN32
1339 }
1340 #endif // SI_HAS_WIDE_FILE
1341 
1342 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1343 SI_Error
1345  FILE * a_fpFile
1346  )
1347 {
1348  // load the raw file data
1349  int retval = fseek(a_fpFile, 0, SEEK_END);
1350  if (retval != 0) {
1351  return SI_FILE;
1352  }
1353  long lSize = ftell(a_fpFile);
1354  if (lSize < 0) {
1355  return SI_FILE;
1356  }
1357  if (lSize == 0) {
1358  return SI_OK;
1359  }
1360 
1361  // allocate and ensure NULL terminated
1362  char * pData = new char[lSize+1];
1363  if (!pData) {
1364  return SI_NOMEM;
1365  }
1366  pData[lSize] = 0;
1367 
1368  // load data into buffer
1369  fseek(a_fpFile, 0, SEEK_SET);
1370  size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
1371  if (uRead != (size_t) lSize) {
1372  delete[] pData;
1373  return SI_FILE;
1374  }
1375 
1376  // convert the raw data to unicode
1377  SI_Error rc = LoadData(pData, uRead);
1378  delete[] pData;
1379  return rc;
1380 }
1381 
1382 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1383 SI_Error
1385  const char * a_pData,
1386  size_t a_uDataLen
1387  )
1388 {
1389  SI_CONVERTER converter(m_bStoreIsUtf8);
1390 
1391  if (a_uDataLen == 0) {
1392  return SI_OK;
1393  }
1394 
1395  // consume the UTF-8 BOM if it exists
1396  if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
1397  if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
1398  a_pData += 3;
1399  a_uDataLen -= 3;
1400  }
1401  }
1402 
1403  // determine the length of the converted data
1404  size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
1405  if (uLen == (size_t)(-1)) {
1406  return SI_FAIL;
1407  }
1408 
1409  // allocate memory for the data, ensure that there is a NULL
1410  // terminator wherever the converted data ends
1411  SI_CHAR * pData = new SI_CHAR[uLen+1];
1412  if (!pData) {
1413  return SI_NOMEM;
1414  }
1415  memset(pData, 0, sizeof(SI_CHAR)*(uLen+1));
1416 
1417  // convert the data
1418  if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
1419  delete[] pData;
1420  return SI_FAIL;
1421  }
1422 
1423  // parse it
1424  const static SI_CHAR empty = 0;
1425  SI_CHAR * pWork = pData;
1426  const SI_CHAR * pSection = &empty;
1427  const SI_CHAR * pItem = NULL;
1428  const SI_CHAR * pVal = NULL;
1429  const SI_CHAR * pComment = NULL;
1430 
1431  // We copy the strings if we are loading data into this class when we
1432  // already have stored some.
1433  bool bCopyStrings = (m_pData != NULL);
1434 
1435  // find a file comment if it exists, this is a comment that starts at the
1436  // beginning of the file and continues until the first blank line.
1437  SI_Error rc = FindFileComment(pWork, bCopyStrings);
1438  if (rc < 0) return rc;
1439 
1440  // add every entry in the file to the data table
1441  while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
1442  rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings);
1443  if (rc < 0) return rc;
1444  }
1445 
1446  // store these strings if we didn't copy them
1447  if (bCopyStrings) {
1448  delete[] pData;
1449  }
1450  else {
1451  m_pData = pData;
1452  m_uDataLen = uLen+1;
1453  }
1454 
1455  return SI_OK;
1456 }
1457 
1458 #ifdef SI_SUPPORT_IOSTREAMS
1459 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1460 SI_Error
1462  std::istream & a_istream
1463  )
1464 {
1465  std::string strData;
1466  char szBuf[512];
1467  do {
1468  a_istream.get(szBuf, sizeof(szBuf), '\0');
1469  strData.append(szBuf);
1470  }
1471  while (a_istream.good());
1472  return LoadData(strData);
1473 }
1474 #endif // SI_SUPPORT_IOSTREAMS
1475 
1476 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1477 SI_Error
1479  SI_CHAR *& a_pData,
1480  bool a_bCopyStrings
1481  )
1482 {
1483  // there can only be a single file comment
1484  if (m_pFileComment) {
1485  return SI_OK;
1486  }
1487 
1488  // Load the file comment as multi-line text, this will modify all of
1489  // the newline characters to be single \n chars
1490  if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
1491  return SI_OK;
1492  }
1493 
1494  // copy the string if necessary
1495  if (a_bCopyStrings) {
1496  SI_Error rc = CopyString(m_pFileComment);
1497  if (rc < 0) return rc;
1498  }
1499 
1500  return SI_OK;
1501 }
1502 
1503 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1504 bool
1506  SI_CHAR *& a_pData,
1507  const SI_CHAR *& a_pSection,
1508  const SI_CHAR *& a_pKey,
1509  const SI_CHAR *& a_pVal,
1510  const SI_CHAR *& a_pComment
1511  ) const
1512 {
1513  a_pComment = NULL;
1514 
1515  SI_CHAR * pTrail = NULL;
1516  while (*a_pData) {
1517  // skip spaces and empty lines
1518  while (*a_pData && IsSpace(*a_pData)) {
1519  ++a_pData;
1520  }
1521  if (!*a_pData) {
1522  break;
1523  }
1524 
1525  // skip processing of comment lines but keep a pointer to
1526  // the start of the comment.
1527  if (IsComment(*a_pData)) {
1528  LoadMultiLineText(a_pData, a_pComment, NULL, true);
1529  continue;
1530  }
1531 
1532  // process section names
1533  if (*a_pData == '[') {
1534  // skip leading spaces
1535  ++a_pData;
1536  while (*a_pData && IsSpace(*a_pData)) {
1537  ++a_pData;
1538  }
1539 
1540  // find the end of the section name (it may contain spaces)
1541  // and convert it to lowercase as necessary
1542  a_pSection = a_pData;
1543  while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
1544  ++a_pData;
1545  }
1546 
1547  // if it's an invalid line, just skip it
1548  if (*a_pData != ']') {
1549  continue;
1550  }
1551 
1552  // remove trailing spaces from the section
1553  pTrail = a_pData - 1;
1554  while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1555  --pTrail;
1556  }
1557  ++pTrail;
1558  *pTrail = 0;
1559 
1560  // skip to the end of the line
1561  ++a_pData; // safe as checked that it == ']' above
1562  while (*a_pData && !IsNewLineChar(*a_pData)) {
1563  ++a_pData;
1564  }
1565 
1566  a_pKey = NULL;
1567  a_pVal = NULL;
1568  return true;
1569  }
1570 
1571  // find the end of the key name (it may contain spaces)
1572  // and convert it to lowercase as necessary
1573  a_pKey = a_pData;
1574  while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
1575  ++a_pData;
1576  }
1577 
1578  // if it's an invalid line, just skip it
1579  if (*a_pData != '=') {
1580  continue;
1581  }
1582 
1583  // empty keys are invalid
1584  if (a_pKey == a_pData) {
1585  while (*a_pData && !IsNewLineChar(*a_pData)) {
1586  ++a_pData;
1587  }
1588  continue;
1589  }
1590 
1591  // remove trailing spaces from the key
1592  pTrail = a_pData - 1;
1593  while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1594  --pTrail;
1595  }
1596  ++pTrail;
1597  *pTrail = 0;
1598 
1599  // skip leading whitespace on the value
1600  ++a_pData; // safe as checked that it == '=' above
1601  while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1602  ++a_pData;
1603  }
1604 
1605  // find the end of the value which is the end of this line
1606  a_pVal = a_pData;
1607  while (*a_pData && !IsNewLineChar(*a_pData)) {
1608  ++a_pData;
1609  }
1610 
1611  // remove trailing spaces from the value
1612  pTrail = a_pData - 1;
1613  if (*a_pData) { // prepare for the next round
1614  SkipNewLine(a_pData);
1615  }
1616  while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1617  --pTrail;
1618  }
1619  ++pTrail;
1620  *pTrail = 0;
1621 
1622  // check for multi-line entries
1623  if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1624  // skip the "<<<" to get the tag that will end the multiline
1625  const SI_CHAR * pTagName = a_pVal + 3;
1626  return LoadMultiLineText(a_pData, a_pVal, pTagName);
1627  }
1628 
1629  // return the standard entry
1630  return true;
1631  }
1632 
1633  return false;
1634 }
1635 
1636 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1637 bool
1639  const SI_CHAR * a_pVal
1640  ) const
1641 {
1642  // check for the "<<<" prefix for a multi-line entry
1643  if (*a_pVal++ != '<') return false;
1644  if (*a_pVal++ != '<') return false;
1645  if (*a_pVal++ != '<') return false;
1646  return true;
1647 }
1648 
1649 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1650 bool
1652  const SI_CHAR * a_pData
1653  ) const
1654 {
1655  // data is multi-line if it has any of the following features:
1656  // * whitespace prefix
1657  // * embedded newlines
1658  // * whitespace suffix
1659 
1660  // empty string
1661  if (!*a_pData) {
1662  return false;
1663  }
1664 
1665  // check for prefix
1666  if (IsSpace(*a_pData)) {
1667  return true;
1668  }
1669 
1670  // embedded newlines
1671  while (*a_pData) {
1672  if (IsNewLineChar(*a_pData)) {
1673  return true;
1674  }
1675  ++a_pData;
1676  }
1677 
1678  // check for suffix
1679  if (IsSpace(*--a_pData)) {
1680  return true;
1681  }
1682 
1683  return false;
1684 }
1685 
1686 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1687 bool
1689  SI_CHAR a_c
1690  ) const
1691 {
1692  return (a_c == '\n' || a_c == '\r');
1693 }
1694 
1695 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1696 bool
1698  SI_CHAR *& a_pData,
1699  const SI_CHAR *& a_pVal,
1700  const SI_CHAR * a_pTagName,
1701  bool a_bAllowBlankLinesInComment
1702  ) const
1703 {
1704  // we modify this data to strip all newlines down to a single '\n'
1705  // character. This means that on Windows we need to strip out some
1706  // characters which will make the data shorter.
1707  // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
1708  // LINE1-LINE1\nLINE2-LINE2\0
1709  // The pDataLine entry is the pointer to the location in memory that
1710  // the current line needs to start to run following the existing one.
1711  // This may be the same as pCurrLine in which case no move is needed.
1712  SI_CHAR * pDataLine = a_pData;
1713  SI_CHAR * pCurrLine;
1714 
1715  // value starts at the current line
1716  a_pVal = a_pData;
1717 
1718  // find the end tag. This tag must start in column 1 and be
1719  // followed by a newline. No whitespace removal is done while
1720  // searching for this tag.
1721  SI_CHAR cEndOfLineChar = *a_pData;
1722  for(;;) {
1723  // if we are loading comments then we need a comment character as
1724  // the first character on every line
1725  if (!a_pTagName && !IsComment(*a_pData)) {
1726  // if we aren't allowing blank lines then we're done
1727  if (!a_bAllowBlankLinesInComment) {
1728  break;
1729  }
1730 
1731  // if we are allowing blank lines then we only include them
1732  // in this comment if another comment follows, so read ahead
1733  // to find out.
1734  SI_CHAR * pCurr = a_pData;
1735  int nNewLines = 0;
1736  while (IsSpace(*pCurr)) {
1737  if (IsNewLineChar(*pCurr)) {
1738  ++nNewLines;
1739  SkipNewLine(pCurr);
1740  }
1741  else {
1742  ++pCurr;
1743  }
1744  }
1745 
1746  // we have a comment, add the blank lines to the output
1747  // and continue processing from here
1748  if (IsComment(*pCurr)) {
1749  for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
1750  a_pData = pCurr;
1751  continue;
1752  }
1753 
1754  // the comment ends here
1755  break;
1756  }
1757 
1758  // find the end of this line
1759  pCurrLine = a_pData;
1760  while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1761 
1762  // move this line down to the location that it should be if necessary
1763  if (pDataLine < pCurrLine) {
1764  size_t nLen = (size_t) (a_pData - pCurrLine);
1765  memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR));
1766  pDataLine[nLen] = '\0';
1767  }
1768 
1769  // end the line with a NULL
1770  cEndOfLineChar = *a_pData;
1771  *a_pData = 0;
1772 
1773  // if are looking for a tag then do the check now. This is done before
1774  // checking for end of the data, so that if we have the tag at the end
1775  // of the data then the tag is removed correctly.
1776  if (a_pTagName &&
1777  (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
1778  {
1779  break;
1780  }
1781 
1782  // if we are at the end of the data then we just automatically end
1783  // this entry and return the current data.
1784  if (!cEndOfLineChar) {
1785  return true;
1786  }
1787 
1788  // otherwise we need to process this newline to ensure that it consists
1789  // of just a single \n character.
1790  pDataLine += (a_pData - pCurrLine);
1791  *a_pData = cEndOfLineChar;
1792  SkipNewLine(a_pData);
1793  *pDataLine++ = '\n';
1794  }
1795 
1796  // if we didn't find a comment at all then return false
1797  if (a_pVal == a_pData) {
1798  a_pVal = NULL;
1799  return false;
1800  }
1801 
1802  // the data (which ends at the end of the last line) needs to be
1803  // null-terminated BEFORE before the newline character(s). If the
1804  // user wants a new line in the multi-line data then they need to
1805  // add an empty line before the tag.
1806  *--pDataLine = '\0';
1807 
1808  // if looking for a tag and if we aren't at the end of the data,
1809  // then move a_pData to the start of the next line.
1810  if (a_pTagName && cEndOfLineChar) {
1811  SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1812  *a_pData = cEndOfLineChar;
1813  SkipNewLine(a_pData);
1814  }
1815 
1816  return true;
1817 }
1818 
1819 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1820 SI_Error
1822  const SI_CHAR *& a_pString
1823  )
1824 {
1825  size_t uLen = 0;
1826  if (sizeof(SI_CHAR) == sizeof(char)) {
1827  uLen = strlen((const char *)a_pString);
1828  }
1829  else if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
1830  uLen = wcslen((const wchar_t *)a_pString);
1831  }
1832  else {
1833  for ( ; a_pString[uLen]; ++uLen) /*loop*/ ;
1834  }
1835  ++uLen; // NULL character
1836  SI_CHAR * pCopy = new SI_CHAR[uLen];
1837  if (!pCopy) {
1838  return SI_NOMEM;
1839  }
1840  memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen);
1841  m_strings.push_back(pCopy);
1842  a_pString = pCopy;
1843  return SI_OK;
1844 }
1845 
1846 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1847 SI_Error
1849  const SI_CHAR * a_pSection,
1850  const SI_CHAR * a_pKey,
1851  const SI_CHAR * a_pValue,
1852  const SI_CHAR * a_pComment,
1853  bool a_bForceReplace,
1854  bool a_bCopyStrings
1855  )
1856 {
1857  SI_Error rc;
1858  bool bInserted = false;
1859 
1860  SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1861 
1862  // if we are copying strings then make a copy of the comment now
1863  // because we will need it when we add the entry.
1864  if (a_bCopyStrings && a_pComment) {
1865  rc = CopyString(a_pComment);
1866  if (rc < 0) return rc;
1867  }
1868 
1869  // create the section entry if necessary
1870  typename TSection::iterator iSection = m_data.find(a_pSection);
1871  if (iSection == m_data.end()) {
1872  // if the section doesn't exist then we need a copy as the
1873  // string needs to last beyond the end of this function
1874  if (a_bCopyStrings) {
1875  rc = CopyString(a_pSection);
1876  if (rc < 0) return rc;
1877  }
1878 
1879  // only set the comment if this is a section only entry
1880  Entry oSection(a_pSection, ++m_nOrder);
1881  if (a_pComment && (!a_pKey || !a_pValue)) {
1882  oSection.pComment = a_pComment;
1883  }
1884 
1885  typename TSection::value_type oEntry(oSection, TKeyVal());
1886  typedef typename TSection::iterator SectionIterator;
1887  std::pair<SectionIterator,bool> i = m_data.insert(oEntry);
1888  iSection = i.first;
1889  bInserted = true;
1890  }
1891  if (!a_pKey || !a_pValue) {
1892  // section only entries are specified with pItem and pVal as NULL
1893  return bInserted ? SI_INSERTED : SI_UPDATED;
1894  }
1895 
1896  // check for existence of the key
1897  TKeyVal & keyval = iSection->second;
1898  typename TKeyVal::iterator iKey = keyval.find(a_pKey);
1899 
1900  // remove all existing entries but save the load order and
1901  // comment of the first entry
1902  int nLoadOrder = ++m_nOrder;
1903  if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
1904  const SI_CHAR * pComment = NULL;
1905  while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
1906  if (iKey->first.nOrder < nLoadOrder) {
1907  nLoadOrder = iKey->first.nOrder;
1908  pComment = iKey->first.pComment;
1909  }
1910  ++iKey;
1911  }
1912  if (pComment) {
1913  DeleteString(a_pComment);
1914  a_pComment = pComment;
1915  CopyString(a_pComment);
1916  }
1917  Delete(a_pSection, a_pKey);
1918  iKey = keyval.end();
1919  }
1920 
1921  // make string copies if necessary
1922  bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
1923  if (a_bCopyStrings) {
1924  if (bForceCreateNewKey || iKey == keyval.end()) {
1925  // if the key doesn't exist then we need a copy as the
1926  // string needs to last beyond the end of this function
1927  // because we will be inserting the key next
1928  rc = CopyString(a_pKey);
1929  if (rc < 0) return rc;
1930  }
1931 
1932  // we always need a copy of the value
1933  rc = CopyString(a_pValue);
1934  if (rc < 0) return rc;
1935  }
1936 
1937  // create the key entry
1938  if (iKey == keyval.end() || bForceCreateNewKey) {
1939  Entry oKey(a_pKey, nLoadOrder);
1940  if (a_pComment) {
1941  oKey.pComment = a_pComment;
1942  }
1943  typename TKeyVal::value_type oEntry(oKey, static_cast<const SI_CHAR *>(NULL));
1944  iKey = keyval.insert(oEntry);
1945  bInserted = true;
1946  }
1947  iKey->second = a_pValue;
1948  return bInserted ? SI_INSERTED : SI_UPDATED;
1949 }
1950 
1951 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1952 const SI_CHAR *
1954  const SI_CHAR * a_pSection,
1955  const SI_CHAR * a_pKey,
1956  const SI_CHAR * a_pDefault,
1957  bool * a_pHasMultiple
1958  ) const
1959 {
1960  if (a_pHasMultiple) {
1961  *a_pHasMultiple = false;
1962  }
1963  if (!a_pSection || !a_pKey) {
1964  return a_pDefault;
1965  }
1966  typename TSection::const_iterator iSection = m_data.find(a_pSection);
1967  if (iSection == m_data.end()) {
1968  return a_pDefault;
1969  }
1970  typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
1971  if (iKeyVal == iSection->second.end()) {
1972  return a_pDefault;
1973  }
1974 
1975  // check for multiple entries with the same key
1976  if (m_bAllowMultiKey && a_pHasMultiple) {
1977  typename TKeyVal::const_iterator iTemp = iKeyVal;
1978  if (++iTemp != iSection->second.end()) {
1979  if (!IsLess(a_pKey, iTemp->first.pItem)) {
1980  *a_pHasMultiple = true;
1981  }
1982  }
1983  }
1984 
1985  return iKeyVal->second;
1986 }
1987 
1988 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
1989 long
1991  const SI_CHAR * a_pSection,
1992  const SI_CHAR * a_pKey,
1993  long a_nDefault,
1994  bool * a_pHasMultiple
1995  ) const
1996 {
1997  // return the default if we don't have a value
1998  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
1999  if (!pszValue || !*pszValue) return a_nDefault;
2000 
2001  // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
2002  char szValue[64] = { 0 };
2003  SI_CONVERTER c(m_bStoreIsUtf8);
2004  if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
2005  return a_nDefault;
2006  }
2007 
2008  // handle the value as hex if prefaced with "0x"
2009  long nValue = a_nDefault;
2010  char * pszSuffix = szValue;
2011  if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
2012  if (!szValue[2]) return a_nDefault;
2013  nValue = strtol(&szValue[2], &pszSuffix, 16);
2014  }
2015  else {
2016  nValue = strtol(szValue, &pszSuffix, 10);
2017  }
2018 
2019  // any invalid strings will return the default value
2020  if (*pszSuffix) {
2021  return a_nDefault;
2022  }
2023 
2024  return nValue;
2025 }
2026 
2027 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2028 SI_Error
2030  const SI_CHAR * a_pSection,
2031  const SI_CHAR * a_pKey,
2032  long a_nValue,
2033  const SI_CHAR * a_pComment,
2034  bool a_bUseHex,
2035  bool a_bForceReplace
2036  )
2037 {
2038  // use SetValue to create sections
2039  if (!a_pSection || !a_pKey) return SI_FAIL;
2040 
2041  // convert to an ASCII string
2042  char szInput[64];
2043 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2044  sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
2045 #else // !__STDC_WANT_SECURE_LIB__
2046  sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
2047 #endif // __STDC_WANT_SECURE_LIB__
2048 
2049  // convert to output text
2050  SI_CHAR szOutput[64];
2051  SI_CONVERTER c(m_bStoreIsUtf8);
2052  c.ConvertFromStore(szInput, strlen(szInput) + 1,
2053  szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
2054 
2055  // actually add it
2056  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2057 }
2058 
2059 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2060 double
2062  const SI_CHAR * a_pSection,
2063  const SI_CHAR * a_pKey,
2064  double a_nDefault,
2065  bool * a_pHasMultiple
2066  ) const
2067 {
2068  // return the default if we don't have a value
2069  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2070  if (!pszValue || !*pszValue) return a_nDefault;
2071 
2072  // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
2073  char szValue[64] = { 0 };
2074  SI_CONVERTER c(m_bStoreIsUtf8);
2075  if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
2076  return a_nDefault;
2077  }
2078 
2079  char * pszSuffix = NULL;
2080  double nValue = strtod(szValue, &pszSuffix);
2081 
2082  // any invalid strings will return the default value
2083  if (!pszSuffix || *pszSuffix) {
2084  return a_nDefault;
2085  }
2086 
2087  return nValue;
2088 }
2089 
2090 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2091 SI_Error
2093  const SI_CHAR * a_pSection,
2094  const SI_CHAR * a_pKey,
2095  double a_nValue,
2096  const SI_CHAR * a_pComment,
2097  bool a_bForceReplace
2098  )
2099 {
2100  // use SetValue to create sections
2101  if (!a_pSection || !a_pKey) return SI_FAIL;
2102 
2103  // convert to an ASCII string
2104  char szInput[64];
2105 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2106  sprintf_s(szInput, "%f", a_nValue);
2107 #else // !__STDC_WANT_SECURE_LIB__
2108  sprintf(szInput, "%f", a_nValue);
2109 #endif // __STDC_WANT_SECURE_LIB__
2110 
2111  // convert to output text
2112  SI_CHAR szOutput[64];
2113  SI_CONVERTER c(m_bStoreIsUtf8);
2114  c.ConvertFromStore(szInput, strlen(szInput) + 1,
2115  szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
2116 
2117  // actually add it
2118  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2119 }
2120 
2121 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2122 bool
2124  const SI_CHAR * a_pSection,
2125  const SI_CHAR * a_pKey,
2126  bool a_bDefault,
2127  bool * a_pHasMultiple
2128  ) const
2129 {
2130  // return the default if we don't have a value
2131  const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2132  if (!pszValue || !*pszValue) return a_bDefault;
2133 
2134  // we only look at the minimum number of characters
2135  switch (pszValue[0]) {
2136  case 't': case 'T': // true
2137  case 'y': case 'Y': // yes
2138  case '1': // 1 (one)
2139  return true;
2140 
2141  case 'f': case 'F': // false
2142  case 'n': case 'N': // no
2143  case '0': // 0 (zero)
2144  return false;
2145 
2146  case 'o': case 'O':
2147  if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on
2148  if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off
2149  break;
2150  }
2151 
2152  // no recognized value, return the default
2153  return a_bDefault;
2154 }
2155 
2156 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2157 SI_Error
2159  const SI_CHAR * a_pSection,
2160  const SI_CHAR * a_pKey,
2161  bool a_bValue,
2162  const SI_CHAR * a_pComment,
2163  bool a_bForceReplace
2164  )
2165 {
2166  // use SetValue to create sections
2167  if (!a_pSection || !a_pKey) return SI_FAIL;
2168 
2169  // convert to an ASCII string
2170  const char * pszInput = a_bValue ? "true" : "false";
2171 
2172  // convert to output text
2173  SI_CHAR szOutput[64];
2174  SI_CONVERTER c(m_bStoreIsUtf8);
2175  c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
2176  szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
2177 
2178  // actually add it
2179  return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
2180 }
2181 
2182 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2183 bool
2185  const SI_CHAR * a_pSection,
2186  const SI_CHAR * a_pKey,
2187  TNamesDepend & a_values
2188  ) const
2189 {
2190  a_values.clear();
2191 
2192  if (!a_pSection || !a_pKey) {
2193  return false;
2194  }
2195  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2196  if (iSection == m_data.end()) {
2197  return false;
2198  }
2199  typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2200  if (iKeyVal == iSection->second.end()) {
2201  return false;
2202  }
2203 
2204  // insert all values for this key
2205  a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2206  if (m_bAllowMultiKey) {
2207  ++iKeyVal;
2208  while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
2209  a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2210  ++iKeyVal;
2211  }
2212  }
2213 
2214  return true;
2215 }
2216 
2217 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2218 int
2220  const SI_CHAR * a_pSection
2221  ) const
2222 {
2223  if (!a_pSection) {
2224  return -1;
2225  }
2226 
2227  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2228  if (iSection == m_data.end()) {
2229  return -1;
2230  }
2231  const TKeyVal & section = iSection->second;
2232 
2233  // if multi-key isn't permitted then the section size is
2234  // the number of keys that we have.
2235  if (!m_bAllowMultiKey || section.empty()) {
2236  return (int) section.size();
2237  }
2238 
2239  // otherwise we need to count them
2240  int nCount = 0;
2241  const SI_CHAR * pLastKey = NULL;
2242  typename TKeyVal::const_iterator iKeyVal = section.begin();
2243  for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
2244  if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2245  ++nCount;
2246  pLastKey = iKeyVal->first.pItem;
2247  }
2248  }
2249  return nCount;
2250 }
2251 
2252 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2255  const SI_CHAR * a_pSection
2256  ) const
2257 {
2258  if (a_pSection) {
2259  typename TSection::const_iterator i = m_data.find(a_pSection);
2260  if (i != m_data.end()) {
2261  return &(i->second);
2262  }
2263  }
2264  return 0;
2265 }
2266 
2267 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2268 void
2270  TNamesDepend & a_names
2271  ) const
2272 {
2273  a_names.clear();
2274  typename TSection::const_iterator i = m_data.begin();
2275  for (int n = 0; i != m_data.end(); ++i, ++n ) {
2276  a_names.push_back(i->first);
2277  }
2278 }
2279 
2280 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2281 bool
2283  const SI_CHAR * a_pSection,
2284  TNamesDepend & a_names
2285  ) const
2286 {
2287  a_names.clear();
2288 
2289  if (!a_pSection) {
2290  return false;
2291  }
2292 
2293  typename TSection::const_iterator iSection = m_data.find(a_pSection);
2294  if (iSection == m_data.end()) {
2295  return false;
2296  }
2297 
2298  const TKeyVal & section = iSection->second;
2299  const SI_CHAR * pLastKey = NULL;
2300  typename TKeyVal::const_iterator iKeyVal = section.begin();
2301  for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) {
2302  if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2303  a_names.push_back(iKeyVal->first);
2304  pLastKey = iKeyVal->first.pItem;
2305  }
2306  }
2307 
2308  return true;
2309 }
2310 
2311 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2312 SI_Error
2314  const char * a_pszFile,
2315  bool a_bAddSignature
2316  ) const
2317 {
2318  FILE * fp = NULL;
2319 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2320  fopen_s(&fp, a_pszFile, "wb");
2321 #else // !__STDC_WANT_SECURE_LIB__
2322  fp = fopen(a_pszFile, "wb");
2323 #endif // __STDC_WANT_SECURE_LIB__
2324  if (!fp) return SI_FILE;
2325  SI_Error rc = SaveFile(fp, a_bAddSignature);
2326  fclose(fp);
2327  return rc;
2328 }
2329 
2330 #ifdef SI_HAS_WIDE_FILE
2331 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2332 SI_Error
2334  const SI_WCHAR_T * a_pwszFile,
2335  bool a_bAddSignature
2336  ) const
2337 {
2338 #ifdef _WIN32
2339  FILE * fp = NULL;
2340 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2341  _wfopen_s(&fp, a_pwszFile, L"wb");
2342 #else // !__STDC_WANT_SECURE_LIB__
2343  fp = _wfopen(a_pwszFile, L"wb");
2344 #endif // __STDC_WANT_SECURE_LIB__
2345  if (!fp) return SI_FILE;
2346  SI_Error rc = SaveFile(fp, a_bAddSignature);
2347  fclose(fp);
2348  return rc;
2349 #else // !_WIN32 (therefore SI_CONVERT_ICU)
2350  char szFile[256];
2351  u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
2352  return SaveFile(szFile, a_bAddSignature);
2353 #endif // _WIN32
2354 }
2355 #endif // SI_HAS_WIDE_FILE
2356 
2357 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2358 SI_Error
2360  FILE * a_pFile,
2361  bool a_bAddSignature
2362  ) const
2363 {
2364  FileWriter writer(a_pFile);
2365  return Save(writer, a_bAddSignature);
2366 }
2367 
2368 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2369 SI_Error
2371  OutputWriter & a_oOutput,
2372  bool a_bAddSignature
2373  ) const
2374 {
2375  Converter convert(m_bStoreIsUtf8);
2376 
2377  // add the UTF-8 signature if it is desired
2378  if (m_bStoreIsUtf8 && a_bAddSignature) {
2379  a_oOutput.Write(SI_UTF8_SIGNATURE);
2380  }
2381 
2382  // get all of the sections sorted in load order
2383  TNamesDepend oSections;
2384  GetAllSections(oSections);
2385 #if defined(_MSC_VER) && _MSC_VER <= 1200
2386  oSections.sort();
2387 #elif defined(__BORLANDC__)
2388  oSections.sort(Entry::LoadOrder());
2389 #else
2390  oSections.sort(typename Entry::LoadOrder());
2391 #endif
2392 
2393  // write the file comment if we have one
2394  bool bNeedNewLine = false;
2395  if (m_pFileComment) {
2396  if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
2397  return SI_FAIL;
2398  }
2399  bNeedNewLine = true;
2400  }
2401 
2402  // iterate through our sections and output the data
2403  typename TNamesDepend::const_iterator iSection = oSections.begin();
2404  for ( ; iSection != oSections.end(); ++iSection ) {
2405  // write out the comment if there is one
2406  if (iSection->pComment) {
2407  if (bNeedNewLine) {
2408  a_oOutput.Write(SI_NEWLINE_A);
2409  a_oOutput.Write(SI_NEWLINE_A);
2410  }
2411  if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
2412  return SI_FAIL;
2413  }
2414  bNeedNewLine = false;
2415  }
2416 
2417  if (bNeedNewLine) {
2418  a_oOutput.Write(SI_NEWLINE_A);
2419  a_oOutput.Write(SI_NEWLINE_A);
2420  bNeedNewLine = false;
2421  }
2422 
2423  // write the section (unless there is no section name)
2424  if (*iSection->pItem) {
2425  if (!convert.ConvertToStore(iSection->pItem)) {
2426  return SI_FAIL;
2427  }
2428  a_oOutput.Write("[");
2429  a_oOutput.Write(convert.Data());
2430  a_oOutput.Write("]");
2431  a_oOutput.Write(SI_NEWLINE_A);
2432  }
2433 
2434  // get all of the keys sorted in load order
2435  TNamesDepend oKeys;
2436  GetAllKeys(iSection->pItem, oKeys);
2437 #if defined(_MSC_VER) && _MSC_VER <= 1200
2438  oKeys.sort();
2439 #elif defined(__BORLANDC__)
2440  oKeys.sort(Entry::LoadOrder());
2441 #else
2442  oKeys.sort(typename Entry::LoadOrder());
2443 #endif
2444 
2445  // write all keys and values
2446  typename TNamesDepend::const_iterator iKey = oKeys.begin();
2447  for ( ; iKey != oKeys.end(); ++iKey) {
2448  // get all values for this key
2449  TNamesDepend oValues;
2450  GetAllValues(iSection->pItem, iKey->pItem, oValues);
2451 
2452  typename TNamesDepend::const_iterator iValue = oValues.begin();
2453  for ( ; iValue != oValues.end(); ++iValue) {
2454  // write out the comment if there is one
2455  if (iValue->pComment) {
2456  a_oOutput.Write(SI_NEWLINE_A);
2457  if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
2458  return SI_FAIL;
2459  }
2460  }
2461 
2462  // write the key
2463  if (!convert.ConvertToStore(iKey->pItem)) {
2464  return SI_FAIL;
2465  }
2466  a_oOutput.Write(convert.Data());
2467 
2468  // write the value
2469  if (!convert.ConvertToStore(iValue->pItem)) {
2470  return SI_FAIL;
2471  }
2472  a_oOutput.Write(m_bSpaces ? " = " : "=");
2473  if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
2474  // multi-line data needs to be processed specially to ensure
2475  // that we use the correct newline format for the current system
2476  a_oOutput.Write("<<<END_OF_TEXT" SI_NEWLINE_A);
2477  if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
2478  return SI_FAIL;
2479  }
2480  a_oOutput.Write("END_OF_TEXT");
2481  }
2482  else {
2483  a_oOutput.Write(convert.Data());
2484  }
2485  a_oOutput.Write(SI_NEWLINE_A);
2486  }
2487  }
2488 
2489  bNeedNewLine = true;
2490  }
2491 
2492  return SI_OK;
2493 }
2494 
2495 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2496 bool
2498  OutputWriter & a_oOutput,
2499  Converter & a_oConverter,
2500  const SI_CHAR * a_pText
2501  ) const
2502 {
2503  const SI_CHAR * pEndOfLine;
2504  SI_CHAR cEndOfLineChar = *a_pText;
2505  while (cEndOfLineChar) {
2506  // find the end of this line
2507  pEndOfLine = a_pText;
2508  for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ;
2509  cEndOfLineChar = *pEndOfLine;
2510 
2511  // temporarily null terminate, convert and output the line
2512  *const_cast<SI_CHAR*>(pEndOfLine) = 0;
2513  if (!a_oConverter.ConvertToStore(a_pText)) {
2514  return false;
2515  }
2516  *const_cast<SI_CHAR*>(pEndOfLine) = cEndOfLineChar;
2517  a_pText += (pEndOfLine - a_pText) + 1;
2518  a_oOutput.Write(a_oConverter.Data());
2519  a_oOutput.Write(SI_NEWLINE_A);
2520  }
2521  return true;
2522 }
2523 
2524 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2525 bool
2527  const SI_CHAR * a_pSection,
2528  const SI_CHAR * a_pKey,
2529  bool a_bRemoveEmpty
2530  )
2531 {
2532  if (!a_pSection) {
2533  return false;
2534  }
2535 
2536  typename TSection::iterator iSection = m_data.find(a_pSection);
2537  if (iSection == m_data.end()) {
2538  return false;
2539  }
2540 
2541  // remove a single key if we have a keyname
2542  if (a_pKey) {
2543  typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
2544  if (iKeyVal == iSection->second.end()) {
2545  return false;
2546  }
2547 
2548  // remove any copied strings and then the key
2549  typename TKeyVal::iterator iDelete;
2550  do {
2551  iDelete = iKeyVal++;
2552 
2553  DeleteString(iDelete->first.pItem);
2554  DeleteString(iDelete->second);
2555  iSection->second.erase(iDelete);
2556  }
2557  while (iKeyVal != iSection->second.end()
2558  && !IsLess(a_pKey, iKeyVal->first.pItem));
2559 
2560  // done now if the section is not empty or we are not pruning away
2561  // the empty sections. Otherwise let it fall through into the section
2562  // deletion code
2563  if (!a_bRemoveEmpty || !iSection->second.empty()) {
2564  return true;
2565  }
2566  }
2567  else {
2568  // delete all copied strings from this section. The actual
2569  // entries will be removed when the section is removed.
2570  typename TKeyVal::iterator iKeyVal = iSection->second.begin();
2571  for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
2572  DeleteString(iKeyVal->first.pItem);
2573  DeleteString(iKeyVal->second);
2574  }
2575  }
2576 
2577  // delete the section itself
2578  DeleteString(iSection->first.pItem);
2579  m_data.erase(iSection);
2580 
2581  return true;
2582 }
2583 
2584 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
2585 void
2587  const SI_CHAR * a_pString
2588  )
2589 {
2590  // strings may exist either inside the data block, or they will be
2591  // individually allocated and stored in m_strings. We only physically
2592  // delete those stored in m_strings.
2593  if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
2594  typename TNamesDepend::iterator i = m_strings.begin();
2595  for (;i != m_strings.end(); ++i) {
2596  if (a_pString == i->pItem) {
2597  delete[] const_cast<SI_CHAR*>(i->pItem);
2598  m_strings.erase(i);
2599  break;
2600  }
2601  }
2602  }
2603 }
2604 
2605 // ---------------------------------------------------------------------------
2606 // CONVERSION FUNCTIONS
2607 // ---------------------------------------------------------------------------
2608 
2609 // Defines the conversion classes for different libraries. Before including
2610 // SimpleIni.h, set the converter that you wish you use by defining one of the
2611 // following symbols.
2612 //
2613 // SI_CONVERT_GENERIC Use the Unicode reference conversion library in
2614 // the accompanying files ConvertUTF.h/c
2615 // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
2616 // ICU headers on include path and icuuc.lib
2617 // SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
2618 
2619 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2620 # ifdef _WIN32
2621 # define SI_CONVERT_WIN32
2622 # else
2623 # define SI_CONVERT_GENERIC
2624 # endif
2625 #endif
2626 
2632 template<class SI_CHAR>
2634  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
2635  long cmp;
2636  for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
2637  cmp = (long) *pLeft - (long) *pRight;
2638  if (cmp != 0) {
2639  return cmp < 0;
2640  }
2641  }
2642  return *pRight != 0;
2643  }
2644 };
2645 
2652 template<class SI_CHAR>
2654  inline SI_CHAR locase(SI_CHAR ch) const {
2655  return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a');
2656  }
2657  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
2658  long cmp;
2659  for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
2660  cmp = (long) locase(*pLeft) - (long) locase(*pRight);
2661  if (cmp != 0) {
2662  return cmp < 0;
2663  }
2664  }
2665  return *pRight != 0;
2666  }
2667 };
2668 
2672 template<class SI_CHAR>
2674  bool m_bStoreIsUtf8;
2675 protected:
2677 public:
2678  SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
2679 
2680  /* copy and assignment */
2681  SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); }
2683  m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
2684  return *this;
2685  }
2686 
2701  const char * a_pInputData,
2702  size_t a_uInputDataLen)
2703  {
2704  (void)a_pInputData;
2705  SI_ASSERT(a_uInputDataLen != (size_t) -1);
2706 
2707  // ASCII/MBCS/UTF-8 needs no conversion
2708  return a_uInputDataLen;
2709  }
2710 
2725  const char * a_pInputData,
2726  size_t a_uInputDataLen,
2727  SI_CHAR * a_pOutputData,
2728  size_t a_uOutputDataSize)
2729  {
2730  // ASCII/MBCS/UTF-8 needs no conversion
2731  if (a_uInputDataLen > a_uOutputDataSize) {
2732  return false;
2733  }
2734  memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2735  return true;
2736  }
2737 
2748  size_t SizeToStore(
2749  const SI_CHAR * a_pInputData)
2750  {
2751  // ASCII/MBCS/UTF-8 needs no conversion
2752  return strlen((const char *)a_pInputData) + 1;
2753  }
2754 
2769  const SI_CHAR * a_pInputData,
2770  char * a_pOutputData,
2771  size_t a_uOutputDataSize)
2772  {
2773  // calc input string length (SI_CHAR type and size independent)
2774  size_t uInputLen = strlen((const char *)a_pInputData) + 1;
2775  if (uInputLen > a_uOutputDataSize) {
2776  return false;
2777  }
2778 
2779  // ascii/UTF-8 needs no conversion
2780  memcpy(a_pOutputData, a_pInputData, uInputLen);
2781  return true;
2782  }
2783 };
2784 
2785 
2786 // ---------------------------------------------------------------------------
2787 // SI_CONVERT_GENERIC
2788 // ---------------------------------------------------------------------------
2789 #ifdef SI_CONVERT_GENERIC
2790 
2791 #define SI_Case SI_GenericCase
2792 #define SI_NoCase SI_GenericNoCase
2793 
2794 #include <wchar.h>
2795 #include "ConvertUTF.h"
2796 
2801 template<class SI_CHAR>
2803  bool m_bStoreIsUtf8;
2804 protected:
2806 public:
2807  SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
2808 
2809  /* copy and assignment */
2810  SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
2812  m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
2813  return *this;
2814  }
2815 
2830  const char * a_pInputData,
2831  size_t a_uInputDataLen)
2832  {
2833  SI_ASSERT(a_uInputDataLen != (size_t) -1);
2834 
2835  if (m_bStoreIsUtf8) {
2836  // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
2837  // so we just return the same number of characters required as for
2838  // the source text.
2839  return a_uInputDataLen;
2840  }
2841 
2842 #if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
2843  // fall back processing for platforms that don't support a NULL dest to mbstowcs
2844  // worst case scenario is 1:1, this will be a sufficient buffer size
2845  (void)a_pInputData;
2846  return a_uInputDataLen;
2847 #else
2848  // get the actual required buffer size
2849  return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
2850 #endif
2851  }
2852 
2867  const char * a_pInputData,
2868  size_t a_uInputDataLen,
2869  SI_CHAR * a_pOutputData,
2870  size_t a_uOutputDataSize)
2871  {
2872  if (m_bStoreIsUtf8) {
2873  // This uses the Unicode reference implementation to do the
2874  // conversion from UTF-8 to wchar_t. The required files are
2875  // ConvertUTF.h and ConvertUTF.c which should be included in
2876  // the distribution but are publically available from unicode.org
2877  // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
2878  ConversionResult retval;
2879  const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
2880  if (sizeof(wchar_t) == sizeof(UTF32)) {
2881  UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
2882  retval = ConvertUTF8toUTF32(
2883  &pUtf8, pUtf8 + a_uInputDataLen,
2884  &pUtf32, pUtf32 + a_uOutputDataSize,
2885  lenientConversion);
2886  }
2887  else if (sizeof(wchar_t) == sizeof(UTF16)) {
2888  UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
2889  retval = ConvertUTF8toUTF16(
2890  &pUtf8, pUtf8 + a_uInputDataLen,
2891  &pUtf16, pUtf16 + a_uOutputDataSize,
2892  lenientConversion);
2893  }
2894  return retval == conversionOK;
2895  }
2896 
2897  // convert to wchar_t
2898  size_t retval = mbstowcs(a_pOutputData,
2899  a_pInputData, a_uOutputDataSize);
2900  return retval != (size_t)(-1);
2901  }
2902 
2913  size_t SizeToStore(
2914  const SI_CHAR * a_pInputData)
2915  {
2916  if (m_bStoreIsUtf8) {
2917  // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
2918  size_t uLen = 0;
2919  while (a_pInputData[uLen]) {
2920  ++uLen;
2921  }
2922  return (6 * uLen) + 1;
2923  }
2924  else {
2925  size_t uLen = wcstombs(NULL, a_pInputData, 0);
2926  if (uLen == (size_t)(-1)) {
2927  return uLen;
2928  }
2929  return uLen + 1; // include NULL terminator
2930  }
2931  }
2932 
2947  const SI_CHAR * a_pInputData,
2948  char * a_pOutputData,
2949  size_t a_uOutputDataSize
2950  )
2951  {
2952  if (m_bStoreIsUtf8) {
2953  // calc input string length (SI_CHAR type and size independent)
2954  size_t uInputLen = 0;
2955  while (a_pInputData[uInputLen]) {
2956  ++uInputLen;
2957  }
2958  ++uInputLen; // include the NULL char
2959 
2960  // This uses the Unicode reference implementation to do the
2961  // conversion from wchar_t to UTF-8. The required files are
2962  // ConvertUTF.h and ConvertUTF.c which should be included in
2963  // the distribution but are publically available from unicode.org
2964  // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
2965  ConversionResult retval;
2966  UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
2967  if (sizeof(wchar_t) == sizeof(UTF32)) {
2968  const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
2969  retval = ConvertUTF32toUTF8(
2970  &pUtf32, pUtf32 + uInputLen,
2971  &pUtf8, pUtf8 + a_uOutputDataSize,
2972  lenientConversion);
2973  }
2974  else if (sizeof(wchar_t) == sizeof(UTF16)) {
2975  const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
2976  retval = ConvertUTF16toUTF8(
2977  &pUtf16, pUtf16 + uInputLen,
2978  &pUtf8, pUtf8 + a_uOutputDataSize,
2979  lenientConversion);
2980  }
2981  return retval == conversionOK;
2982  }
2983  else {
2984  size_t retval = wcstombs(a_pOutputData,
2985  a_pInputData, a_uOutputDataSize);
2986  return retval != (size_t) -1;
2987  }
2988  }
2989 };
2990 
2991 #endif // SI_CONVERT_GENERIC
2992 
2993 
2994 // ---------------------------------------------------------------------------
2995 // SI_CONVERT_ICU
2996 // ---------------------------------------------------------------------------
2997 #ifdef SI_CONVERT_ICU
2998 
2999 #define SI_Case SI_GenericCase
3000 #define SI_NoCase SI_GenericNoCase
3001 
3002 #include <unicode/ucnv.h>
3003 
3007 template<class SI_CHAR>
3008 class SI_ConvertW {
3009  const char * m_pEncoding;
3010  UConverter * m_pConverter;
3011 protected:
3012  SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { }
3013 public:
3014  SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) {
3015  m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL;
3016  }
3017 
3018  /* copy and assignment */
3019  SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
3020  SI_ConvertW & operator=(const SI_ConvertW & rhs) {
3021  m_pEncoding = rhs.m_pEncoding;
3022  m_pConverter = NULL;
3023  return *this;
3024  }
3025  ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); }
3026 
3040  size_t SizeFromStore(
3041  const char * a_pInputData,
3042  size_t a_uInputDataLen)
3043  {
3044  SI_ASSERT(a_uInputDataLen != (size_t) -1);
3045 
3046  UErrorCode nError;
3047 
3048  if (!m_pConverter) {
3049  nError = U_ZERO_ERROR;
3050  m_pConverter = ucnv_open(m_pEncoding, &nError);
3051  if (U_FAILURE(nError)) {
3052  return (size_t) -1;
3053  }
3054  }
3055 
3056  nError = U_ZERO_ERROR;
3057  int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
3058  a_pInputData, (int32_t) a_uInputDataLen, &nError);
3059  if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3060  return (size_t) -1;
3061  }
3062 
3063  return (size_t) nLen;
3064  }
3065 
3079  bool ConvertFromStore(
3080  const char * a_pInputData,
3081  size_t a_uInputDataLen,
3082  UChar * a_pOutputData,
3083  size_t a_uOutputDataSize)
3084  {
3085  UErrorCode nError;
3086 
3087  if (!m_pConverter) {
3088  nError = U_ZERO_ERROR;
3089  m_pConverter = ucnv_open(m_pEncoding, &nError);
3090  if (U_FAILURE(nError)) {
3091  return false;
3092  }
3093  }
3094 
3095  nError = U_ZERO_ERROR;
3096  ucnv_toUChars(m_pConverter,
3097  a_pOutputData, (int32_t) a_uOutputDataSize,
3098  a_pInputData, (int32_t) a_uInputDataLen, &nError);
3099  if (U_FAILURE(nError)) {
3100  return false;
3101  }
3102 
3103  return true;
3104  }
3105 
3116  size_t SizeToStore(
3117  const UChar * a_pInputData)
3118  {
3119  UErrorCode nError;
3120 
3121  if (!m_pConverter) {
3122  nError = U_ZERO_ERROR;
3123  m_pConverter = ucnv_open(m_pEncoding, &nError);
3124  if (U_FAILURE(nError)) {
3125  return (size_t) -1;
3126  }
3127  }
3128 
3129  nError = U_ZERO_ERROR;
3130  int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
3131  a_pInputData, -1, &nError);
3132  if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3133  return (size_t) -1;
3134  }
3135 
3136  return (size_t) nLen + 1;
3137  }
3138 
3152  bool ConvertToStore(
3153  const UChar * a_pInputData,
3154  char * a_pOutputData,
3155  size_t a_uOutputDataSize)
3156  {
3157  UErrorCode nError;
3158 
3159  if (!m_pConverter) {
3160  nError = U_ZERO_ERROR;
3161  m_pConverter = ucnv_open(m_pEncoding, &nError);
3162  if (U_FAILURE(nError)) {
3163  return false;
3164  }
3165  }
3166 
3167  nError = U_ZERO_ERROR;
3168  ucnv_fromUChars(m_pConverter,
3169  a_pOutputData, (int32_t) a_uOutputDataSize,
3170  a_pInputData, -1, &nError);
3171  if (U_FAILURE(nError)) {
3172  return false;
3173  }
3174 
3175  return true;
3176  }
3177 };
3178 
3179 #endif // SI_CONVERT_ICU
3180 
3181 
3182 // ---------------------------------------------------------------------------
3183 // SI_CONVERT_WIN32
3184 // ---------------------------------------------------------------------------
3185 #ifdef SI_CONVERT_WIN32
3186 
3187 #define SI_Case SI_GenericCase
3188 
3189 // Windows CE doesn't have errno or MBCS libraries
3190 #ifdef _WIN32_WCE
3191 # ifndef SI_NO_MBCS
3192 # define SI_NO_MBCS
3193 # endif
3194 #endif
3195 
3196 #include <windows.h>
3197 #ifdef SI_NO_MBCS
3198 # define SI_NoCase SI_GenericNoCase
3199 #else // !SI_NO_MBCS
3200 
3208 #include <mbstring.h>
3209 template<class SI_CHAR>
3210 struct SI_NoCase {
3211  bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
3212  if (sizeof(SI_CHAR) == sizeof(char)) {
3213  return _mbsicmp((const unsigned char *)pLeft,
3214  (const unsigned char *)pRight) < 0;
3215  }
3216  if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
3217  return _wcsicmp((const wchar_t *)pLeft,
3218  (const wchar_t *)pRight) < 0;
3219  }
3220  return SI_GenericNoCase<SI_CHAR>()(pLeft, pRight);
3221  }
3222 };
3223 #endif // SI_NO_MBCS
3224 
3231 template<class SI_CHAR>
3232 class SI_ConvertW {
3233  UINT m_uCodePage;
3234 protected:
3235  SI_ConvertW() { }
3236 public:
3237  SI_ConvertW(bool a_bStoreIsUtf8) {
3238  m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
3239  }
3240 
3241  /* copy and assignment */
3242  SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
3243  SI_ConvertW & operator=(const SI_ConvertW & rhs) {
3244  m_uCodePage = rhs.m_uCodePage;
3245  return *this;
3246  }
3247 
3261  size_t SizeFromStore(
3262  const char * a_pInputData,
3263  size_t a_uInputDataLen)
3264  {
3265  SI_ASSERT(a_uInputDataLen != (size_t) -1);
3266 
3267  int retval = MultiByteToWideChar(
3268  m_uCodePage, 0,
3269  a_pInputData, (int) a_uInputDataLen,
3270  0, 0);
3271  return (size_t)(retval > 0 ? retval : -1);
3272  }
3273 
3287  bool ConvertFromStore(
3288  const char * a_pInputData,
3289  size_t a_uInputDataLen,
3290  SI_CHAR * a_pOutputData,
3291  size_t a_uOutputDataSize)
3292  {
3293  int nSize = MultiByteToWideChar(
3294  m_uCodePage, 0,
3295  a_pInputData, (int) a_uInputDataLen,
3296  (wchar_t *) a_pOutputData, (int) a_uOutputDataSize);
3297  return (nSize > 0);
3298  }
3299 
3310  size_t SizeToStore(
3311  const SI_CHAR * a_pInputData)
3312  {
3313  int retval = WideCharToMultiByte(
3314  m_uCodePage, 0,
3315  (const wchar_t *) a_pInputData, -1,
3316  0, 0, 0, 0);
3317  return (size_t) (retval > 0 ? retval : -1);
3318  }
3319 
3333  bool ConvertToStore(
3334  const SI_CHAR * a_pInputData,
3335  char * a_pOutputData,
3336  size_t a_uOutputDataSize)
3337  {
3338  int retval = WideCharToMultiByte(
3339  m_uCodePage, 0,
3340  (const wchar_t *) a_pInputData, -1,
3341  a_pOutputData, (int) a_uOutputDataSize, 0, 0);
3342  return retval > 0;
3343  }
3344 };
3345 
3346 #endif // SI_CONVERT_WIN32
3347 
3348 
3349 // ---------------------------------------------------------------------------
3350 // TYPE DEFINITIONS
3351 // ---------------------------------------------------------------------------
3352 
3353 typedef CSimpleIniTempl<char,
3354  SI_NoCase<char>,SI_ConvertA<char> > CSimpleIniA;
3355 typedef CSimpleIniTempl<char,
3357 
3358 #if defined(SI_CONVERT_ICU)
3359 typedef CSimpleIniTempl<UChar,
3360  SI_NoCase<UChar>,SI_ConvertW<UChar> > CSimpleIniW;
3361 typedef CSimpleIniTempl<UChar,
3362  SI_Case<UChar>,SI_ConvertW<UChar> > CSimpleIniCaseW;
3363 #else
3364 typedef CSimpleIniTempl<wchar_t,
3365  SI_NoCase<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniW;
3366 typedef CSimpleIniTempl<wchar_t,
3368 #endif
3369 
3370 #ifdef _UNICODE
3371 # define CSimpleIni CSimpleIniW
3372 # define CSimpleIniCase CSimpleIniCaseW
3373 # define SI_NEWLINE SI_NEWLINE_W
3374 #else // !_UNICODE
3375 # define CSimpleIni CSimpleIniA
3376 # define CSimpleIniCase CSimpleIniCaseA
3377 # define SI_NEWLINE SI_NEWLINE_A
3378 #endif // _UNICODE
3379 
3380 #ifdef _MSC_VER
3381 # pragma warning (pop)
3382 #endif
3383 
3384 #endif // INCLUDED_SimpleIni_h
3385 
SI_FILE
@ SI_FILE
File error (see errno for detail error)
Definition: SimpleIni.h:243
CSimpleIniTempl::StringWriter
OutputWriter class to write the INI data to a string.
Definition: SimpleIni.h:385
SI_ConvertW::operator=
SI_ConvertW & operator=(const SI_ConvertW &rhs)
Definition: SimpleIni.h:2811
CSimpleIniTempl::Delete
bool Delete(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bRemoveEmpty=false)
Delete an entire section, or a key from a section.
Definition: SimpleIni.h:2526
CSimpleIniTempl::GetConverter
Converter GetConverter() const
Return a conversion object to convert text to the same encoding as is used by the Save(),...
Definition: SimpleIni.h:1097
CSimpleIniTempl::Converter::Converter
Converter(const Converter &rhs)
Definition: SimpleIni.h:421
CSimpleIniTempl::Entry::Entry
Entry(const SI_CHAR *a_pszItem=NULL, int a_nOrder=0)
Definition: SimpleIni.h:304
SI_ConvertW::SizeToStore
size_t SizeToStore(const SI_CHAR *a_pInputData)
Calculate the number of char required by the storage format of this data.
Definition: SimpleIni.h:2913
SI_ConvertW::SI_ConvertW
SI_ConvertW(bool a_bStoreIsUtf8)
Definition: SimpleIni.h:2807
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)
Add or update a section or value.
Definition: SimpleIni.h:965
CSimpleIniTempl::IsMultiLine
bool IsMultiLine() const
Query the status of multi-line data.
Definition: SimpleIni.h:529
SI_ConvertW
Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference library functions.
Definition: SimpleIni.h:2802
SI_GenericCase::operator()
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
Definition: SimpleIni.h:2634
SI_GenericNoCase::locase
SI_CHAR locase(SI_CHAR ch) const
Definition: SimpleIni.h:2654
CSimpleIniTempl::StreamWriter::Write
void Write(const char *a_pBuf)
Definition: SimpleIni.h:403
CSimpleIniTempl::Save
SI_Error Save(OutputWriter &a_oOutput, bool a_bAddSignature=false) const
Save the INI data.
Definition: SimpleIni.h:2370
SI_ConvertA::ConvertFromStore
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Convert the input string from the storage format to SI_CHAR.
Definition: SimpleIni.h:2724
SI_ConvertA::SI_ConvertA
SI_ConvertA(bool a_bStoreIsUtf8)
Definition: SimpleIni.h:2678
CSimpleIniCaseW
CSimpleIniTempl< wchar_t, SI_Case< wchar_t >, SI_ConvertW< wchar_t > > CSimpleIniCaseW
Definition: SimpleIni.h:3367
SI_GenericCase
Generic case-sensitive less than comparison.
Definition: SimpleIni.h:2633
CSimpleIniW
CSimpleIniTempl< wchar_t, SI_NoCase< wchar_t >, SI_ConvertW< wchar_t > > CSimpleIniW
Definition: SimpleIni.h:3365
CSimpleIniTempl::Entry::Entry
Entry(const SI_CHAR *a_pszItem, const SI_CHAR *a_pszComment, int a_nOrder)
Definition: SimpleIni.h:309
SI_ConvertA::operator=
SI_ConvertA & operator=(const SI_ConvertA &rhs)
Definition: SimpleIni.h:2682
CSimpleIniTempl::FileWriter::FileWriter
FileWriter(FILE *a_file)
Definition: SimpleIni.h:375
CSimpleIniTempl::TSection
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
map sections to key/value map
Definition: SimpleIni.h:351
CSimpleIniTempl::OutputWriter::~OutputWriter
virtual ~OutputWriter()
Definition: SimpleIni.h:364
CSimpleIniTempl::GetSection
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Retrieve all key and value pairs for a section.
Definition: SimpleIni.h:2254
SI_NOMEM
@ SI_NOMEM
Out of memory error.
Definition: SimpleIni.h:242
SI_ConvertA::SizeFromStore
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Calculate the number of SI_CHAR required for converting the input from the storage format.
Definition: SimpleIni.h:2700
SI_OK
@ SI_OK
No error.
Definition: SimpleIni.h:236
CSimpleIniTempl::Save
SI_Error Save(std::ostream &a_ostream, bool a_bAddSignature=false) const
Save the INI data to an ostream.
Definition: SimpleIni.h:720
CSimpleIniTempl::~CSimpleIniTempl
~CSimpleIniTempl()
Destructor.
Definition: SimpleIni.h:1268
CSimpleIniTempl::Save
SI_Error Save(std::string &a_sBuffer, bool a_bAddSignature=false) const
Append the INI data to a string.
Definition: SimpleIni.h:741
SI_ConvertA::SizeToStore
size_t SizeToStore(const SI_CHAR *a_pInputData)
Calculate the number of char required by the storage format of this data.
Definition: SimpleIni.h:2748
CSimpleIniTempl::FileWriter::Write
void Write(const char *a_pBuf)
Definition: SimpleIni.h:376
SI_ConvertA::SI_ConvertA
SI_ConvertA()
Definition: SimpleIni.h:2676
CSimpleIniTempl::GetAllValues
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Retrieve all values for a specific key.
Definition: SimpleIni.h:2184
CSimpleIniTempl::SetMultiKey
void SetMultiKey(bool a_bAllowMultiKey=true)
Should multiple identical keys be permitted in the file.
Definition: SimpleIni.h:510
CSimpleIniTempl::IsMultiKey
bool IsMultiKey() const
Get the storage format of the INI data.
Definition: SimpleIni.h:515
SI_NoCase
#define SI_NoCase
Definition: SimpleIni.h:2792
CSimpleIniTempl::Entry::operator=
Entry & operator=(const Entry &rhs)
Definition: SimpleIni.h:315
CSimpleIniTempl::CSimpleIniTempl
CSimpleIniTempl(bool a_bIsUtf8=false, bool a_bMultiKey=false, bool a_bMultiLine=false)
Default constructor.
Definition: SimpleIni.h:1252
CSimpleIniTempl::SetMultiLine
void SetMultiLine(bool a_bAllowMultiLine=true)
Should data values be permitted to span multiple lines in the file.
Definition: SimpleIni.h:524
CSimpleIniTempl::Entry::pItem
const SI_CHAR * pItem
Definition: SimpleIni.h:300
CSimpleIniTempl::Converter::Converter
Converter(bool a_bStoreIsUtf8)
Definition: SimpleIni.h:418
CSimpleIniTempl::OutputWriter::OutputWriter
OutputWriter()
Definition: SimpleIni.h:363
SI_INSERTED
@ SI_INSERTED
A new value was inserted.
Definition: SimpleIni.h:238
CSimpleIniTempl::Converter::Data
const char * Data()
Definition: SimpleIni.h:439
CSimpleIniCaseA
CSimpleIniTempl< char, SI_Case< char >, SI_ConvertA< char > > CSimpleIniCaseA
Definition: SimpleIni.h:3356
SI_ConvertW::ConvertFromStore
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Convert the input string from the storage format to SI_CHAR.
Definition: SimpleIni.h:2866
CSimpleIniTempl::StreamWriter
OutputWriter class to write the INI data to an ostream.
Definition: SimpleIni.h:399
CSimpleIniTempl::LoadFile
SI_Error LoadFile(const char *a_pszFile)
Load an INI file from disk into memory.
Definition: SimpleIni.h:1298
CSimpleIniTempl
Simple INI file reader.
Definition: SimpleIni.h:293
CSimpleIniTempl::Entry::nOrder
int nOrder
Definition: SimpleIni.h:302
SI_GenericNoCase::operator()
bool operator()(const SI_CHAR *pLeft, const SI_CHAR *pRight) const
Definition: SimpleIni.h:2657
CSimpleIniTempl::Converter::ConvertToStore
bool ConvertToStore(const SI_CHAR *a_pszString)
Definition: SimpleIni.h:426
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)
Add or update a numeric value.
Definition: SimpleIni.h:2029
SI_ConvertW::SI_ConvertW
SI_ConvertW(const SI_ConvertW &rhs)
Definition: SimpleIni.h:2810
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)
Add or update a double value.
Definition: SimpleIni.h:2092
CSimpleIniTempl::Entry::KeyOrder
Strict less ordering by name of key only.
Definition: SimpleIni.h:329
CSimpleIniTempl::OutputWriter
interface definition for the OutputWriter object to pass to Save() in order to output the INI file da...
Definition: SimpleIni.h:361
CSimpleIniTempl::OutputWriter::Write
virtual void Write(const char *a_pBuf)=0
CSimpleIniTempl::SaveFile
SI_Error SaveFile(const char *a_pszFile, bool a_bAddSignature=true) const
Save an INI file from memory to disk.
Definition: SimpleIni.h:2313
CSimpleIniTempl::IsEmpty
bool IsEmpty() const
Has any data been loaded.
Definition: SimpleIni.h:466
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)
Add or update a boolean value.
Definition: SimpleIni.h:2158
CSimpleIniTempl::IsUnicode
bool IsUnicode() const
Get the storage format of the INI data.
Definition: SimpleIni.h:490
CSimpleIniTempl::GetBoolValue
bool GetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bDefault=false, bool *a_pHasMultiple=NULL) const
Retrieve a boolean value for a specific key.
Definition: SimpleIni.h:2123
SI_ConvertW::ConvertToStore
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Convert the input string to the storage format of this data.
Definition: SimpleIni.h:2946
CSimpleIniTempl::SetSpaces
void SetSpaces(bool a_bSpaces=true)
Should spaces be added around the equals sign when writing key/value pairs out.
Definition: SimpleIni.h:537
CSimpleIniTempl::Entry::KeyOrder::operator()
bool operator()(const Entry &lhs, const Entry &rhs) const
Definition: SimpleIni.h:330
SI_UPDATED
@ SI_UPDATED
An existing value was updated.
Definition: SimpleIni.h:237
SI_Error
SI_Error
Definition: SimpleIni.h:235
CSimpleIniTempl::FileWriter
OutputWriter class to write the INI data to a file.
Definition: SimpleIni.h:372
CSimpleIniTempl::SI_CHAR_T
SI_CHAR SI_CHAR_T
Definition: SimpleIni.h:296
CSimpleIniTempl::Converter
Characterset conversion utility class to convert strings to the same format as is used for the storag...
Definition: SimpleIni.h:415
SI_ConvertW::SI_ConvertW
SI_ConvertW()
Definition: SimpleIni.h:2805
CSimpleIniTempl::GetLongValue
long GetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nDefault=0, bool *a_pHasMultiple=NULL) const
Retrieve a numeric value for a specific key.
Definition: SimpleIni.h:1990
SI_NEWLINE_A
#define SI_NEWLINE_A
Definition: SimpleIni.h:252
CSimpleIniTempl::Entry::Entry
Entry(const Entry &rhs)
Definition: SimpleIni.h:314
CSimpleIniTempl::SetUnicode
void SetUnicode(bool a_bIsUtf8=true)
Set the storage format of the INI data.
Definition: SimpleIni.h:485
CSimpleIniTempl::Reset
void Reset()
Deallocate all memory stored by this object.
Definition: SimpleIni.h:1275
CSimpleIniTempl::LoadData
SI_Error LoadData(std::istream &a_istream)
Load INI file data from an istream.
Definition: SimpleIni.h:1461
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
Retrieve the value for a specific key.
Definition: SimpleIni.h:1953
SI_ConvertW::SizeFromStore
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Calculate the number of SI_CHAR required for converting the input from the storage format.
Definition: SimpleIni.h:2829
SI_ConvertA::SI_ConvertA
SI_ConvertA(const SI_ConvertA &rhs)
Definition: SimpleIni.h:2681
CSimpleIniTempl::Entry::pComment
const SI_CHAR * pComment
Definition: SimpleIni.h:301
CSimpleIniTempl::GetAllSections
void GetAllSections(TNamesDepend &a_names) const
Retrieve all section names.
Definition: SimpleIni.h:2269
CSimpleIniTempl::Entry::LoadOrder::operator()
bool operator()(const Entry &lhs, const Entry &rhs) const
Definition: SimpleIni.h:338
CSimpleIniTempl::TNamesDepend
std::list< Entry > TNamesDepend
set of dependent string pointers.
Definition: SimpleIni.h:356
CSimpleIniTempl::StreamWriter::StreamWriter
StreamWriter(std::ostream &a_ostream)
Definition: SimpleIni.h:402
SI_ASSERT
#define SI_ASSERT(x)
Definition: SimpleIni.h:232
CSimpleIniA
CSimpleIniTempl< char, SI_NoCase< char >, SI_ConvertA< char > > CSimpleIniA
Definition: SimpleIni.h:3354
SI_ConvertA
Null conversion class for MBCS/UTF-8 to char (or equivalent).
Definition: SimpleIni.h:2673
CSimpleIniTempl::GetAllKeys
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Retrieve all unique key names in a section.
Definition: SimpleIni.h:2282
SI_GenericNoCase
Generic ASCII case-insensitive less than comparison.
Definition: SimpleIni.h:2653
SI_FAIL
@ SI_FAIL
Generic failure.
Definition: SimpleIni.h:241
CSimpleIniTempl::UsingSpaces
bool UsingSpaces() const
Query the status of spaces output.
Definition: SimpleIni.h:542
CSimpleIniTempl::StringWriter::Write
void Write(const char *a_pBuf)
Definition: SimpleIni.h:389
CSimpleIniTempl::GetDoubleValue
double GetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nDefault=0, bool *a_pHasMultiple=NULL) const
Retrieve a numeric value for a specific key.
Definition: SimpleIni.h:2061
CSimpleIniTempl::Entry::LoadOrder
Strict less ordering by order, and then name of key.
Definition: SimpleIni.h:337
CSimpleIniTempl::StringWriter::StringWriter
StringWriter(std::string &a_string)
Definition: SimpleIni.h:388
SI_ConvertA::ConvertToStore
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Convert the input string to the storage format of this data.
Definition: SimpleIni.h:2768
CSimpleIniTempl::LoadData
SI_Error LoadData(const std::string &a_strData)
Load INI file data direct from a std::string.
Definition: SimpleIni.h:601
CSimpleIniTempl::Converter::operator=
Converter & operator=(const Converter &rhs)
Definition: SimpleIni.h:422
CSimpleIniTempl::TKeyVal
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
map keys to values
Definition: SimpleIni.h:348
CSimpleIniTempl::Entry
key entry
Definition: SimpleIni.h:299
SI_UTF8_SIGNATURE
#define SI_UTF8_SIGNATURE
Definition: SimpleIni.h:246
CSimpleIniTempl::GetSectionSize
int GetSectionSize(const SI_CHAR *a_pSection) const
Query the number of keys in a specific section.
Definition: SimpleIni.h:2219