226#ifndef INCLUDED_SimpleIni_h
227#define INCLUDED_SimpleIni_h
229#if defined(_MSC_VER) && (_MSC_VER >= 1020)
244#pragma warning(disable : 4127 4503 4702 4786)
257#ifdef SI_SUPPORT_IOSTREAMS
265#define SI_ASSERT(x) assert(x)
272constexpr int SI_OK = 0;
273constexpr int SI_UPDATED = 1;
274constexpr int SI_INSERTED = 2;
277constexpr int SI_FAIL = -1;
278constexpr int SI_NOMEM = -2;
279constexpr int SI_FILE = -3;
283constexpr size_t SI_MAX_FILE_SIZE = 1024ULL * 1024ULL * 1024ULL;
285#define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
288#define SI_NEWLINE_A "\r\n"
289#define SI_NEWLINE_W L"\r\n"
291#define SI_NEWLINE_A "\n"
292#define SI_NEWLINE_W L"\n"
295#if defined(SI_CONVERT_ICU)
296#include <unicode/ustring.h>
300#define SI_HAS_WIDE_FILE
301#define SI_WCHAR_T wchar_t
302#elif defined(SI_CONVERT_ICU)
303#define SI_HAS_WIDE_FILE
304#define SI_WCHAR_T UChar
330template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
333 typedef SI_CHAR SI_CHAR_T;
337 const SI_CHAR *pItem;
338 const SI_CHAR *pComment;
341 Entry(
const SI_CHAR *a_pszItem = NULL,
int a_nOrder = 0)
342 : pItem(a_pszItem), pComment(NULL), nOrder(a_nOrder) {}
343 Entry(
const SI_CHAR *a_pszItem,
const SI_CHAR *a_pszComment,
int a_nOrder)
344 : pItem(a_pszItem), pComment(a_pszComment), nOrder(a_nOrder) {}
348 pComment = rhs.pComment;
353#if defined(_MSC_VER) && _MSC_VER <= 1200
355 bool operator<(
const Entry &rhs)
const {
return LoadOrder()(*
this, rhs); }
356 bool operator>(
const Entry &rhs)
const {
return LoadOrder()(rhs, *
this); }
361 bool operator()(
const Entry &lhs,
const Entry &rhs)
const {
362 const static SI_STRLESS isLess = SI_STRLESS();
363 return isLess(lhs.pItem, rhs.pItem);
369 bool operator()(
const Entry &lhs,
const Entry &rhs)
const {
370 if (lhs.nOrder != rhs.nOrder) {
371 return lhs.nOrder < rhs.nOrder;
379 typedef std::multimap<Entry, const SI_CHAR *, typename Entry::KeyOrder>
383 typedef std::map<Entry, TKeyVal, typename Entry::KeyOrder>
TSection;
397 virtual void Write(
const char *a_pBuf) = 0;
410 void Write(
const char *a_pBuf) { fputs(a_pBuf, m_file); }
419 std::string &m_string;
422 StringWriter(std::string &a_string) : m_string(a_string) {}
423 void Write(
const char *a_pBuf) { m_string.append(a_pBuf); }
430#ifdef SI_SUPPORT_IOSTREAMS
433 std::ostream &m_ostream;
436 StreamWriter(std::ostream &a_ostream) : m_ostream(a_ostream) {}
437 void Write(
const char *a_pBuf) { m_ostream << a_pBuf; }
440 StreamWriter(
const StreamWriter &);
441 StreamWriter &operator=(
const StreamWriter &);
450 Converter(
bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
451 m_scratch.resize(1024);
454 : SI_CONVERTER(rhs), m_scratch(rhs.m_scratch) {}
456 SI_CONVERTER::operator=(rhs);
457 m_scratch = rhs.m_scratch;
460 bool ConvertToStore(
const SI_CHAR *a_pszString) {
461 size_t uLen = SI_CONVERTER::SizeToStore(a_pszString);
462 if (uLen == (
size_t)(-1)) {
465 while (uLen > m_scratch.size()) {
466 m_scratch.resize(m_scratch.size() * 2);
468 return SI_CONVERTER::ConvertToStore(
469 a_pszString,
const_cast<char *
>(m_scratch.data()), m_scratch.size());
471 const char *Data() {
return m_scratch.data(); }
474 std::string m_scratch;
487 bool a_bMultiLine =
false);
496 bool IsEmpty()
const {
return m_data.empty(); }
517 m_bStoreIsUtf8 = a_bIsUtf8;
542 m_bAllowMultiKey = a_bAllowMultiKey;
556 m_bAllowMultiLine = a_bAllowMultiLine;
568 void SetSpaces(
bool a_bSpaces =
true) { m_bSpaces = a_bSpaces; }
578 m_bParseQuotes = a_bParseQuotes;
593 m_bAllowKeyOnly = a_bAllowKeyOnly;
611 SI_Error
LoadFile(
const char *a_pszFile);
613#ifdef SI_HAS_WIDE_FILE
620 SI_Error
LoadFile(
const SI_WCHAR_T *a_pwszFile);
632#ifdef SI_SUPPORT_IOSTREAMS
643 SI_Error
LoadData(std::istream &a_istream);
653 return LoadData(a_strData.c_str(), a_strData.size());
663 SI_Error
LoadData(
const char *a_pData,
size_t a_uDataLen);
681 SI_Error
SaveFile(
const char *a_pszFile,
bool a_bAddSignature =
true)
const;
683#ifdef SI_HAS_WIDE_FILE
694 SI_Error
SaveFile(
const SI_WCHAR_T *a_pwszFile,
695 bool a_bAddSignature =
true)
const;
710 SI_Error
SaveFile(FILE *a_pFile,
bool a_bAddSignature =
false)
const;
743 SI_Error
Save(OutputWriter &a_oOutput,
bool a_bAddSignature =
false)
const;
745#ifdef SI_SUPPORT_IOSTREAMS
757 SI_Error
Save(std::ostream &a_ostream,
bool a_bAddSignature =
false)
const {
758 StreamWriter writer(a_ostream);
759 return Save(writer, a_bAddSignature);
774 SI_Error
Save(std::string &a_sBuffer,
bool a_bAddSignature =
false)
const {
776 return Save(writer, a_bAddSignature);
834 bool GetAllValues(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
870 const SI_CHAR *a_pKey)
const {
871 return GetValue(a_pSection, a_pKey) != NULL;
891 const SI_CHAR *
GetValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
892 const SI_CHAR *a_pDefault = NULL,
893 bool *a_pHasMultiple = NULL)
const;
908 long GetLongValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
909 long a_nDefault = 0,
bool *a_pHasMultiple = NULL)
const;
924 double GetDoubleValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
925 double a_nDefault = 0,
926 bool *a_pHasMultiple = NULL)
const;
946 bool GetBoolValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
947 bool a_bDefault =
false,
bool *a_pHasMultiple = NULL)
const;
978 SI_Error
SetValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
979 const SI_CHAR *a_pValue,
const SI_CHAR *a_pComment = NULL,
980 bool a_bForceReplace =
false) {
983 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace,
1010 SI_Error
SetLongValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1011 long a_nValue,
const SI_CHAR *a_pComment = NULL,
1012 bool a_bUseHex =
false,
bool a_bForceReplace =
false);
1034 SI_Error
SetDoubleValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1035 double a_nValue,
const SI_CHAR *a_pComment = NULL,
1036 bool a_bForceReplace =
false);
1058 SI_Error
SetBoolValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1059 bool a_bValue,
const SI_CHAR *a_pComment = NULL,
1060 bool a_bForceReplace =
false);
1080 bool Delete(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1081 bool a_bRemoveEmpty =
false);
1103 bool DeleteValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1104 const SI_CHAR *a_pValue,
bool a_bRemoveEmpty =
false);
1127 SI_Error FindFileComment(SI_CHAR *&a_pData,
bool a_bCopyStrings);
1133 bool FindEntry(SI_CHAR *&a_pData,
const SI_CHAR *&a_pSection,
1134 const SI_CHAR *&a_pKey,
const SI_CHAR *&a_pVal,
1135 const SI_CHAR *&a_pComment)
const;
1159 SI_Error AddEntry(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1160 const SI_CHAR *a_pValue,
const SI_CHAR *a_pComment,
1161 bool a_bForceReplace,
bool a_bCopyStrings);
1164 inline bool IsSpace(SI_CHAR ch)
const {
1165 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
1169 inline bool IsComment(SI_CHAR ch)
const {
return (ch ==
';' || ch ==
'#'); }
1172 inline void SkipNewLine(SI_CHAR *&a_pData)
const {
1173 a_pData += (*a_pData ==
'\r' && *(a_pData + 1) ==
'\n') ? 2 : 1;
1177 SI_Error CopyString(
const SI_CHAR *&a_pString);
1185 void UndoIncrementalLoadData(
const TNamesDepend &a_oAddedSections,
1189 void DeleteString(
const SI_CHAR *a_pString);
1192 bool IsLess(
const SI_CHAR *a_pLeft,
const SI_CHAR *a_pRight)
const {
1193 const static SI_STRLESS isLess = SI_STRLESS();
1194 return isLess(a_pLeft, a_pRight);
1197 bool IsMultiLineTag(
const SI_CHAR *a_pData)
const;
1198 bool IsMultiLineData(
const SI_CHAR *a_pData)
const;
1199 bool IsSingleLineQuotedValue(
const SI_CHAR *a_pData)
const;
1200 bool MultiLineTextHasTag(
const SI_CHAR *a_pText,
const SI_CHAR *a_pTag)
const;
1201 bool LoadMultiLineText(SI_CHAR *&a_pData,
const SI_CHAR *&a_pVal,
1202 const SI_CHAR *a_pTagName,
1203 bool a_bAllowBlankLinesInComment =
false)
const;
1204 bool IsNewLineChar(SI_CHAR a_c)
const;
1206 bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter,
1207 const SI_CHAR *a_pText)
const;
1224 const SI_CHAR *m_pFileComment;
1227 const SI_CHAR m_cEmptyString;
1239 bool m_bStoreIsUtf8;
1242 bool m_bAllowMultiKey;
1245 bool m_bAllowMultiLine;
1251 bool m_bParseQuotes;
1254 bool m_bAllowKeyOnly;
1266template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1268 bool a_bIsUtf8,
bool a_bAllowMultiKey,
bool a_bAllowMultiLine)
1269 : m_pData(0), m_uDataLen(0), m_pFileComment(NULL), m_cEmptyString(0),
1270 m_bStoreIsUtf8(a_bIsUtf8), m_bAllowMultiKey(a_bAllowMultiKey),
1271 m_bAllowMultiLine(a_bAllowMultiLine), m_bSpaces(true),
1272 m_bParseQuotes(false), m_bAllowKeyOnly(false), m_nOrder(0) {}
1274template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1279template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1285 m_pFileComment = NULL;
1287 if (!m_data.empty()) {
1288 m_data.erase(m_data.begin(), m_data.end());
1292 if (!m_strings.empty()) {
1293 typename TNamesDepend::iterator i = m_strings.begin();
1294 for (; i != m_strings.end(); ++i) {
1295 delete[]
const_cast<SI_CHAR *
>(i->pItem);
1297 m_strings.erase(m_strings.begin(), m_strings.end());
1301namespace SI_Internal {
1302#ifdef SI_CONVERT_ICU
1304inline SI_Error UCharPathToUtf8(
const UChar *a_pPath,
char *&a_pUtf8Path) {
1306 UErrorCode status = U_ZERO_ERROR;
1308 u_strToUTF8(NULL, 0, &uLen, a_pPath, -1, &status);
1309 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
1315 char *pBuf =
new (std::nothrow)
char[
static_cast<size_t>(uLen) + 1];
1319 status = U_ZERO_ERROR;
1320 u_strToUTF8(pBuf, uLen + 1, NULL, a_pPath, -1, &status);
1321 if (U_FAILURE(status)) {
1331inline bool GetFileSize(FILE *a_fpFile,
size_t &a_uSize) {
1334#if defined(_WIN32) && !defined(_WIN32_WCE)
1335 if (_fseeki64(a_fpFile, 0, SEEK_END) != 0) {
1338 const __int64 nSize = _ftelli64(a_fpFile);
1342 if (
static_cast<unsigned long long>(nSize) >
1343 static_cast<unsigned long long>(SI_MAX_FILE_SIZE)) {
1346 if (
static_cast<unsigned long long>(nSize) >
1347 static_cast<unsigned long long>(std::numeric_limits<size_t>::max())) {
1350 a_uSize =
static_cast<size_t>(nSize);
1351 if (_fseeki64(a_fpFile, 0, SEEK_SET) != 0) {
1355#elif defined(_POSIX_VERSION) || defined(__unix__) || defined(__APPLE__)
1356 if (fseeko(a_fpFile, 0, SEEK_END) != 0) {
1359 const off_t nSize = ftello(a_fpFile);
1363 if (
static_cast<unsigned long long>(nSize) >
1364 static_cast<unsigned long long>(SI_MAX_FILE_SIZE)) {
1367 if (
static_cast<unsigned long long>(nSize) >
1368 static_cast<unsigned long long>(std::numeric_limits<size_t>::max())) {
1371 a_uSize =
static_cast<size_t>(nSize);
1372 if (fseeko(a_fpFile, 0, SEEK_SET) != 0) {
1377 if (fseek(a_fpFile, 0, SEEK_END) != 0) {
1380 const long nSize = ftell(a_fpFile);
1384 if (
static_cast<unsigned long long>(nSize) >
1385 static_cast<unsigned long long>(SI_MAX_FILE_SIZE)) {
1388 a_uSize =
static_cast<size_t>(nSize);
1389 if (fseek(a_fpFile, 0, SEEK_SET) != 0) {
1397template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1399 const char *a_pszFile) {
1401#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1402 fopen_s(&fp, a_pszFile,
"rb");
1404 fp = fopen(a_pszFile,
"rb");
1409 SI_Error rc = LoadFile(fp);
1414#ifdef SI_HAS_WIDE_FILE
1415template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1417 const SI_WCHAR_T *a_pwszFile) {
1420#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1421 _wfopen_s(&fp, a_pwszFile, L
"rb");
1423 fp = _wfopen(a_pwszFile, L
"rb");
1427 SI_Error rc = LoadFile(fp);
1431 char *szFile = NULL;
1432 SI_Error rcPath = SI_Internal::UCharPathToUtf8(a_pwszFile, szFile);
1436 SI_Error rc = LoadFile(szFile);
1443template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1447 if (!SI_Internal::GetFileSize(a_fpFile, uSize)) {
1455 char *pData =
new (std::nothrow)
char[uSize + 1];
1462 size_t uRead = fread(pData,
sizeof(
char), uSize, a_fpFile);
1463 if (uRead != uSize) {
1469 SI_Error rc = LoadData(pData, uRead);
1474template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1476 const char *a_pData,
size_t a_uDataLen) {
1484 if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
1487 SI_ASSERT(m_bStoreIsUtf8 || !m_pData);
1491 if (a_uDataLen == 0) {
1496 SI_CONVERTER converter(m_bStoreIsUtf8);
1497 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
1498 if (uLen == (
size_t)(-1)) {
1503 if (uLen >= (SI_MAX_FILE_SIZE /
sizeof(SI_CHAR))) {
1509 SI_CHAR *pData =
new (std::nothrow) SI_CHAR[uLen + 1];
1513 memset(pData, 0,
sizeof(SI_CHAR) * (uLen + 1));
1516 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
1522 const static SI_CHAR empty = 0;
1523 SI_CHAR *pWork = pData;
1524 const SI_CHAR *pSection = ∅
1525 const SI_CHAR *pItem = NULL;
1526 const SI_CHAR *pVal = NULL;
1527 const SI_CHAR *pComment = NULL;
1531 bool bCopyStrings = (m_pData != NULL);
1533 size_t nStringsBefore = 0;
1534 const SI_CHAR *pFileCommentBefore = NULL;
1538 nStringsBefore = m_strings.size();
1539 pFileCommentBefore = m_pFileComment;
1544 SI_Error rc = FindFileComment(pWork, bCopyStrings);
1548 m_pFileComment = pFileCommentBefore;
1549 while (m_strings.size() > nStringsBefore) {
1550 delete[]
const_cast<SI_CHAR *
>(m_strings.back().pItem);
1551 m_strings.pop_back();
1554 m_pFileComment = NULL;
1560 while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
1561 bool bSectionExisted = SectionExists(pSection);
1562 bool bKeyExisted = pItem && bSectionExisted && KeyExists(pSection, pItem);
1564 rc = AddEntry(pSection, pItem, pVal, pComment,
false, bCopyStrings);
1567 m_pFileComment = pFileCommentBefore;
1568 UndoIncrementalLoadData(oAddedSections, oAddedKeys);
1569 while (m_strings.size() > nStringsBefore) {
1570 delete[]
const_cast<SI_CHAR *
>(m_strings.back().pItem);
1571 m_strings.pop_back();
1575 m_pFileComment = NULL;
1583 if (!bSectionExisted && *pSection) {
1584 oAddedSections.push_back(
Entry(pSection, NULL, 0));
1586 if (pItem && !bKeyExisted) {
1587 oAddedKeys.push_back(
Entry(pItem, pSection, 0));
1597 m_uDataLen = uLen + 1;
1603#ifdef SI_SUPPORT_IOSTREAMS
1604template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1606 std::istream &a_istream) {
1607 std::string strData;
1609 while (a_istream.read(buf,
sizeof(buf)) || a_istream.gcount() > 0) {
1610 const std::streamsize nRead = a_istream.gcount();
1611 for (std::streamsize i = 0; i < nRead; ++i) {
1612 if (buf[i] ==
'\0') {
1616 if (strData.size() +
static_cast<size_t>(nRead) > SI_MAX_FILE_SIZE) {
1619 strData.append(buf,
static_cast<size_t>(nRead));
1621 return LoadData(strData.data(), strData.size());
1625template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1627 SI_CHAR *&a_pData,
bool a_bCopyStrings) {
1629 if (m_pFileComment) {
1635 if (!LoadMultiLineText(a_pData, m_pFileComment, NULL,
false)) {
1640 if (a_bCopyStrings) {
1641 SI_Error rc = CopyString(m_pFileComment);
1649template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1651 SI_CHAR *&a_pData,
const SI_CHAR *&a_pSection,
const SI_CHAR *&a_pKey,
1652 const SI_CHAR *&a_pVal,
const SI_CHAR *&a_pComment)
const {
1656 bool bHaveValue =
false;
1657 SI_CHAR *pTrail = NULL;
1660 while (*a_pData && IsSpace(*a_pData)) {
1669 if (IsComment(*a_pData)) {
1670 LoadMultiLineText(a_pData, a_pComment, NULL,
true);
1675 if (*a_pData ==
'[') {
1678 while (*a_pData && IsSpace(*a_pData)) {
1684 a_pSection = a_pData;
1685 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData)) {
1690 if (*a_pData !=
']') {
1695 pTrail = a_pData - 1;
1696 while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1704 while (*a_pData && !IsNewLineChar(*a_pData)) {
1715 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData)) {
1721 bHaveValue = (*a_pData ==
'=');
1722 if (!bHaveValue && !m_bAllowKeyOnly) {
1727 if (bHaveValue && a_pKey == a_pData) {
1728 while (*a_pData && !IsNewLineChar(*a_pData)) {
1735 pTrail = a_pData - 1;
1736 while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1747 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1753 while (*a_pData && !IsNewLineChar(*a_pData)) {
1758 pTrail = a_pData - 1;
1760 SkipNewLine(a_pData);
1762 while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1769 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1771 const SI_CHAR *pTagName = a_pVal + 3;
1772 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1776 if (m_bParseQuotes) {
1778 if (pTrail > a_pVal && *a_pVal ==
'"' && *pTrail ==
'"') {
1786 SkipNewLine(a_pData);
1799template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1801 const SI_CHAR *a_pVal)
const {
1803 if (*a_pVal++ !=
'<')
1805 if (*a_pVal++ !=
'<')
1807 if (*a_pVal++ !=
'<')
1812template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1814 const SI_CHAR *a_pData)
const {
1826 if (IsSpace(*a_pData)) {
1831 const SI_CHAR *pStart = a_pData;
1833 if (IsNewLineChar(*a_pData)) {
1840 if (a_pData > pStart && IsSpace(*(a_pData - 1))) {
1847template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1849 const SI_CHAR *a_pText,
const SI_CHAR *a_pTag)
const {
1850 if (!a_pText || !a_pTag) {
1853 const SI_CHAR *p = a_pText;
1855 const SI_CHAR *pEndOfLine = p;
1856 while (*pEndOfLine && *pEndOfLine !=
'\n') {
1859 const std::basic_string<SI_CHAR> line(p,
1860 static_cast<size_t>(pEndOfLine - p));
1861 if (!IsLess(line.c_str(), a_pTag) && !IsLess(a_pTag, line.c_str())) {
1872template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1884 const SI_CHAR *pStart = a_pData;
1886 if (IsNewLineChar(*a_pData)) {
1893 if (IsSpace(*pStart)) {
1898 if (a_pData > pStart && IsSpace(*(a_pData - 1))) {
1903 if (a_pData > pStart + 1 && *pStart ==
'"' && *(a_pData - 1) ==
'"') {
1910template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1912 SI_CHAR a_c)
const {
1913 return (a_c ==
'\n' || a_c ==
'\r');
1916template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1918 SI_CHAR *&a_pData,
const SI_CHAR *&a_pVal,
const SI_CHAR *a_pTagName,
1919 bool a_bAllowBlankLinesInComment)
const {
1928 SI_CHAR *pDataLine = a_pData;
1937 SI_CHAR cEndOfLineChar = *a_pData;
1941 if (!a_pTagName && !IsComment(*a_pData)) {
1943 if (!a_bAllowBlankLinesInComment) {
1950 SI_CHAR *pCurr = a_pData;
1952 while (IsSpace(*pCurr)) {
1953 if (IsNewLineChar(*pCurr)) {
1963 if (IsComment(*pCurr)) {
1964 for (; nNewLines > 0; --nNewLines)
1965 *pDataLine++ =
'\n';
1975 pCurrLine = a_pData;
1976 while (*a_pData && !IsNewLineChar(*a_pData))
1980 if (pDataLine < pCurrLine) {
1981 size_t nLen = (size_t)(a_pData - pCurrLine);
1982 memmove(pDataLine, pCurrLine, nLen *
sizeof(SI_CHAR));
1983 pDataLine[nLen] =
'\0';
1987 cEndOfLineChar = *a_pData;
1995 SI_CHAR *pc = a_pData - 1;
1996 while (pc > pDataLine && IsSpace(*pc))
2001 if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) {
2010 if (!cEndOfLineChar) {
2016 pDataLine += (a_pData - pCurrLine);
2017 *a_pData = cEndOfLineChar;
2018 SkipNewLine(a_pData);
2019 *pDataLine++ =
'\n';
2023 if (a_pVal == a_pData) {
2032 *--pDataLine =
'\0';
2036 if (a_pTagName && cEndOfLineChar) {
2037 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
2038 *a_pData = cEndOfLineChar;
2039 SkipNewLine(a_pData);
2045template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2047 const SI_CHAR *&a_pString) {
2049 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
2050 uLen = strlen((
const char *)a_pString);
2051 }
else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
2052 uLen = wcslen((
const wchar_t *)a_pString);
2054 for (; a_pString[uLen]; ++uLen)
2057 if (uLen >= (SI_MAX_FILE_SIZE /
sizeof(SI_CHAR))) {
2061 SI_CHAR *pCopy =
new (std::nothrow) SI_CHAR[uLen];
2065 memcpy(pCopy, a_pString,
sizeof(SI_CHAR) * uLen);
2066 m_strings.push_back(pCopy);
2071template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2074 const TNamesDepend &a_oAddedKeys) {
2075 typename TNamesDepend::const_iterator iAddedKey = a_oAddedKeys.begin();
2076 for (; iAddedKey != a_oAddedKeys.end(); ++iAddedKey) {
2077 Delete(iAddedKey->pComment, iAddedKey->pItem,
false);
2080 typename TNamesDepend::const_iterator iAddedSection =
2081 a_oAddedSections.begin();
2082 for (; iAddedSection != a_oAddedSections.end(); ++iAddedSection) {
2083 Delete(iAddedSection->pItem, NULL,
false);
2087template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2089 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
const SI_CHAR *a_pValue,
2090 const SI_CHAR *a_pComment,
bool a_bForceReplace,
bool a_bCopyStrings) {
2092 bool bInserted =
false;
2093 bool bInsertedSection =
false;
2094 bool bCopiedComment =
false;
2095 bool bCopiedSection =
false;
2096 bool bCopiedKey =
false;
2098 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
2102 if (a_bCopyStrings && a_pComment) {
2103 rc = CopyString(a_pComment);
2106 bCopiedComment =
true;
2110 typename TSection::iterator iSection = m_data.find(a_pSection);
2111 if (iSection == m_data.end()) {
2114 if (a_bCopyStrings) {
2115 rc = CopyString(a_pSection);
2117 if (bCopiedComment) {
2118 DeleteString(a_pComment);
2122 bCopiedSection =
true;
2126 Entry oSection(a_pSection, ++m_nOrder);
2127 if (a_pComment && !a_pKey) {
2128 oSection.pComment = a_pComment;
2131 typename TSection::value_type oEntry(oSection, TKeyVal());
2132 typedef typename TSection::iterator SectionIterator;
2133 std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
2136 bInsertedSection =
true;
2140 return bInserted ? SI_INSERTED : SI_UPDATED;
2144 TKeyVal &keyval = iSection->second;
2145 typename TKeyVal::iterator iKey = keyval.find(a_pKey);
2146 bInserted = iKey == keyval.end();
2150 int nLoadOrder = ++m_nOrder;
2151 if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
2152 const SI_CHAR *pComment = NULL;
2153 while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
2154 if (iKey->first.nOrder < nLoadOrder) {
2155 nLoadOrder = iKey->first.nOrder;
2156 pComment = iKey->first.pComment;
2161 DeleteString(a_pComment);
2162 a_pComment = pComment;
2163 rc = CopyString(a_pComment);
2167 Delete(a_pSection, a_pKey);
2168 iKey = keyval.end();
2173 a_pValue = &m_cEmptyString;
2177 bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
2178 if (a_bCopyStrings) {
2179 if (bForceCreateNewKey || iKey == keyval.end()) {
2183 rc = CopyString(a_pKey);
2185 if (bInsertedSection) {
2186 m_data.erase(iSection);
2188 if (bCopiedSection) {
2189 DeleteString(a_pSection);
2191 if (bCopiedComment) {
2192 DeleteString(a_pComment);
2200 rc = CopyString(a_pValue);
2203 DeleteString(a_pKey);
2205 if (bInsertedSection) {
2206 m_data.erase(iSection);
2208 if (bCopiedSection) {
2209 DeleteString(a_pSection);
2211 if (bCopiedComment) {
2212 DeleteString(a_pComment);
2219 if (iKey == keyval.end() || bForceCreateNewKey) {
2220 Entry oKey(a_pKey, nLoadOrder);
2222 oKey.pComment = a_pComment;
2224 typename TKeyVal::value_type oEntry(oKey,
2225 static_cast<const SI_CHAR *
>(NULL));
2226 iKey = keyval.insert(oEntry);
2228 DeleteString(iKey->second);
2231 iKey->second = a_pValue;
2232 return bInserted ? SI_INSERTED : SI_UPDATED;
2235template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2237 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
const SI_CHAR *a_pDefault,
2238 bool *a_pHasMultiple)
const {
2239 if (a_pHasMultiple) {
2240 *a_pHasMultiple =
false;
2242 if (!a_pSection || !a_pKey) {
2245 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2246 if (iSection == m_data.end()) {
2249 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2250 if (iKeyVal == iSection->second.end()) {
2255 if (m_bAllowMultiKey && a_pHasMultiple) {
2256 typename TKeyVal::const_iterator iTemp = iKeyVal;
2257 if (++iTemp != iSection->second.end()) {
2258 if (!IsLess(a_pKey, iTemp->first.pItem)) {
2259 *a_pHasMultiple =
true;
2264 return iKeyVal->second;
2267template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2269 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
long a_nDefault,
2270 bool *a_pHasMultiple)
const {
2272 const SI_CHAR *pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2273 if (!pszValue || !*pszValue)
2277 char szValue[64] = {0};
2278 SI_CONVERTER c(m_bStoreIsUtf8);
2279 if (!c.ConvertToStore(pszValue, szValue,
sizeof(szValue))) {
2284 long nValue = a_nDefault;
2285 char *pszSuffix = szValue;
2287 if (szValue[0] ==
'0' && (szValue[1] ==
'x' || szValue[1] ==
'X')) {
2290 nValue = strtol(&szValue[2], &pszSuffix, 16);
2292 nValue = strtol(szValue, &pszSuffix, 10);
2296 if (*pszSuffix || errno == ERANGE) {
2303template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2305 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
long a_nValue,
2306 const SI_CHAR *a_pComment,
bool a_bUseHex,
bool a_bForceReplace) {
2308 if (!a_pSection || !a_pKey)
2313#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2314 sprintf_s(szInput, a_bUseHex ?
"0x%lx" :
"%ld", a_nValue);
2316 snprintf(szInput,
sizeof(szInput), a_bUseHex ?
"0x%lx" :
"%ld", a_nValue);
2320 SI_CHAR szOutput[64];
2321 SI_CONVERTER c(m_bStoreIsUtf8);
2322 if (!c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput,
2323 sizeof(szOutput) /
sizeof(SI_CHAR))) {
2328 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
2332template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2334 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
double a_nDefault,
2335 bool *a_pHasMultiple)
const {
2337 const SI_CHAR *pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2338 if (!pszValue || !*pszValue)
2342 char szValue[64] = {0};
2343 SI_CONVERTER c(m_bStoreIsUtf8);
2344 if (!c.ConvertToStore(pszValue, szValue,
sizeof(szValue))) {
2348 char *pszSuffix = szValue;
2349 double nValue = strtod(szValue, &pszSuffix);
2353 if (pszSuffix == szValue || *pszSuffix) {
2360template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2362 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
double a_nValue,
2363 const SI_CHAR *a_pComment,
bool a_bForceReplace) {
2365 if (!a_pSection || !a_pKey)
2370#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2371 sprintf_s(szInput,
"%.17g", a_nValue);
2373 snprintf(szInput,
sizeof(szInput),
"%.17g", a_nValue);
2377 SI_CHAR szOutput[64];
2378 SI_CONVERTER c(m_bStoreIsUtf8);
2379 if (!c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput,
2380 sizeof(szOutput) /
sizeof(SI_CHAR))) {
2385 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
2389template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2391 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
bool a_bDefault,
2392 bool *a_pHasMultiple)
const {
2394 const SI_CHAR *pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2395 if (!pszValue || !*pszValue)
2399 switch (pszValue[0]) {
2416 if (pszValue[1] ==
'n' || pszValue[1] ==
'N')
2418 if (pszValue[1] ==
'f' || pszValue[1] ==
'F')
2427template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2429 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
bool a_bValue,
2430 const SI_CHAR *a_pComment,
bool a_bForceReplace) {
2432 if (!a_pSection || !a_pKey)
2436 const char *pszInput = a_bValue ?
"true" :
"false";
2439 SI_CHAR szOutput[64];
2440 SI_CONVERTER c(m_bStoreIsUtf8);
2441 if (!c.ConvertFromStore(pszInput, strlen(pszInput) + 1, szOutput,
2442 sizeof(szOutput) /
sizeof(SI_CHAR))) {
2447 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
2451template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2453 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
2457 if (!a_pSection || !a_pKey) {
2460 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2461 if (iSection == m_data.end()) {
2464 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2465 if (iKeyVal == iSection->second.end()) {
2471 Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2472 if (m_bAllowMultiKey) {
2474 while (iKeyVal != iSection->second.end() &&
2475 !IsLess(a_pKey, iKeyVal->first.pItem)) {
2476 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.pComment,
2477 iKeyVal->first.nOrder));
2485template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2487 const SI_CHAR *a_pSection)
const {
2492 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2493 if (iSection == m_data.end()) {
2496 const TKeyVal §ion = iSection->second;
2500 if (!m_bAllowMultiKey || section.empty()) {
2501 return (
int)section.size();
2506 const SI_CHAR *pLastKey = NULL;
2507 typename TKeyVal::const_iterator iKeyVal = section.begin();
2508 for (; iKeyVal != section.end(); ++iKeyVal) {
2509 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2511 pLastKey = iKeyVal->first.pItem;
2517template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2520 const SI_CHAR *a_pSection)
const {
2522 typename TSection::const_iterator i = m_data.find(a_pSection);
2523 if (i != m_data.end()) {
2524 return &(i->second);
2530template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2534 typename TSection::const_iterator i = m_data.begin();
2535 for (; i != m_data.end(); ++i) {
2536 a_names.push_back(i->first);
2540template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2542 const SI_CHAR *a_pSection,
TNamesDepend &a_names)
const {
2549 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2550 if (iSection == m_data.end()) {
2554 const TKeyVal §ion = iSection->second;
2555 const SI_CHAR *pLastKey = NULL;
2556 typename TKeyVal::const_iterator iKeyVal = section.begin();
2557 for (; iKeyVal != section.end(); ++iKeyVal) {
2558 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2559 a_names.push_back(iKeyVal->first);
2560 pLastKey = iKeyVal->first.pItem;
2567template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2569 const char *a_pszFile,
bool a_bAddSignature)
const {
2571#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2572 fopen_s(&fp, a_pszFile,
"wb");
2574 fp = fopen(a_pszFile,
"wb");
2578 SI_Error rc = SaveFile(fp, a_bAddSignature);
2583#ifdef SI_HAS_WIDE_FILE
2584template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2586 const SI_WCHAR_T *a_pwszFile,
bool a_bAddSignature)
const {
2589#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2590 _wfopen_s(&fp, a_pwszFile, L
"wb");
2592 fp = _wfopen(a_pwszFile, L
"wb");
2596 SI_Error rc = SaveFile(fp, a_bAddSignature);
2600 char *szFile = NULL;
2601 SI_Error rcPath = SI_Internal::UCharPathToUtf8(a_pwszFile, szFile);
2605 SI_Error rc = SaveFile(szFile, a_bAddSignature);
2612template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2614 FILE *a_pFile,
bool a_bAddSignature)
const {
2616 return Save(writer, a_bAddSignature);
2619template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2625 if (m_bStoreIsUtf8 && a_bAddSignature) {
2626 a_oOutput.Write(SI_UTF8_SIGNATURE);
2631 GetAllSections(oSections);
2632#if defined(_MSC_VER) && _MSC_VER <= 1200
2634#elif defined(__BORLANDC__)
2642 typename TNamesDepend::iterator is = oSections.begin();
2643 for (; is != oSections.end(); ++is) {
2646 if (is != oSections.begin()) {
2647 oSections.splice(oSections.begin(), oSections, is, std::next(is));
2654 bool bNeedNewLine =
false;
2655 if (m_pFileComment) {
2656 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
2659 bNeedNewLine =
true;
2663 typename TNamesDepend::const_iterator iSection = oSections.begin();
2664 for (; iSection != oSections.end(); ++iSection) {
2666 if (iSection->pComment) {
2668 a_oOutput.Write(SI_NEWLINE_A);
2669 a_oOutput.Write(SI_NEWLINE_A);
2671 if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
2674 bNeedNewLine =
false;
2678 a_oOutput.Write(SI_NEWLINE_A);
2679 a_oOutput.Write(SI_NEWLINE_A);
2680 bNeedNewLine =
false;
2684 if (*iSection->pItem) {
2685 if (!convert.ConvertToStore(iSection->pItem)) {
2688 a_oOutput.Write(
"[");
2689 a_oOutput.Write(convert.Data());
2690 a_oOutput.Write(
"]");
2691 a_oOutput.Write(SI_NEWLINE_A);
2696 GetAllKeys(iSection->pItem, oKeys);
2697#if defined(_MSC_VER) && _MSC_VER <= 1200
2699#elif defined(__BORLANDC__)
2706 typename TNamesDepend::const_iterator iKey = oKeys.begin();
2707 for (; iKey != oKeys.end(); ++iKey) {
2710 GetAllValues(iSection->pItem, iKey->pItem, oValues);
2712 typename TNamesDepend::const_iterator iValue = oValues.begin();
2713 for (; iValue != oValues.end(); ++iValue) {
2715 if (iValue->pComment) {
2716 a_oOutput.Write(SI_NEWLINE_A);
2717 if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
2723 if (!convert.ConvertToStore(iKey->pItem)) {
2726 a_oOutput.Write(convert.Data());
2729 if (*iValue->pItem || !m_bAllowKeyOnly) {
2730 if (!convert.ConvertToStore(iValue->pItem)) {
2733 a_oOutput.Write(m_bSpaces ?
" = " :
"=");
2734 if (m_bParseQuotes && IsSingleLineQuotedValue(iValue->pItem)) {
2737 a_oOutput.Write(
"\"");
2738 a_oOutput.Write(convert.Data());
2739 a_oOutput.Write(
"\"");
2740 }
else if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
2744 SI_CHAR szTagSi[64];
2748#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2749 sprintf_s(szTag,
"END_OF_TEXT");
2751 snprintf(szTag,
sizeof(szTag),
"END_OF_TEXT");
2754#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2755 sprintf_s(szTag,
"END_OF_TEXT_%d", nSuffix);
2757 snprintf(szTag,
sizeof(szTag),
"END_OF_TEXT_%d", nSuffix);
2761 for (; szTag[u] && u + 1 <
sizeof(szTagSi) /
sizeof(szTagSi[0]);
2763 szTagSi[u] =
static_cast<SI_CHAR
>(szTag[u]);
2766 if (!MultiLineTextHasTag(iValue->pItem, szTagSi)) {
2771 a_oOutput.Write(
"<<<");
2772 a_oOutput.Write(szTag);
2773 a_oOutput.Write(SI_NEWLINE_A);
2774 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
2777 a_oOutput.Write(szTag);
2779 a_oOutput.Write(convert.Data());
2782 a_oOutput.Write(SI_NEWLINE_A);
2786 bNeedNewLine =
true;
2792template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2794 OutputWriter &a_oOutput, Converter &a_oConverter,
2795 const SI_CHAR *a_pText)
const {
2796 const SI_CHAR *pEndOfLine;
2797 SI_CHAR cEndOfLineChar = *a_pText;
2798 while (cEndOfLineChar) {
2800 pEndOfLine = a_pText;
2801 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine)
2803 cEndOfLineChar = *pEndOfLine;
2805 const std::basic_string<SI_CHAR> line(
2806 a_pText,
static_cast<size_t>(pEndOfLine - a_pText));
2807 if (!a_oConverter.ConvertToStore(line.c_str())) {
2810 a_pText += (pEndOfLine - a_pText) + 1;
2811 a_oOutput.Write(a_oConverter.Data());
2812 a_oOutput.Write(SI_NEWLINE_A);
2817template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2819 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
bool a_bRemoveEmpty) {
2820 return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty);
2823template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2825 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
const SI_CHAR *a_pValue,
2826 bool a_bRemoveEmpty) {
2831 typename TSection::iterator iSection = m_data.find(a_pSection);
2832 if (iSection == m_data.end()) {
2838 typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
2839 if (iKeyVal == iSection->second.end()) {
2843 const static SI_STRLESS isLess = SI_STRLESS();
2846 typename TKeyVal::iterator iDelete;
2847 bool bDeleted =
false;
2849 iDelete = iKeyVal++;
2851 if (a_pValue == NULL || (isLess(a_pValue, iDelete->second) ==
false &&
2852 isLess(iDelete->second, a_pValue) ==
false)) {
2853 DeleteString(iDelete->first.pItem);
2854 DeleteString(iDelete->first.pComment);
2855 DeleteString(iDelete->second);
2856 iSection->second.erase(iDelete);
2859 }
while (iKeyVal != iSection->second.end() &&
2860 !IsLess(a_pKey, iKeyVal->first.pItem));
2869 if (!a_bRemoveEmpty || !iSection->second.empty()) {
2875 typename TKeyVal::iterator iKeyVal = iSection->second.begin();
2876 for (; iKeyVal != iSection->second.end(); ++iKeyVal) {
2877 DeleteString(iKeyVal->first.pItem);
2878 DeleteString(iKeyVal->first.pComment);
2879 DeleteString(iKeyVal->second);
2884 DeleteString(iSection->first.pItem);
2885 DeleteString(iSection->first.pComment);
2886 m_data.erase(iSection);
2891template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2893 const SI_CHAR *a_pString) {
2900 if (!m_pData || a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
2901 typename TNamesDepend::iterator i = m_strings.begin();
2902 for (; i != m_strings.end(); ++i) {
2903 if (a_pString == i->pItem) {
2904 delete[]
const_cast<SI_CHAR *
>(i->pItem);
2930#if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && \
2931 !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2933#define SI_CONVERT_WIN32
2935#define SI_NO_CONVERSION
2945 bool operator()(
const SI_CHAR *pLeft,
const SI_CHAR *pRight)
const {
2947 for (; *pLeft && *pRight; ++pLeft, ++pRight) {
2948 cmp = (long)*pLeft - (
long)*pRight;
2953 return *pRight != 0;
2964 inline SI_CHAR locase(SI_CHAR ch)
const {
2965 return (ch <
'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
2967 bool operator()(
const SI_CHAR *pLeft,
const SI_CHAR *pRight)
const {
2969 for (; *pLeft && *pRight; ++pLeft, ++pRight) {
2970 cmp = (long)locase(*pLeft) - (long)locase(*pRight);
2975 return *pRight != 0;
2983 bool m_bStoreIsUtf8;
2989 SI_ConvertA(
bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) {}
2994 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
3013 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
3016 return a_uInputDataLen;
3033 SI_CHAR *a_pOutputData,
size_t a_uOutputDataSize) {
3035 if (a_uInputDataLen > a_uOutputDataSize) {
3038 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
3054 return strlen((
const char *)a_pInputData) + 1;
3071 size_t a_uOutputDataSize) {
3073 size_t uInputLen = strlen((
const char *)a_pInputData) + 1;
3074 if (uInputLen > a_uOutputDataSize) {
3079 memcpy(a_pOutputData, a_pInputData, uInputLen);
3087#ifdef SI_CONVERT_GENERIC
3089#define SI_Case SI_GenericCase
3090#define SI_NoCase SI_GenericNoCase
3096constexpr char32_t REPLACEMENT = 0xFFFD;
3099inline bool Decode(
const char *&a_src,
const char *a_end,
char32_t &a_cp) {
3100 if (a_src >= a_end) {
3103 const unsigned char c0 = (
unsigned char)*a_src++;
3117 }
else if (c0 < 0xF0) {
3120 }
else if (c0 < 0xF5) {
3126 if (a_src + extra > a_end) {
3131 for (
int i = 0; i < extra; ++i) {
3132 const unsigned char cx = (
unsigned char)*a_src++;
3133 if ((cx & 0xC0) != 0x80) {
3137 ch = (ch << 6) | (cx & 0x3F);
3140 if ((extra == 1 && ch < 0x80) || (extra == 2 && ch < 0x800) ||
3141 (extra == 3 && ch < 0x10000) || ch > 0x10FFFF ||
3142 (ch >= 0xD800 && ch <= 0xDFFF)) {
3143 a_src -= (extra + 1);
3154inline int Encode(
char32_t a_cp,
char *a_dst,
size_t a_cap) {
3155 if (a_cp >= 0x110000 || (a_cp >= 0xD800 && a_cp <= 0xDFFF)) {
3162 a_dst[0] = (char)a_cp;
3168 a_dst[0] = (char)(0xC0 | (a_cp >> 6));
3169 a_dst[1] = (char)(0x80 | (a_cp & 0x3F));
3172 if (a_cp < 0x10000) {
3175 a_dst[0] = (char)(0xE0 | (a_cp >> 12));
3176 a_dst[1] = (char)(0x80 | ((a_cp >> 6) & 0x3F));
3177 a_dst[2] = (char)(0x80 | (a_cp & 0x3F));
3182 a_dst[0] = (char)(0xF0 | (a_cp >> 18));
3183 a_dst[1] = (char)(0x80 | ((a_cp >> 12) & 0x3F));
3184 a_dst[2] = (char)(0x80 | ((a_cp >> 6) & 0x3F));
3185 a_dst[3] = (char)(0x80 | (a_cp & 0x3F));
3189template <
class SI_CHAR>
3190inline bool AppendCodePoint(
char32_t a_cp, SI_CHAR *&a_dst, SI_CHAR *a_dstEnd) {
3191 if (
sizeof(SI_CHAR) >=
sizeof(
char32_t)) {
3192 if (a_dst >= a_dstEnd)
3194 *a_dst++ = (SI_CHAR)a_cp;
3197 if (
sizeof(SI_CHAR) == 2) {
3198 if (a_cp < 0x10000) {
3199 if (a_dst >= a_dstEnd)
3201 *a_dst++ = (SI_CHAR)a_cp;
3204 if (a_dst + 1 >= a_dstEnd)
3207 *a_dst++ = (SI_CHAR)(0xD800 + (a_cp >> 10));
3208 *a_dst++ = (SI_CHAR)(0xDC00 + (a_cp & 0x3FF));
3214template <
class SI_CHAR>
3215inline bool ReadCodePoint(
const SI_CHAR *&a_src,
char32_t &a_cp) {
3216 if (
sizeof(SI_CHAR) >=
sizeof(
char32_t)) {
3217 a_cp = (char32_t)*a_src++;
3220 if (
sizeof(SI_CHAR) == 2) {
3221 const char32_t w = (char32_t)*a_src++;
3222 if (w >= 0xD800 && w <= 0xDBFF) {
3223 if (*a_src >= 0xDC00 && *a_src <= 0xDFFF) {
3224 a_cp = 0x10000 + ((w - 0xD800) << 10) + ((char32_t)*a_src++ - 0xDC00);
3240template <
class SI_CHAR>
class SI_ConvertW {
3241 bool m_bStoreIsUtf8;
3247 SI_ConvertW(
bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) {}
3250 SI_ConvertW(
const SI_ConvertW &rhs) { operator=(rhs); }
3251 SI_ConvertW &operator=(
const SI_ConvertW &rhs) {
3252 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
3269 size_t SizeFromStore(
const char *a_pInputData,
size_t a_uInputDataLen) {
3270 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
3272 if (m_bStoreIsUtf8) {
3276 return a_uInputDataLen;
3280#if defined(_MSC_VER)
3282 errno_t e = mbstowcs_s(&uBufSiz, NULL, 0, a_pInputData, a_uInputDataLen);
3283 return (e == 0) ? uBufSiz : (size_t)-1;
3284#elif !defined(SI_NO_MBSTOWCS_NULL)
3288 return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
3293 return a_uInputDataLen;
3310 bool ConvertFromStore(
const char *a_pInputData,
size_t a_uInputDataLen,
3311 SI_CHAR *a_pOutputData,
size_t a_uOutputDataSize) {
3312 if (m_bStoreIsUtf8) {
3313 const char *src = a_pInputData;
3314 const char *srcEnd = a_pInputData + a_uInputDataLen;
3315 SI_CHAR *dst = a_pOutputData;
3316 SI_CHAR *dstEnd = a_pOutputData + a_uOutputDataSize;
3317 if (
sizeof(SI_CHAR) != 2 &&
sizeof(SI_CHAR) <
sizeof(
char32_t)) {
3320 while (src < srcEnd) {
3322 if (!SI_UTF8::Decode(src, srcEnd, cp)) {
3325 if (!SI_UTF8::AppendCodePoint(cp, dst, dstEnd)) {
3333#if defined(_MSC_VER)
3335 errno_t e = mbstowcs_s(&uBufSiz, a_pOutputData, a_uOutputDataSize,
3336 a_pInputData, a_uInputDataLen);
3340 size_t retval = mbstowcs(a_pOutputData, a_pInputData, a_uOutputDataSize);
3341 return retval != (size_t)(-1);
3355 size_t SizeToStore(
const SI_CHAR *a_pInputData) {
3356 if (m_bStoreIsUtf8) {
3359 while (a_pInputData[uLen]) {
3362 return (6 * uLen) + 1;
3364#if defined(_MSC_VER)
3366 errno_t e = wcstombs_s(&uLen, NULL, 0, a_pInputData, 0);
3372 size_t uLen = wcstombs(NULL, a_pInputData, 0);
3373 if (uLen == (
size_t)(-1)) {
3394 bool ConvertToStore(
const SI_CHAR *a_pInputData,
char *a_pOutputData,
3395 size_t a_uOutputDataSize) {
3396 if (m_bStoreIsUtf8) {
3397 const SI_CHAR *src = a_pInputData;
3398 char *dst = a_pOutputData;
3399 char *dstEnd = a_pOutputData + a_uOutputDataSize;
3400 if (
sizeof(SI_CHAR) != 2 &&
sizeof(SI_CHAR) <
sizeof(
char32_t)) {
3405 if (!SI_UTF8::ReadCodePoint(src, cp)) {
3409 const int n = SI_UTF8::Encode(cp, buf,
sizeof(buf));
3410 if (n < 0 || (
size_t)(dstEnd - dst) < (
size_t)n) {
3413 memcpy(dst, buf, (
size_t)n);
3416 if (dst >= dstEnd) {
3422#if defined(_MSC_VER)
3423 size_t converted = 0;
3424 errno_t e = wcstombs_s(&converted, a_pOutputData, a_uOutputDataSize,
3428 size_t retval = wcstombs(a_pOutputData, a_pInputData, a_uOutputDataSize);
3429 return retval != (size_t)-1;
3440#ifdef SI_CONVERT_ICU
3442#define SI_Case SI_GenericCase
3443#define SI_NoCase SI_GenericNoCase
3445#include <unicode/ucnv.h>
3450template <
class SI_CHAR>
class SI_ConvertW {
3451 const char *m_pEncoding;
3452 UConverter *m_pConverter;
3455 SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) {}
3458 SI_ConvertW(
bool a_bStoreIsUtf8) : m_pConverter(NULL) {
3459 m_pEncoding = a_bStoreIsUtf8 ?
"UTF-8" : NULL;
3463 SI_ConvertW(
const SI_ConvertW &rhs) { operator=(rhs); }
3464 SI_ConvertW &operator=(
const SI_ConvertW &rhs) {
3465 m_pEncoding = rhs.m_pEncoding;
3466 m_pConverter = NULL;
3471 ucnv_close(m_pConverter);
3487 size_t SizeFromStore(
const char *a_pInputData,
size_t a_uInputDataLen) {
3488 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
3492 if (!m_pConverter) {
3493 nError = U_ZERO_ERROR;
3494 m_pConverter = ucnv_open(m_pEncoding, &nError);
3495 if (U_FAILURE(nError)) {
3500 nError = U_ZERO_ERROR;
3501 int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, a_pInputData,
3502 (int32_t)a_uInputDataLen, &nError);
3503 if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3507 return (
size_t)nLen;
3523 bool ConvertFromStore(
const char *a_pInputData,
size_t a_uInputDataLen,
3524 UChar *a_pOutputData,
size_t a_uOutputDataSize) {
3527 if (!m_pConverter) {
3528 nError = U_ZERO_ERROR;
3529 m_pConverter = ucnv_open(m_pEncoding, &nError);
3530 if (U_FAILURE(nError)) {
3535 nError = U_ZERO_ERROR;
3536 ucnv_toUChars(m_pConverter, a_pOutputData, (int32_t)a_uOutputDataSize,
3537 a_pInputData, (int32_t)a_uInputDataLen, &nError);
3538 if (U_FAILURE(nError)) {
3555 size_t SizeToStore(
const UChar *a_pInputData) {
3558 if (!m_pConverter) {
3559 nError = U_ZERO_ERROR;
3560 m_pConverter = ucnv_open(m_pEncoding, &nError);
3561 if (U_FAILURE(nError)) {
3566 nError = U_ZERO_ERROR;
3568 ucnv_fromUChars(m_pConverter, NULL, 0, a_pInputData, -1, &nError);
3569 if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3573 return (
size_t)nLen + 1;
3589 bool ConvertToStore(
const UChar *a_pInputData,
char *a_pOutputData,
3590 size_t a_uOutputDataSize) {
3593 if (!m_pConverter) {
3594 nError = U_ZERO_ERROR;
3595 m_pConverter = ucnv_open(m_pEncoding, &nError);
3596 if (U_FAILURE(nError)) {
3601 nError = U_ZERO_ERROR;
3602 ucnv_fromUChars(m_pConverter, a_pOutputData, (int32_t)a_uOutputDataSize,
3603 a_pInputData, -1, &nError);
3604 if (U_FAILURE(nError)) {
3617#ifdef SI_CONVERT_WIN32
3619#define SI_Case SI_GenericCase
3630#define SI_NoCase SI_GenericNoCase
3640#include <mbstring.h>
3641template <
class SI_CHAR>
struct SI_NoCase {
3642 bool operator()(
const SI_CHAR *pLeft,
const SI_CHAR *pRight)
const {
3643 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
3644 return _mbsicmp((
const unsigned char *)pLeft,
3645 (
const unsigned char *)pRight) < 0;
3647 if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
3648 return _wcsicmp((
const wchar_t *)pLeft, (
const wchar_t *)pRight) < 0;
3764#ifdef SI_NO_CONVERSION
3766#define SI_Case SI_GenericCase
3767#define SI_NoCase SI_GenericNoCase
3778#if defined(SI_NO_CONVERSION)
3781#define CSimpleIni CSimpleIniA
3782#define CSimpleIniCase CSimpleIniCaseA
3783#define SI_NEWLINE SI_NEWLINE_A
3785#if defined(SI_CONVERT_ICU)
3798#define CSimpleIni CSimpleIniW
3799#define CSimpleIniCase CSimpleIniCaseW
3800#define SI_NEWLINE SI_NEWLINE_W
3802#define CSimpleIni CSimpleIniA
3803#define CSimpleIniCase CSimpleIniCaseA
3804#define SI_NEWLINE SI_NEWLINE_A
Definition SimpleIni.h:448
Definition SimpleIni.h:405
Definition SimpleIni.h:393
Definition SimpleIni.h:418
Definition SimpleIni.h:331
bool DeleteValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, bool a_bRemoveEmpty=false)
Definition SimpleIni.h:2824
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Definition SimpleIni.h:2541
int GetSectionSize(const SI_CHAR *a_pSection) const
Definition SimpleIni.h:2486
void SetAllowKeyOnly(bool a_bAllowKeyOnly=true)
Definition SimpleIni.h:592
SI_Error LoadData(const std::string &a_strData)
Definition SimpleIni.h:652
bool UsingQuotes() const
Definition SimpleIni.h:582
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
Definition SimpleIni.h:383
std::list< Entry > TNamesDepend
Definition SimpleIni.h:388
bool IsUnicode() const
Definition SimpleIni.h:521
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:2428
bool IsMultiKey() const
Definition SimpleIni.h:546
Converter GetConverter() const
Definition SimpleIni.h:1115
bool IsEmpty() const
Definition SimpleIni.h:496
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
Definition SimpleIni.h:380
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Definition SimpleIni.h:2519
SI_Error Save(OutputWriter &a_oOutput, bool a_bAddSignature=false) const
Definition SimpleIni.h:2620
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:2236
bool GetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bDefault=false, bool *a_pHasMultiple=NULL) const
Definition SimpleIni.h:2390
long GetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nDefault=0, bool *a_pHasMultiple=NULL) const
Definition SimpleIni.h:2268
void GetAllSections(TNamesDepend &a_names) const
Definition SimpleIni.h:2531
void Reset()
Definition SimpleIni.h:1280
~CSimpleIniTempl()
Definition SimpleIni.h:1275
bool UsingSpaces() const
Definition SimpleIni.h:571
SI_Error Save(std::string &a_sBuffer, bool a_bAddSignature=false) const
Definition SimpleIni.h:774
bool KeyExists(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey) const
Definition SimpleIni.h:869
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:978
bool SectionExists(const SI_CHAR *a_pSection) const
Definition SimpleIni.h:864
bool Delete(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bRemoveEmpty=false)
Definition SimpleIni.h:2818
void SetMultiLine(bool a_bAllowMultiLine=true)
Definition SimpleIni.h:555
void SetQuotes(bool a_bParseQuotes=true)
Definition SimpleIni.h:577
void SetUnicode(bool a_bIsUtf8=true)
Definition SimpleIni.h:515
double GetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nDefault=0, bool *a_pHasMultiple=NULL) const
Definition SimpleIni.h:2333
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:2304
void SetMultiKey(bool a_bAllowMultiKey=true)
Definition SimpleIni.h:541
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Definition SimpleIni.h:2452
void SetSpaces(bool a_bSpaces=true)
Definition SimpleIni.h:568
SI_Error LoadFile(const char *a_pszFile)
Definition SimpleIni.h:1398
bool GetAllowKeyOnly() const
Definition SimpleIni.h:597
SI_Error SaveFile(const char *a_pszFile, bool a_bAddSignature=true) const
Definition SimpleIni.h:2568
CSimpleIniTempl(bool a_bIsUtf8=false, bool a_bMultiKey=false, bool a_bMultiLine=false)
Definition SimpleIni.h:1267
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:2361
bool IsMultiLine() const
Definition SimpleIni.h:560
Definition SimpleIni.h:2982
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Definition SimpleIni.h:3070
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Definition SimpleIni.h:3011
size_t SizeToStore(const SI_CHAR *a_pInputData)
Definition SimpleIni.h:3052
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Definition SimpleIni.h:3032
Definition SimpleIni.h:360
Definition SimpleIni.h:368
Definition SimpleIni.h:336
Definition SimpleIni.h:2944
Definition SimpleIni.h:2963