223#ifndef INCLUDED_SimpleIni_h
224#define INCLUDED_SimpleIni_h
226#if defined(_MSC_VER) && (_MSC_VER >= 1020)
241#pragma warning(disable : 4127 4503 4702 4786)
253#ifdef SI_SUPPORT_IOSTREAMS
261#define SI_ASSERT(x) assert(x)
268constexpr int SI_OK = 0;
269constexpr int SI_UPDATED = 1;
270constexpr int SI_INSERTED = 2;
273constexpr int SI_FAIL = -1;
274constexpr int SI_NOMEM = -2;
275constexpr int SI_FILE = -3;
279constexpr size_t SI_MAX_FILE_SIZE = 1024ULL * 1024ULL * 1024ULL;
281#define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
284#define SI_NEWLINE_A "\r\n"
285#define SI_NEWLINE_W L"\r\n"
287#define SI_NEWLINE_A "\n"
288#define SI_NEWLINE_W L"\n"
291#if defined(SI_CONVERT_ICU)
292#include <unicode/ustring.h>
296#define SI_HAS_WIDE_FILE
297#define SI_WCHAR_T wchar_t
298#elif defined(SI_CONVERT_ICU)
299#define SI_HAS_WIDE_FILE
300#define SI_WCHAR_T UChar
326template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
329 typedef SI_CHAR SI_CHAR_T;
333 const SI_CHAR *pItem;
334 const SI_CHAR *pComment;
337 Entry(
const SI_CHAR *a_pszItem = NULL,
int a_nOrder = 0)
338 : pItem(a_pszItem), pComment(NULL), nOrder(a_nOrder) {}
339 Entry(
const SI_CHAR *a_pszItem,
const SI_CHAR *a_pszComment,
int a_nOrder)
340 : pItem(a_pszItem), pComment(a_pszComment), nOrder(a_nOrder) {}
344 pComment = rhs.pComment;
349#if defined(_MSC_VER) && _MSC_VER <= 1200
351 bool operator<(
const Entry &rhs)
const {
return LoadOrder()(*
this, rhs); }
352 bool operator>(
const Entry &rhs)
const {
return LoadOrder()(rhs, *
this); }
357 bool operator()(
const Entry &lhs,
const Entry &rhs)
const {
358 const static SI_STRLESS isLess = SI_STRLESS();
359 return isLess(lhs.pItem, rhs.pItem);
365 bool operator()(
const Entry &lhs,
const Entry &rhs)
const {
366 if (lhs.nOrder != rhs.nOrder) {
367 return lhs.nOrder < rhs.nOrder;
375 typedef std::multimap<Entry, const SI_CHAR *, typename Entry::KeyOrder>
379 typedef std::map<Entry, TKeyVal, typename Entry::KeyOrder>
TSection;
393 virtual void Write(
const char *a_pBuf) = 0;
406 void Write(
const char *a_pBuf) { fputs(a_pBuf, m_file); }
415 std::string &m_string;
418 StringWriter(std::string &a_string) : m_string(a_string) {}
419 void Write(
const char *a_pBuf) { m_string.append(a_pBuf); }
426#ifdef SI_SUPPORT_IOSTREAMS
429 std::ostream &m_ostream;
432 StreamWriter(std::ostream &a_ostream) : m_ostream(a_ostream) {}
433 void Write(
const char *a_pBuf) { m_ostream << a_pBuf; }
436 StreamWriter(
const StreamWriter &);
437 StreamWriter &operator=(
const StreamWriter &);
446 Converter(
bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
447 m_scratch.resize(1024);
451 m_scratch = rhs.m_scratch;
454 bool ConvertToStore(
const SI_CHAR *a_pszString) {
455 size_t uLen = SI_CONVERTER::SizeToStore(a_pszString);
456 if (uLen == (
size_t)(-1)) {
459 while (uLen > m_scratch.size()) {
460 m_scratch.resize(m_scratch.size() * 2);
462 return SI_CONVERTER::ConvertToStore(
463 a_pszString,
const_cast<char *
>(m_scratch.data()), m_scratch.size());
465 const char *Data() {
return m_scratch.data(); }
468 std::string m_scratch;
481 bool a_bMultiLine =
false);
490 bool IsEmpty()
const {
return m_data.empty(); }
511 m_bStoreIsUtf8 = a_bIsUtf8;
536 m_bAllowMultiKey = a_bAllowMultiKey;
550 m_bAllowMultiLine = a_bAllowMultiLine;
562 void SetSpaces(
bool a_bSpaces =
true) { m_bSpaces = a_bSpaces; }
572 m_bParseQuotes = a_bParseQuotes;
587 m_bAllowKeyOnly = a_bAllowKeyOnly;
605 SI_Error
LoadFile(
const char *a_pszFile);
607#ifdef SI_HAS_WIDE_FILE
614 SI_Error
LoadFile(
const SI_WCHAR_T *a_pwszFile);
626#ifdef SI_SUPPORT_IOSTREAMS
637 SI_Error
LoadData(std::istream &a_istream);
647 return LoadData(a_strData.c_str(), a_strData.size());
657 SI_Error
LoadData(
const char *a_pData,
size_t a_uDataLen);
675 SI_Error
SaveFile(
const char *a_pszFile,
bool a_bAddSignature =
true)
const;
677#ifdef SI_HAS_WIDE_FILE
688 SI_Error
SaveFile(
const SI_WCHAR_T *a_pwszFile,
689 bool a_bAddSignature =
true)
const;
704 SI_Error
SaveFile(FILE *a_pFile,
bool a_bAddSignature =
false)
const;
737 SI_Error
Save(OutputWriter &a_oOutput,
bool a_bAddSignature =
false)
const;
739#ifdef SI_SUPPORT_IOSTREAMS
751 SI_Error
Save(std::ostream &a_ostream,
bool a_bAddSignature =
false)
const {
752 StreamWriter writer(a_ostream);
753 return Save(writer, a_bAddSignature);
768 SI_Error
Save(std::string &a_sBuffer,
bool a_bAddSignature =
false)
const {
770 return Save(writer, a_bAddSignature);
828 bool GetAllValues(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
864 const SI_CHAR *a_pKey)
const {
865 return GetValue(a_pSection, a_pKey) != NULL;
885 const SI_CHAR *
GetValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
886 const SI_CHAR *a_pDefault = NULL,
887 bool *a_pHasMultiple = NULL)
const;
902 long GetLongValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
903 long a_nDefault = 0,
bool *a_pHasMultiple = NULL)
const;
918 double GetDoubleValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
919 double a_nDefault = 0,
920 bool *a_pHasMultiple = NULL)
const;
940 bool GetBoolValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
941 bool a_bDefault =
false,
bool *a_pHasMultiple = NULL)
const;
972 SI_Error
SetValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
973 const SI_CHAR *a_pValue,
const SI_CHAR *a_pComment = NULL,
974 bool a_bForceReplace =
false) {
975 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace,
1002 SI_Error
SetLongValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1003 long a_nValue,
const SI_CHAR *a_pComment = NULL,
1004 bool a_bUseHex =
false,
bool a_bForceReplace =
false);
1026 SI_Error
SetDoubleValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1027 double a_nValue,
const SI_CHAR *a_pComment = NULL,
1028 bool a_bForceReplace =
false);
1050 SI_Error
SetBoolValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1051 bool a_bValue,
const SI_CHAR *a_pComment = NULL,
1052 bool a_bForceReplace =
false);
1072 bool Delete(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1073 bool a_bRemoveEmpty =
false);
1095 bool DeleteValue(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1096 const SI_CHAR *a_pValue,
bool a_bRemoveEmpty =
false);
1119 SI_Error FindFileComment(SI_CHAR *&a_pData,
bool a_bCopyStrings);
1125 bool FindEntry(SI_CHAR *&a_pData,
const SI_CHAR *&a_pSection,
1126 const SI_CHAR *&a_pKey,
const SI_CHAR *&a_pVal,
1127 const SI_CHAR *&a_pComment)
const;
1151 SI_Error AddEntry(
const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
1152 const SI_CHAR *a_pValue,
const SI_CHAR *a_pComment,
1153 bool a_bForceReplace,
bool a_bCopyStrings);
1156 inline bool IsSpace(SI_CHAR ch)
const {
1157 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
1161 inline bool IsComment(SI_CHAR ch)
const {
return (ch ==
';' || ch ==
'#'); }
1164 inline void SkipNewLine(SI_CHAR *&a_pData)
const {
1165 a_pData += (*a_pData ==
'\r' && *(a_pData + 1) ==
'\n') ? 2 : 1;
1169 SI_Error CopyString(
const SI_CHAR *&a_pString);
1172 void UndoIncrementalLoadData(
const TNamesDepend &a_oAddedSections,
1176 void DeleteString(
const SI_CHAR *a_pString);
1179 bool IsLess(
const SI_CHAR *a_pLeft,
const SI_CHAR *a_pRight)
const {
1180 const static SI_STRLESS isLess = SI_STRLESS();
1181 return isLess(a_pLeft, a_pRight);
1184 bool IsMultiLineTag(
const SI_CHAR *a_pData)
const;
1185 bool IsMultiLineData(
const SI_CHAR *a_pData)
const;
1186 bool IsSingleLineQuotedValue(
const SI_CHAR *a_pData)
const;
1187 bool LoadMultiLineText(SI_CHAR *&a_pData,
const SI_CHAR *&a_pVal,
1188 const SI_CHAR *a_pTagName,
1189 bool a_bAllowBlankLinesInComment =
false)
const;
1190 bool IsNewLineChar(SI_CHAR a_c)
const;
1192 bool OutputMultiLineText(OutputWriter &a_oOutput, Converter &a_oConverter,
1193 const SI_CHAR *a_pText)
const;
1210 const SI_CHAR *m_pFileComment;
1213 const SI_CHAR m_cEmptyString;
1225 bool m_bStoreIsUtf8;
1228 bool m_bAllowMultiKey;
1231 bool m_bAllowMultiLine;
1237 bool m_bParseQuotes;
1240 bool m_bAllowKeyOnly;
1252template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1254 bool a_bIsUtf8,
bool a_bAllowMultiKey,
bool a_bAllowMultiLine)
1255 : m_pData(0), m_uDataLen(0), m_pFileComment(NULL), m_cEmptyString(0),
1256 m_bStoreIsUtf8(a_bIsUtf8), m_bAllowMultiKey(a_bAllowMultiKey),
1257 m_bAllowMultiLine(a_bAllowMultiLine), m_bSpaces(true),
1258 m_bParseQuotes(false), m_bAllowKeyOnly(false), m_nOrder(0) {}
1260template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1265template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1271 m_pFileComment = NULL;
1273 if (!m_data.empty()) {
1274 m_data.erase(m_data.begin(), m_data.end());
1278 if (!m_strings.empty()) {
1279 typename TNamesDepend::iterator i = m_strings.begin();
1280 for (; i != m_strings.end(); ++i) {
1281 delete[]
const_cast<SI_CHAR *
>(i->pItem);
1283 m_strings.erase(m_strings.begin(), m_strings.end());
1287namespace SI_Internal {
1288#ifdef SI_CONVERT_ICU
1290inline SI_Error UCharPathToUtf8(
const UChar *a_pPath,
char *&a_pUtf8Path) {
1292 UErrorCode status = U_ZERO_ERROR;
1294 u_strToUTF8(NULL, 0, &uLen, a_pPath, -1, &status);
1295 if (U_FAILURE(status) && status != U_BUFFER_OVERFLOW_ERROR) {
1301 char *pBuf =
new (std::nothrow)
char[
static_cast<size_t>(uLen) + 1];
1305 status = U_ZERO_ERROR;
1306 u_strToUTF8(pBuf, uLen + 1, NULL, a_pPath, -1, &status);
1307 if (U_FAILURE(status)) {
1317inline bool GetFileSize(FILE *a_fpFile,
size_t &a_uSize) {
1320#if defined(_WIN32) && !defined(_WIN32_WCE)
1321 if (_fseeki64(a_fpFile, 0, SEEK_END) != 0) {
1324 const __int64 nSize = _ftelli64(a_fpFile);
1328 if (
static_cast<unsigned long long>(nSize) >
1329 static_cast<unsigned long long>(SI_MAX_FILE_SIZE)) {
1332 if (
static_cast<unsigned long long>(nSize) >
1333 static_cast<unsigned long long>(std::numeric_limits<size_t>::max())) {
1336 a_uSize =
static_cast<size_t>(nSize);
1337 if (_fseeki64(a_fpFile, 0, SEEK_SET) != 0) {
1341#elif defined(_POSIX_VERSION) || defined(__unix__) || defined(__APPLE__)
1342 if (fseeko(a_fpFile, 0, SEEK_END) != 0) {
1345 const off_t nSize = ftello(a_fpFile);
1349 if (
static_cast<unsigned long long>(nSize) >
1350 static_cast<unsigned long long>(SI_MAX_FILE_SIZE)) {
1353 if (
static_cast<unsigned long long>(nSize) >
1354 static_cast<unsigned long long>(std::numeric_limits<size_t>::max())) {
1357 a_uSize =
static_cast<size_t>(nSize);
1358 if (fseeko(a_fpFile, 0, SEEK_SET) != 0) {
1363 if (fseek(a_fpFile, 0, SEEK_END) != 0) {
1366 const long nSize = ftell(a_fpFile);
1370 if (
static_cast<unsigned long long>(nSize) >
1371 static_cast<unsigned long long>(SI_MAX_FILE_SIZE)) {
1374 a_uSize =
static_cast<size_t>(nSize);
1375 if (fseek(a_fpFile, 0, SEEK_SET) != 0) {
1383template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1385 const char *a_pszFile) {
1387#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1388 fopen_s(&fp, a_pszFile,
"rb");
1390 fp = fopen(a_pszFile,
"rb");
1395 SI_Error rc = LoadFile(fp);
1400#ifdef SI_HAS_WIDE_FILE
1401template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1403 const SI_WCHAR_T *a_pwszFile) {
1406#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1407 _wfopen_s(&fp, a_pwszFile, L
"rb");
1409 fp = _wfopen(a_pwszFile, L
"rb");
1413 SI_Error rc = LoadFile(fp);
1417 char *szFile = NULL;
1418 SI_Error rcPath = SI_Internal::UCharPathToUtf8(a_pwszFile, szFile);
1422 SI_Error rc = LoadFile(szFile);
1429template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1433 if (!SI_Internal::GetFileSize(a_fpFile, uSize)) {
1441 char *pData =
new (std::nothrow)
char[uSize + 1];
1448 size_t uRead = fread(pData,
sizeof(
char), uSize, a_fpFile);
1449 if (uRead != uSize) {
1455 SI_Error rc = LoadData(pData, uRead);
1460template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1462 const char *a_pData,
size_t a_uDataLen) {
1470 if (a_uDataLen >= 3 && memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
1473 SI_ASSERT(m_bStoreIsUtf8 || !m_pData);
1477 if (a_uDataLen == 0) {
1482 SI_CONVERTER converter(m_bStoreIsUtf8);
1483 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
1484 if (uLen == (
size_t)(-1)) {
1489 if (uLen >= (SI_MAX_FILE_SIZE /
sizeof(SI_CHAR))) {
1495 SI_CHAR *pData =
new (std::nothrow) SI_CHAR[uLen + 1];
1499 memset(pData, 0,
sizeof(SI_CHAR) * (uLen + 1));
1502 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
1508 const static SI_CHAR empty = 0;
1509 SI_CHAR *pWork = pData;
1510 const SI_CHAR *pSection = ∅
1511 const SI_CHAR *pItem = NULL;
1512 const SI_CHAR *pVal = NULL;
1513 const SI_CHAR *pComment = NULL;
1517 bool bCopyStrings = (m_pData != NULL);
1519 size_t nStringsBefore = 0;
1520 const SI_CHAR *pFileCommentBefore = NULL;
1524 nStringsBefore = m_strings.size();
1525 pFileCommentBefore = m_pFileComment;
1530 SI_Error rc = FindFileComment(pWork, bCopyStrings);
1534 m_pFileComment = pFileCommentBefore;
1535 while (m_strings.size() > nStringsBefore) {
1536 delete[]
const_cast<SI_CHAR *
>(m_strings.back().pItem);
1537 m_strings.pop_back();
1540 m_pFileComment = NULL;
1546 while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
1547 bool bSectionExisted = SectionExists(pSection);
1548 bool bKeyExisted = pItem && bSectionExisted && KeyExists(pSection, pItem);
1550 rc = AddEntry(pSection, pItem, pVal, pComment,
false, bCopyStrings);
1553 m_pFileComment = pFileCommentBefore;
1554 UndoIncrementalLoadData(oAddedSections, oAddedKeys);
1555 while (m_strings.size() > nStringsBefore) {
1556 delete[]
const_cast<SI_CHAR *
>(m_strings.back().pItem);
1557 m_strings.pop_back();
1561 m_pFileComment = NULL;
1569 if (!bSectionExisted && *pSection) {
1570 oAddedSections.push_back(
Entry(pSection, NULL, 0));
1572 if (pItem && !bKeyExisted) {
1573 oAddedKeys.push_back(
Entry(pItem, pSection, 0));
1583 m_uDataLen = uLen + 1;
1589#ifdef SI_SUPPORT_IOSTREAMS
1590template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1592 std::istream &a_istream) {
1593 std::string strData;
1595 while (a_istream.read(buf,
sizeof(buf)) || a_istream.gcount() > 0) {
1596 const std::streamsize nRead = a_istream.gcount();
1597 for (std::streamsize i = 0; i < nRead; ++i) {
1598 if (buf[i] ==
'\0') {
1602 if (strData.size() +
static_cast<size_t>(nRead) > SI_MAX_FILE_SIZE) {
1605 strData.append(buf,
static_cast<size_t>(nRead));
1607 return LoadData(strData.data(), strData.size());
1611template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1613 SI_CHAR *&a_pData,
bool a_bCopyStrings) {
1615 if (m_pFileComment) {
1621 if (!LoadMultiLineText(a_pData, m_pFileComment, NULL,
false)) {
1626 if (a_bCopyStrings) {
1627 SI_Error rc = CopyString(m_pFileComment);
1635template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1637 SI_CHAR *&a_pData,
const SI_CHAR *&a_pSection,
const SI_CHAR *&a_pKey,
1638 const SI_CHAR *&a_pVal,
const SI_CHAR *&a_pComment)
const {
1641 bool bHaveValue =
false;
1642 SI_CHAR *pTrail = NULL;
1645 while (*a_pData && IsSpace(*a_pData)) {
1654 if (IsComment(*a_pData)) {
1655 LoadMultiLineText(a_pData, a_pComment, NULL,
true);
1660 if (*a_pData ==
'[') {
1663 while (*a_pData && IsSpace(*a_pData)) {
1669 a_pSection = a_pData;
1670 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData)) {
1675 if (*a_pData !=
']') {
1680 pTrail = a_pData - 1;
1681 while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1689 while (*a_pData && !IsNewLineChar(*a_pData)) {
1700 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData)) {
1706 bHaveValue = (*a_pData ==
'=');
1707 if (!bHaveValue && !m_bAllowKeyOnly) {
1712 if (bHaveValue && a_pKey == a_pData) {
1713 while (*a_pData && !IsNewLineChar(*a_pData)) {
1720 pTrail = a_pData - 1;
1721 while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1732 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1738 while (*a_pData && !IsNewLineChar(*a_pData)) {
1743 pTrail = a_pData - 1;
1745 SkipNewLine(a_pData);
1747 while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1754 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1756 const SI_CHAR *pTagName = a_pVal + 3;
1757 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1761 if (m_bParseQuotes) {
1763 if (pTrail > a_pVal && *a_pVal ==
'"' && *pTrail ==
'"') {
1771 SkipNewLine(a_pData);
1783template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1785 const SI_CHAR *a_pVal)
const {
1787 if (*a_pVal++ !=
'<')
1789 if (*a_pVal++ !=
'<')
1791 if (*a_pVal++ !=
'<')
1796template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1798 const SI_CHAR *a_pData)
const {
1810 if (IsSpace(*a_pData)) {
1815 const SI_CHAR *pStart = a_pData;
1817 if (IsNewLineChar(*a_pData)) {
1824 if (a_pData > pStart && IsSpace(*(a_pData - 1))) {
1831template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1843 if (IsSpace(*a_pData)) {
1848 const SI_CHAR *pStart = a_pData;
1850 if (IsNewLineChar(*a_pData)) {
1857 if (a_pData > pStart && IsSpace(*(a_pData - 1))) {
1864template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1866 SI_CHAR a_c)
const {
1867 return (a_c ==
'\n' || a_c ==
'\r');
1870template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1872 SI_CHAR *&a_pData,
const SI_CHAR *&a_pVal,
const SI_CHAR *a_pTagName,
1873 bool a_bAllowBlankLinesInComment)
const {
1882 SI_CHAR *pDataLine = a_pData;
1891 SI_CHAR cEndOfLineChar = *a_pData;
1895 if (!a_pTagName && !IsComment(*a_pData)) {
1897 if (!a_bAllowBlankLinesInComment) {
1904 SI_CHAR *pCurr = a_pData;
1906 while (IsSpace(*pCurr)) {
1907 if (IsNewLineChar(*pCurr)) {
1917 if (IsComment(*pCurr)) {
1918 for (; nNewLines > 0; --nNewLines)
1919 *pDataLine++ =
'\n';
1929 pCurrLine = a_pData;
1930 while (*a_pData && !IsNewLineChar(*a_pData))
1934 if (pDataLine < pCurrLine) {
1935 size_t nLen = (size_t)(a_pData - pCurrLine);
1936 memmove(pDataLine, pCurrLine, nLen *
sizeof(SI_CHAR));
1937 pDataLine[nLen] =
'\0';
1941 cEndOfLineChar = *a_pData;
1949 SI_CHAR *pc = a_pData - 1;
1950 while (pc > pDataLine && IsSpace(*pc))
1955 if (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)) {
1964 if (!cEndOfLineChar) {
1970 pDataLine += (a_pData - pCurrLine);
1971 *a_pData = cEndOfLineChar;
1972 SkipNewLine(a_pData);
1973 *pDataLine++ =
'\n';
1977 if (a_pVal == a_pData) {
1986 *--pDataLine =
'\0';
1990 if (a_pTagName && cEndOfLineChar) {
1991 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1992 *a_pData = cEndOfLineChar;
1993 SkipNewLine(a_pData);
1999template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2001 const SI_CHAR *&a_pString) {
2003 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
2004 uLen = strlen((
const char *)a_pString);
2005 }
else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
2006 uLen = wcslen((
const wchar_t *)a_pString);
2008 for (; a_pString[uLen]; ++uLen)
2011 if (uLen >= (SI_MAX_FILE_SIZE /
sizeof(SI_CHAR))) {
2015 SI_CHAR *pCopy =
new (std::nothrow) SI_CHAR[uLen];
2019 memcpy(pCopy, a_pString,
sizeof(SI_CHAR) * uLen);
2020 m_strings.push_back(pCopy);
2025template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2028 const TNamesDepend &a_oAddedKeys) {
2029 typename TNamesDepend::const_iterator iAddedKey = a_oAddedKeys.begin();
2030 for (; iAddedKey != a_oAddedKeys.end(); ++iAddedKey) {
2031 Delete(iAddedKey->pComment, iAddedKey->pItem,
false);
2034 typename TNamesDepend::const_iterator iAddedSection =
2035 a_oAddedSections.begin();
2036 for (; iAddedSection != a_oAddedSections.end(); ++iAddedSection) {
2037 Delete(iAddedSection->pItem, NULL,
false);
2041template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2043 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
const SI_CHAR *a_pValue,
2044 const SI_CHAR *a_pComment,
bool a_bForceReplace,
bool a_bCopyStrings) {
2046 bool bInserted =
false;
2048 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
2052 if (a_bCopyStrings && a_pComment) {
2053 rc = CopyString(a_pComment);
2059 typename TSection::iterator iSection = m_data.find(a_pSection);
2060 if (iSection == m_data.end()) {
2063 if (a_bCopyStrings) {
2064 rc = CopyString(a_pSection);
2070 Entry oSection(a_pSection, ++m_nOrder);
2071 if (a_pComment && !a_pKey) {
2072 oSection.pComment = a_pComment;
2075 typename TSection::value_type oEntry(oSection, TKeyVal());
2076 typedef typename TSection::iterator SectionIterator;
2077 std::pair<SectionIterator, bool> i = m_data.insert(oEntry);
2083 return bInserted ? SI_INSERTED : SI_UPDATED;
2087 TKeyVal &keyval = iSection->second;
2088 typename TKeyVal::iterator iKey = keyval.find(a_pKey);
2089 bInserted = iKey == keyval.end();
2093 int nLoadOrder = ++m_nOrder;
2094 if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
2095 const SI_CHAR *pComment = NULL;
2096 while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
2097 if (iKey->first.nOrder < nLoadOrder) {
2098 nLoadOrder = iKey->first.nOrder;
2099 pComment = iKey->first.pComment;
2104 DeleteString(a_pComment);
2105 a_pComment = pComment;
2106 rc = CopyString(a_pComment);
2110 Delete(a_pSection, a_pKey);
2111 iKey = keyval.end();
2116 a_pValue = &m_cEmptyString;
2120 bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
2121 if (a_bCopyStrings) {
2122 if (bForceCreateNewKey || iKey == keyval.end()) {
2126 rc = CopyString(a_pKey);
2132 rc = CopyString(a_pValue);
2138 if (iKey == keyval.end() || bForceCreateNewKey) {
2139 Entry oKey(a_pKey, nLoadOrder);
2141 oKey.pComment = a_pComment;
2143 typename TKeyVal::value_type oEntry(oKey,
2144 static_cast<const SI_CHAR *
>(NULL));
2145 iKey = keyval.insert(oEntry);
2147 DeleteString(iKey->second);
2150 iKey->second = a_pValue;
2151 return bInserted ? SI_INSERTED : SI_UPDATED;
2154template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2156 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
const SI_CHAR *a_pDefault,
2157 bool *a_pHasMultiple)
const {
2158 if (a_pHasMultiple) {
2159 *a_pHasMultiple =
false;
2161 if (!a_pSection || !a_pKey) {
2164 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2165 if (iSection == m_data.end()) {
2168 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2169 if (iKeyVal == iSection->second.end()) {
2174 if (m_bAllowMultiKey && a_pHasMultiple) {
2175 typename TKeyVal::const_iterator iTemp = iKeyVal;
2176 if (++iTemp != iSection->second.end()) {
2177 if (!IsLess(a_pKey, iTemp->first.pItem)) {
2178 *a_pHasMultiple =
true;
2183 return iKeyVal->second;
2186template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2188 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
long a_nDefault,
2189 bool *a_pHasMultiple)
const {
2191 const SI_CHAR *pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2192 if (!pszValue || !*pszValue)
2196 char szValue[64] = {0};
2197 SI_CONVERTER c(m_bStoreIsUtf8);
2198 if (!c.ConvertToStore(pszValue, szValue,
sizeof(szValue))) {
2203 long nValue = a_nDefault;
2204 char *pszSuffix = szValue;
2205 if (szValue[0] ==
'0' && (szValue[1] ==
'x' || szValue[1] ==
'X')) {
2208 nValue = strtol(&szValue[2], &pszSuffix, 16);
2210 nValue = strtol(szValue, &pszSuffix, 10);
2221template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2223 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
long a_nValue,
2224 const SI_CHAR *a_pComment,
bool a_bUseHex,
bool a_bForceReplace) {
2226 if (!a_pSection || !a_pKey)
2231#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2232 sprintf_s(szInput, a_bUseHex ?
"0x%lx" :
"%ld", a_nValue);
2234 snprintf(szInput,
sizeof(szInput), a_bUseHex ?
"0x%lx" :
"%ld", a_nValue);
2238 SI_CHAR szOutput[64];
2239 SI_CONVERTER c(m_bStoreIsUtf8);
2240 if (!c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput,
2241 sizeof(szOutput) /
sizeof(SI_CHAR))) {
2246 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
2250template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2252 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
double a_nDefault,
2253 bool *a_pHasMultiple)
const {
2255 const SI_CHAR *pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2256 if (!pszValue || !*pszValue)
2260 char szValue[64] = {0};
2261 SI_CONVERTER c(m_bStoreIsUtf8);
2262 if (!c.ConvertToStore(pszValue, szValue,
sizeof(szValue))) {
2266 char *pszSuffix = szValue;
2267 double nValue = strtod(szValue, &pszSuffix);
2271 if (pszSuffix == szValue || *pszSuffix) {
2278template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2280 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
double a_nValue,
2281 const SI_CHAR *a_pComment,
bool a_bForceReplace) {
2283 if (!a_pSection || !a_pKey)
2288#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2289 sprintf_s(szInput,
"%f", a_nValue);
2291 snprintf(szInput,
sizeof(szInput),
"%f", a_nValue);
2295 SI_CHAR szOutput[64];
2296 SI_CONVERTER c(m_bStoreIsUtf8);
2297 if (!c.ConvertFromStore(szInput, strlen(szInput) + 1, szOutput,
2298 sizeof(szOutput) /
sizeof(SI_CHAR))) {
2303 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
2307template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2309 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
bool a_bDefault,
2310 bool *a_pHasMultiple)
const {
2312 const SI_CHAR *pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2313 if (!pszValue || !*pszValue)
2317 switch (pszValue[0]) {
2334 if (pszValue[1] ==
'n' || pszValue[1] ==
'N')
2336 if (pszValue[1] ==
'f' || pszValue[1] ==
'F')
2345template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2347 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
bool a_bValue,
2348 const SI_CHAR *a_pComment,
bool a_bForceReplace) {
2350 if (!a_pSection || !a_pKey)
2354 const char *pszInput = a_bValue ?
"true" :
"false";
2357 SI_CHAR szOutput[64];
2358 SI_CONVERTER c(m_bStoreIsUtf8);
2359 if (!c.ConvertFromStore(pszInput, strlen(pszInput) + 1, szOutput,
2360 sizeof(szOutput) /
sizeof(SI_CHAR))) {
2365 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
2369template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2371 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
2375 if (!a_pSection || !a_pKey) {
2378 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2379 if (iSection == m_data.end()) {
2382 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2383 if (iKeyVal == iSection->second.end()) {
2389 Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2390 if (m_bAllowMultiKey) {
2392 while (iKeyVal != iSection->second.end() &&
2393 !IsLess(a_pKey, iKeyVal->first.pItem)) {
2394 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.pComment,
2395 iKeyVal->first.nOrder));
2403template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2405 const SI_CHAR *a_pSection)
const {
2410 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2411 if (iSection == m_data.end()) {
2414 const TKeyVal §ion = iSection->second;
2418 if (!m_bAllowMultiKey || section.empty()) {
2419 return (
int)section.size();
2424 const SI_CHAR *pLastKey = NULL;
2425 typename TKeyVal::const_iterator iKeyVal = section.begin();
2426 for (; iKeyVal != section.end(); ++iKeyVal) {
2427 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2429 pLastKey = iKeyVal->first.pItem;
2435template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2438 const SI_CHAR *a_pSection)
const {
2440 typename TSection::const_iterator i = m_data.find(a_pSection);
2441 if (i != m_data.end()) {
2442 return &(i->second);
2448template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2452 typename TSection::const_iterator i = m_data.begin();
2453 for (; i != m_data.end(); ++i) {
2454 a_names.push_back(i->first);
2458template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2460 const SI_CHAR *a_pSection,
TNamesDepend &a_names)
const {
2467 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2468 if (iSection == m_data.end()) {
2472 const TKeyVal §ion = iSection->second;
2473 const SI_CHAR *pLastKey = NULL;
2474 typename TKeyVal::const_iterator iKeyVal = section.begin();
2475 for (; iKeyVal != section.end(); ++iKeyVal) {
2476 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2477 a_names.push_back(iKeyVal->first);
2478 pLastKey = iKeyVal->first.pItem;
2485template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2487 const char *a_pszFile,
bool a_bAddSignature)
const {
2489#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2490 fopen_s(&fp, a_pszFile,
"wb");
2492 fp = fopen(a_pszFile,
"wb");
2496 SI_Error rc = SaveFile(fp, a_bAddSignature);
2501#ifdef SI_HAS_WIDE_FILE
2502template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2504 const SI_WCHAR_T *a_pwszFile,
bool a_bAddSignature)
const {
2507#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2508 _wfopen_s(&fp, a_pwszFile, L
"wb");
2510 fp = _wfopen(a_pwszFile, L
"wb");
2514 SI_Error rc = SaveFile(fp, a_bAddSignature);
2518 char *szFile = NULL;
2519 SI_Error rcPath = SI_Internal::UCharPathToUtf8(a_pwszFile, szFile);
2523 SI_Error rc = SaveFile(szFile, a_bAddSignature);
2530template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2532 FILE *a_pFile,
bool a_bAddSignature)
const {
2534 return Save(writer, a_bAddSignature);
2537template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2543 if (m_bStoreIsUtf8 && a_bAddSignature) {
2544 a_oOutput.Write(SI_UTF8_SIGNATURE);
2549 GetAllSections(oSections);
2550#if defined(_MSC_VER) && _MSC_VER <= 1200
2552#elif defined(__BORLANDC__)
2560 typename TNamesDepend::iterator is = oSections.begin();
2561 for (; is != oSections.end(); ++is) {
2564 if (is != oSections.begin()) {
2565 oSections.splice(oSections.begin(), oSections, is, std::next(is));
2572 bool bNeedNewLine =
false;
2573 if (m_pFileComment) {
2574 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
2577 bNeedNewLine =
true;
2581 typename TNamesDepend::const_iterator iSection = oSections.begin();
2582 for (; iSection != oSections.end(); ++iSection) {
2584 if (iSection->pComment) {
2586 a_oOutput.Write(SI_NEWLINE_A);
2587 a_oOutput.Write(SI_NEWLINE_A);
2589 if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
2592 bNeedNewLine =
false;
2596 a_oOutput.Write(SI_NEWLINE_A);
2597 a_oOutput.Write(SI_NEWLINE_A);
2598 bNeedNewLine =
false;
2602 if (*iSection->pItem) {
2603 if (!convert.ConvertToStore(iSection->pItem)) {
2606 a_oOutput.Write(
"[");
2607 a_oOutput.Write(convert.Data());
2608 a_oOutput.Write(
"]");
2609 a_oOutput.Write(SI_NEWLINE_A);
2614 GetAllKeys(iSection->pItem, oKeys);
2615#if defined(_MSC_VER) && _MSC_VER <= 1200
2617#elif defined(__BORLANDC__)
2624 typename TNamesDepend::const_iterator iKey = oKeys.begin();
2625 for (; iKey != oKeys.end(); ++iKey) {
2628 GetAllValues(iSection->pItem, iKey->pItem, oValues);
2630 typename TNamesDepend::const_iterator iValue = oValues.begin();
2631 for (; iValue != oValues.end(); ++iValue) {
2633 if (iValue->pComment) {
2634 a_oOutput.Write(SI_NEWLINE_A);
2635 if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
2641 if (!convert.ConvertToStore(iKey->pItem)) {
2644 a_oOutput.Write(convert.Data());
2647 if (*iValue->pItem || !m_bAllowKeyOnly) {
2648 if (!convert.ConvertToStore(iValue->pItem)) {
2651 a_oOutput.Write(m_bSpaces ?
" = " :
"=");
2652 if (m_bParseQuotes && IsSingleLineQuotedValue(iValue->pItem)) {
2655 a_oOutput.Write(
"\"");
2656 a_oOutput.Write(convert.Data());
2657 a_oOutput.Write(
"\"");
2658 }
else if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
2661 a_oOutput.Write(
"<<<END_OF_TEXT" SI_NEWLINE_A);
2662 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
2665 a_oOutput.Write(
"END_OF_TEXT");
2667 a_oOutput.Write(convert.Data());
2670 a_oOutput.Write(SI_NEWLINE_A);
2674 bNeedNewLine =
true;
2680template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2682 OutputWriter &a_oOutput, Converter &a_oConverter,
2683 const SI_CHAR *a_pText)
const {
2684 const SI_CHAR *pEndOfLine;
2685 SI_CHAR cEndOfLineChar = *a_pText;
2686 while (cEndOfLineChar) {
2688 pEndOfLine = a_pText;
2689 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine)
2691 cEndOfLineChar = *pEndOfLine;
2693 const std::basic_string<SI_CHAR> line(
2694 a_pText,
static_cast<size_t>(pEndOfLine - a_pText));
2695 if (!a_oConverter.ConvertToStore(line.c_str())) {
2698 a_pText += (pEndOfLine - a_pText) + 1;
2699 a_oOutput.Write(a_oConverter.Data());
2700 a_oOutput.Write(SI_NEWLINE_A);
2705template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2707 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
bool a_bRemoveEmpty) {
2708 return DeleteValue(a_pSection, a_pKey, NULL, a_bRemoveEmpty);
2711template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2713 const SI_CHAR *a_pSection,
const SI_CHAR *a_pKey,
const SI_CHAR *a_pValue,
2714 bool a_bRemoveEmpty) {
2719 typename TSection::iterator iSection = m_data.find(a_pSection);
2720 if (iSection == m_data.end()) {
2726 typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
2727 if (iKeyVal == iSection->second.end()) {
2731 const static SI_STRLESS isLess = SI_STRLESS();
2734 typename TKeyVal::iterator iDelete;
2735 bool bDeleted =
false;
2737 iDelete = iKeyVal++;
2739 if (a_pValue == NULL || (isLess(a_pValue, iDelete->second) ==
false &&
2740 isLess(iDelete->second, a_pValue) ==
false)) {
2741 DeleteString(iDelete->first.pItem);
2742 DeleteString(iDelete->first.pComment);
2743 DeleteString(iDelete->second);
2744 iSection->second.erase(iDelete);
2747 }
while (iKeyVal != iSection->second.end() &&
2748 !IsLess(a_pKey, iKeyVal->first.pItem));
2757 if (!a_bRemoveEmpty || !iSection->second.empty()) {
2763 typename TKeyVal::iterator iKeyVal = iSection->second.begin();
2764 for (; iKeyVal != iSection->second.end(); ++iKeyVal) {
2765 DeleteString(iKeyVal->first.pItem);
2766 DeleteString(iKeyVal->first.pComment);
2767 DeleteString(iKeyVal->second);
2772 DeleteString(iSection->first.pItem);
2773 DeleteString(iSection->first.pComment);
2774 m_data.erase(iSection);
2779template <
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2781 const SI_CHAR *a_pString) {
2788 if (!m_pData || a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
2789 typename TNamesDepend::iterator i = m_strings.begin();
2790 for (; i != m_strings.end(); ++i) {
2791 if (a_pString == i->pItem) {
2792 delete[]
const_cast<SI_CHAR *
>(i->pItem);
2818#if !defined(SI_NO_CONVERSION) && !defined(SI_CONVERT_GENERIC) && \
2819 !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2821#define SI_CONVERT_WIN32
2823#define SI_NO_CONVERSION
2833 bool operator()(
const SI_CHAR *pLeft,
const SI_CHAR *pRight)
const {
2835 for (; *pLeft && *pRight; ++pLeft, ++pRight) {
2836 cmp = (long)*pLeft - (
long)*pRight;
2841 return *pRight != 0;
2852 inline SI_CHAR locase(SI_CHAR ch)
const {
2853 return (ch <
'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
2855 bool operator()(
const SI_CHAR *pLeft,
const SI_CHAR *pRight)
const {
2857 for (; *pLeft && *pRight; ++pLeft, ++pRight) {
2858 cmp = (long)locase(*pLeft) - (long)locase(*pRight);
2863 return *pRight != 0;
2871 bool m_bStoreIsUtf8;
2877 SI_ConvertA(
bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) {}
2882 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
2901 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
2904 return a_uInputDataLen;
2921 SI_CHAR *a_pOutputData,
size_t a_uOutputDataSize) {
2923 if (a_uInputDataLen > a_uOutputDataSize) {
2926 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2942 return strlen((
const char *)a_pInputData) + 1;
2959 size_t a_uOutputDataSize) {
2961 size_t uInputLen = strlen((
const char *)a_pInputData) + 1;
2962 if (uInputLen > a_uOutputDataSize) {
2967 memcpy(a_pOutputData, a_pInputData, uInputLen);
2975#ifdef SI_CONVERT_GENERIC
2977#define SI_Case SI_GenericCase
2978#define SI_NoCase SI_GenericNoCase
2984constexpr char32_t REPLACEMENT = 0xFFFD;
2987inline bool Decode(
const char *&a_src,
const char *a_end,
char32_t &a_cp) {
2988 if (a_src >= a_end) {
2991 const unsigned char c0 = (
unsigned char)*a_src++;
3005 }
else if (c0 < 0xF0) {
3008 }
else if (c0 < 0xF5) {
3014 if (a_src + extra > a_end) {
3019 for (
int i = 0; i < extra; ++i) {
3020 const unsigned char cx = (
unsigned char)*a_src++;
3021 if ((cx & 0xC0) != 0x80) {
3025 ch = (ch << 6) | (cx & 0x3F);
3028 if ((extra == 1 && ch < 0x80) || (extra == 2 && ch < 0x800) ||
3029 (extra == 3 && ch < 0x10000) || ch > 0x10FFFF ||
3030 (ch >= 0xD800 && ch <= 0xDFFF)) {
3031 a_src -= (extra + 1);
3042inline int Encode(
char32_t a_cp,
char *a_dst,
size_t a_cap) {
3043 if (a_cp >= 0x110000 || (a_cp >= 0xD800 && a_cp <= 0xDFFF)) {
3050 a_dst[0] = (char)a_cp;
3056 a_dst[0] = (char)(0xC0 | (a_cp >> 6));
3057 a_dst[1] = (char)(0x80 | (a_cp & 0x3F));
3060 if (a_cp < 0x10000) {
3063 a_dst[0] = (char)(0xE0 | (a_cp >> 12));
3064 a_dst[1] = (char)(0x80 | ((a_cp >> 6) & 0x3F));
3065 a_dst[2] = (char)(0x80 | (a_cp & 0x3F));
3070 a_dst[0] = (char)(0xF0 | (a_cp >> 18));
3071 a_dst[1] = (char)(0x80 | ((a_cp >> 12) & 0x3F));
3072 a_dst[2] = (char)(0x80 | ((a_cp >> 6) & 0x3F));
3073 a_dst[3] = (char)(0x80 | (a_cp & 0x3F));
3077template <
class SI_CHAR>
3078inline bool AppendCodePoint(
char32_t a_cp, SI_CHAR *&a_dst, SI_CHAR *a_dstEnd) {
3079 if (
sizeof(SI_CHAR) >=
sizeof(
char32_t)) {
3080 if (a_dst >= a_dstEnd)
3082 *a_dst++ = (SI_CHAR)a_cp;
3085 if (
sizeof(SI_CHAR) == 2) {
3086 if (a_cp < 0x10000) {
3087 if (a_dst >= a_dstEnd)
3089 *a_dst++ = (SI_CHAR)a_cp;
3092 if (a_dst + 1 >= a_dstEnd)
3095 *a_dst++ = (SI_CHAR)(0xD800 + (a_cp >> 10));
3096 *a_dst++ = (SI_CHAR)(0xDC00 + (a_cp & 0x3FF));
3102template <
class SI_CHAR>
3103inline bool ReadCodePoint(
const SI_CHAR *&a_src,
char32_t &a_cp) {
3104 if (
sizeof(SI_CHAR) >=
sizeof(
char32_t)) {
3105 a_cp = (char32_t)*a_src++;
3108 if (
sizeof(SI_CHAR) == 2) {
3109 const char32_t w = (char32_t)*a_src++;
3110 if (w >= 0xD800 && w <= 0xDBFF) {
3111 if (*a_src >= 0xDC00 && *a_src <= 0xDFFF) {
3112 a_cp = 0x10000 + ((w - 0xD800) << 10) + ((char32_t)*a_src++ - 0xDC00);
3128template <
class SI_CHAR>
class SI_ConvertW {
3129 bool m_bStoreIsUtf8;
3135 SI_ConvertW(
bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) {}
3138 SI_ConvertW(
const SI_ConvertW &rhs) { operator=(rhs); }
3139 SI_ConvertW &operator=(
const SI_ConvertW &rhs) {
3140 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
3157 size_t SizeFromStore(
const char *a_pInputData,
size_t a_uInputDataLen) {
3158 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
3160 if (m_bStoreIsUtf8) {
3164 return a_uInputDataLen;
3168#if defined(_MSC_VER)
3170 errno_t e = mbstowcs_s(&uBufSiz, NULL, 0, a_pInputData, a_uInputDataLen);
3171 return (e == 0) ? uBufSiz : (size_t)-1;
3172#elif !defined(SI_NO_MBSTOWCS_NULL)
3173 return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
3178 return a_uInputDataLen;
3195 bool ConvertFromStore(
const char *a_pInputData,
size_t a_uInputDataLen,
3196 SI_CHAR *a_pOutputData,
size_t a_uOutputDataSize) {
3197 if (m_bStoreIsUtf8) {
3198 const char *src = a_pInputData;
3199 const char *srcEnd = a_pInputData + a_uInputDataLen;
3200 SI_CHAR *dst = a_pOutputData;
3201 SI_CHAR *dstEnd = a_pOutputData + a_uOutputDataSize;
3202 if (
sizeof(SI_CHAR) != 2 &&
sizeof(SI_CHAR) <
sizeof(
char32_t)) {
3205 while (src < srcEnd) {
3207 if (!SI_UTF8::Decode(src, srcEnd, cp)) {
3210 if (!SI_UTF8::AppendCodePoint(cp, dst, dstEnd)) {
3218#if defined(_MSC_VER)
3220 errno_t e = mbstowcs_s(&uBufSiz, a_pOutputData, a_uOutputDataSize,
3221 a_pInputData, a_uInputDataLen);
3225 size_t retval = mbstowcs(a_pOutputData, a_pInputData, a_uOutputDataSize);
3226 return retval != (size_t)(-1);
3240 size_t SizeToStore(
const SI_CHAR *a_pInputData) {
3241 if (m_bStoreIsUtf8) {
3244 while (a_pInputData[uLen]) {
3247 return (6 * uLen) + 1;
3249#if defined(_MSC_VER)
3251 errno_t e = wcstombs_s(&uLen, NULL, 0, a_pInputData, 0);
3257 size_t uLen = wcstombs(NULL, a_pInputData, 0);
3258 if (uLen == (
size_t)(-1)) {
3279 bool ConvertToStore(
const SI_CHAR *a_pInputData,
char *a_pOutputData,
3280 size_t a_uOutputDataSize) {
3281 if (m_bStoreIsUtf8) {
3282 const SI_CHAR *src = a_pInputData;
3283 char *dst = a_pOutputData;
3284 char *dstEnd = a_pOutputData + a_uOutputDataSize;
3285 if (
sizeof(SI_CHAR) != 2 &&
sizeof(SI_CHAR) <
sizeof(
char32_t)) {
3290 if (!SI_UTF8::ReadCodePoint(src, cp)) {
3294 const int n = SI_UTF8::Encode(cp, buf,
sizeof(buf));
3295 if (n < 0 || (
size_t)(dstEnd - dst) < (
size_t)n) {
3298 memcpy(dst, buf, (
size_t)n);
3301 if (dst >= dstEnd) {
3307#if defined(_MSC_VER)
3308 size_t converted = 0;
3309 errno_t e = wcstombs_s(&converted, a_pOutputData, a_uOutputDataSize,
3313 size_t retval = wcstombs(a_pOutputData, a_pInputData, a_uOutputDataSize);
3314 return retval != (size_t)-1;
3325#ifdef SI_CONVERT_ICU
3327#define SI_Case SI_GenericCase
3328#define SI_NoCase SI_GenericNoCase
3330#include <unicode/ucnv.h>
3335template <
class SI_CHAR>
class SI_ConvertW {
3336 const char *m_pEncoding;
3337 UConverter *m_pConverter;
3340 SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) {}
3343 SI_ConvertW(
bool a_bStoreIsUtf8) : m_pConverter(NULL) {
3344 m_pEncoding = a_bStoreIsUtf8 ?
"UTF-8" : NULL;
3348 SI_ConvertW(
const SI_ConvertW &rhs) { operator=(rhs); }
3349 SI_ConvertW &operator=(
const SI_ConvertW &rhs) {
3350 m_pEncoding = rhs.m_pEncoding;
3351 m_pConverter = NULL;
3356 ucnv_close(m_pConverter);
3372 size_t SizeFromStore(
const char *a_pInputData,
size_t a_uInputDataLen) {
3373 SI_ASSERT(a_uInputDataLen != (
size_t)-1);
3377 if (!m_pConverter) {
3378 nError = U_ZERO_ERROR;
3379 m_pConverter = ucnv_open(m_pEncoding, &nError);
3380 if (U_FAILURE(nError)) {
3385 nError = U_ZERO_ERROR;
3386 int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0, a_pInputData,
3387 (int32_t)a_uInputDataLen, &nError);
3388 if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3392 return (
size_t)nLen;
3408 bool ConvertFromStore(
const char *a_pInputData,
size_t a_uInputDataLen,
3409 UChar *a_pOutputData,
size_t a_uOutputDataSize) {
3412 if (!m_pConverter) {
3413 nError = U_ZERO_ERROR;
3414 m_pConverter = ucnv_open(m_pEncoding, &nError);
3415 if (U_FAILURE(nError)) {
3420 nError = U_ZERO_ERROR;
3421 ucnv_toUChars(m_pConverter, a_pOutputData, (int32_t)a_uOutputDataSize,
3422 a_pInputData, (int32_t)a_uInputDataLen, &nError);
3423 if (U_FAILURE(nError)) {
3440 size_t SizeToStore(
const UChar *a_pInputData) {
3443 if (!m_pConverter) {
3444 nError = U_ZERO_ERROR;
3445 m_pConverter = ucnv_open(m_pEncoding, &nError);
3446 if (U_FAILURE(nError)) {
3451 nError = U_ZERO_ERROR;
3453 ucnv_fromUChars(m_pConverter, NULL, 0, a_pInputData, -1, &nError);
3454 if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3458 return (
size_t)nLen + 1;
3474 bool ConvertToStore(
const UChar *a_pInputData,
char *a_pOutputData,
3475 size_t a_uOutputDataSize) {
3478 if (!m_pConverter) {
3479 nError = U_ZERO_ERROR;
3480 m_pConverter = ucnv_open(m_pEncoding, &nError);
3481 if (U_FAILURE(nError)) {
3486 nError = U_ZERO_ERROR;
3487 ucnv_fromUChars(m_pConverter, a_pOutputData, (int32_t)a_uOutputDataSize,
3488 a_pInputData, -1, &nError);
3489 if (U_FAILURE(nError)) {
3502#ifdef SI_CONVERT_WIN32
3504#define SI_Case SI_GenericCase
3515#define SI_NoCase SI_GenericNoCase
3525#include <mbstring.h>
3526template <
class SI_CHAR>
struct SI_NoCase {
3527 bool operator()(
const SI_CHAR *pLeft,
const SI_CHAR *pRight)
const {
3528 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
3529 return _mbsicmp((
const unsigned char *)pLeft,
3530 (
const unsigned char *)pRight) < 0;
3532 if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
3533 return _wcsicmp((
const wchar_t *)pLeft, (
const wchar_t *)pRight) < 0;
3649#ifdef SI_NO_CONVERSION
3651#define SI_Case SI_GenericCase
3652#define SI_NoCase SI_GenericNoCase
3663#if defined(SI_NO_CONVERSION)
3666#define CSimpleIni CSimpleIniA
3667#define CSimpleIniCase CSimpleIniCaseA
3668#define SI_NEWLINE SI_NEWLINE_A
3670#if defined(SI_CONVERT_ICU)
3683#define CSimpleIni CSimpleIniW
3684#define CSimpleIniCase CSimpleIniCaseW
3685#define SI_NEWLINE SI_NEWLINE_W
3687#define CSimpleIni CSimpleIniA
3688#define CSimpleIniCase CSimpleIniCaseA
3689#define SI_NEWLINE SI_NEWLINE_A
Definition SimpleIni.h:444
Definition SimpleIni.h:401
Definition SimpleIni.h:389
Definition SimpleIni.h:414
Definition SimpleIni.h:327
bool DeleteValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, const SI_CHAR *a_pValue, bool a_bRemoveEmpty=false)
Definition SimpleIni.h:2712
bool GetAllKeys(const SI_CHAR *a_pSection, TNamesDepend &a_names) const
Definition SimpleIni.h:2459
int GetSectionSize(const SI_CHAR *a_pSection) const
Definition SimpleIni.h:2404
void SetAllowKeyOnly(bool a_bAllowKeyOnly=true)
Definition SimpleIni.h:586
SI_Error LoadData(const std::string &a_strData)
Definition SimpleIni.h:646
bool UsingQuotes() const
Definition SimpleIni.h:576
std::map< Entry, TKeyVal, typename Entry::KeyOrder > TSection
Definition SimpleIni.h:379
std::list< Entry > TNamesDepend
Definition SimpleIni.h:384
bool IsUnicode() const
Definition SimpleIni.h:515
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:2346
bool IsMultiKey() const
Definition SimpleIni.h:540
Converter GetConverter() const
Definition SimpleIni.h:1107
bool IsEmpty() const
Definition SimpleIni.h:490
std::multimap< Entry, const SI_CHAR *, typename Entry::KeyOrder > TKeyVal
Definition SimpleIni.h:376
const TKeyVal * GetSection(const SI_CHAR *a_pSection) const
Definition SimpleIni.h:2437
SI_Error Save(OutputWriter &a_oOutput, bool a_bAddSignature=false) const
Definition SimpleIni.h:2538
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:2155
bool GetBoolValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bDefault=false, bool *a_pHasMultiple=NULL) const
Definition SimpleIni.h:2308
long GetLongValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, long a_nDefault=0, bool *a_pHasMultiple=NULL) const
Definition SimpleIni.h:2187
void GetAllSections(TNamesDepend &a_names) const
Definition SimpleIni.h:2449
void Reset()
Definition SimpleIni.h:1266
~CSimpleIniTempl()
Definition SimpleIni.h:1261
bool UsingSpaces() const
Definition SimpleIni.h:565
SI_Error Save(std::string &a_sBuffer, bool a_bAddSignature=false) const
Definition SimpleIni.h:768
bool KeyExists(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey) const
Definition SimpleIni.h:863
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:972
bool SectionExists(const SI_CHAR *a_pSection) const
Definition SimpleIni.h:858
bool Delete(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, bool a_bRemoveEmpty=false)
Definition SimpleIni.h:2706
void SetMultiLine(bool a_bAllowMultiLine=true)
Definition SimpleIni.h:549
void SetQuotes(bool a_bParseQuotes=true)
Definition SimpleIni.h:571
void SetUnicode(bool a_bIsUtf8=true)
Definition SimpleIni.h:509
double GetDoubleValue(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, double a_nDefault=0, bool *a_pHasMultiple=NULL) const
Definition SimpleIni.h:2251
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:2222
void SetMultiKey(bool a_bAllowMultiKey=true)
Definition SimpleIni.h:535
bool GetAllValues(const SI_CHAR *a_pSection, const SI_CHAR *a_pKey, TNamesDepend &a_values) const
Definition SimpleIni.h:2370
void SetSpaces(bool a_bSpaces=true)
Definition SimpleIni.h:562
SI_Error LoadFile(const char *a_pszFile)
Definition SimpleIni.h:1384
bool GetAllowKeyOnly() const
Definition SimpleIni.h:591
SI_Error SaveFile(const char *a_pszFile, bool a_bAddSignature=true) const
Definition SimpleIni.h:2486
CSimpleIniTempl(bool a_bIsUtf8=false, bool a_bMultiKey=false, bool a_bMultiLine=false)
Definition SimpleIni.h:1253
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:2279
bool IsMultiLine() const
Definition SimpleIni.h:554
Definition SimpleIni.h:2870
bool ConvertToStore(const SI_CHAR *a_pInputData, char *a_pOutputData, size_t a_uOutputDataSize)
Definition SimpleIni.h:2958
size_t SizeFromStore(const char *a_pInputData, size_t a_uInputDataLen)
Definition SimpleIni.h:2899
size_t SizeToStore(const SI_CHAR *a_pInputData)
Definition SimpleIni.h:2940
bool ConvertFromStore(const char *a_pInputData, size_t a_uInputDataLen, SI_CHAR *a_pOutputData, size_t a_uOutputDataSize)
Definition SimpleIni.h:2920
Definition SimpleIni.h:356
Definition SimpleIni.h:364
Definition SimpleIni.h:332
Definition SimpleIni.h:2832
Definition SimpleIni.h:2851