194 #ifndef INCLUDED_SimpleIni_h
195 #define INCLUDED_SimpleIni_h
197 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
211 # pragma warning (push)
212 # pragma warning (disable: 4127 4503 4702 4786)
222 #ifdef SI_SUPPORT_IOSTREAMS
224 #endif // SI_SUPPORT_IOSTREAMS
230 # define SI_ASSERT(x) assert(x)
232 # define SI_ASSERT(x)
246 #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
249 # define SI_NEWLINE_A "\r\n"
250 # define SI_NEWLINE_W L"\r\n"
252 # define SI_NEWLINE_A "\n"
253 # define SI_NEWLINE_W L"\n"
256 #if defined(SI_CONVERT_ICU)
257 # include <unicode/ustring.h>
261 # define SI_HAS_WIDE_FILE
262 # define SI_WCHAR_T wchar_t
263 #elif defined(SI_CONVERT_ICU)
264 # define SI_HAS_WIDE_FILE
265 # define SI_WCHAR_T UChar
292 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
304 Entry(
const SI_CHAR * a_pszItem = NULL,
int a_nOrder = 0)
309 Entry(
const SI_CHAR * a_pszItem,
const SI_CHAR * a_pszComment,
int a_nOrder)
322 #if defined(_MSC_VER) && _MSC_VER <= 1200
324 bool operator<(
const Entry & rhs)
const {
return LoadOrder()(*
this, rhs); }
325 bool operator>(
const Entry & rhs)
const {
return LoadOrder()(rhs, *
this); }
329 struct KeyOrder : std::binary_function<Entry, Entry, bool> {
331 const static SI_STRLESS isLess = SI_STRLESS();
337 struct LoadOrder : std::binary_function<Entry, Entry, bool> {
348 typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder>
TKeyVal;
351 typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder>
TSection;
365 virtual void Write(
const char * a_pBuf) = 0;
377 fputs(a_pBuf, m_file);
386 std::string & m_string;
390 m_string.append(a_pBuf);
397 #ifdef SI_SUPPORT_IOSTREAMS
400 std::ostream & m_ostream;
410 #endif // SI_SUPPORT_IOSTREAMS
417 using SI_CONVERTER::SizeToStore;
418 Converter(
bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
419 m_scratch.resize(1024);
423 m_scratch = rhs.m_scratch;
427 size_t uLen = SizeToStore(a_pszString);
428 if (uLen == (
size_t)(-1)) {
431 while (uLen > m_scratch.size()) {
432 m_scratch.resize(m_scratch.size() * 2);
434 return SI_CONVERTER::ConvertToStore(
436 const_cast<char*
>(m_scratch.data()),
439 const char *
Data() {
return m_scratch.data(); }
441 std::string m_scratch;
454 bool a_bIsUtf8 =
false,
455 bool a_bMultiKey =
false,
456 bool a_bMultiLine =
false
466 bool IsEmpty()
const {
return m_data.empty(); }
486 if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
511 m_bAllowMultiKey = a_bAllowMultiKey;
525 m_bAllowMultiLine = a_bAllowMultiLine;
538 m_bSpaces = a_bSpaces;
557 const char * a_pszFile
560 #ifdef SI_HAS_WIDE_FILE
568 const SI_WCHAR_T * a_pwszFile
570 #endif // SI_HAS_WIDE_FILE
583 #ifdef SI_SUPPORT_IOSTREAMS
591 std::istream & a_istream
593 #endif // SI_SUPPORT_IOSTREAMS
602 return LoadData(a_strData.c_str(), a_strData.size());
613 const char * a_pData,
634 const char * a_pszFile,
635 bool a_bAddSignature =
true
638 #ifdef SI_HAS_WIDE_FILE
650 const SI_WCHAR_T * a_pwszFile,
651 bool a_bAddSignature =
true
669 bool a_bAddSignature =
false
704 OutputWriter & a_oOutput,
705 bool a_bAddSignature =
false
708 #ifdef SI_SUPPORT_IOSTREAMS
721 std::ostream & a_ostream,
722 bool a_bAddSignature =
false
726 return Save(writer, a_bAddSignature);
728 #endif // SI_SUPPORT_IOSTREAMS
742 std::string & a_sBuffer,
743 bool a_bAddSignature =
false
747 return Save(writer, a_bAddSignature);
790 const SI_CHAR * a_pSection,
811 const SI_CHAR * a_pSection,
812 const SI_CHAR * a_pKey,
826 const SI_CHAR * a_pSection
844 const SI_CHAR * a_pSection
865 const SI_CHAR * a_pSection,
866 const SI_CHAR * a_pKey,
867 const SI_CHAR * a_pDefault = NULL,
868 bool * a_pHasMultiple = NULL
885 const SI_CHAR * a_pSection,
886 const SI_CHAR * a_pKey,
888 bool * a_pHasMultiple = NULL
905 const SI_CHAR * a_pSection,
906 const SI_CHAR * a_pKey,
907 double a_nDefault = 0,
908 bool * a_pHasMultiple = NULL
930 const SI_CHAR * a_pSection,
931 const SI_CHAR * a_pKey,
932 bool a_bDefault =
false,
933 bool * a_pHasMultiple = NULL
966 const SI_CHAR * a_pSection,
967 const SI_CHAR * a_pKey,
968 const SI_CHAR * a_pValue,
969 const SI_CHAR * a_pComment = NULL,
970 bool a_bForceReplace =
false
973 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace,
true);
1000 const SI_CHAR * a_pSection,
1001 const SI_CHAR * a_pKey,
1003 const SI_CHAR * a_pComment = NULL,
1004 bool a_bUseHex =
false,
1005 bool a_bForceReplace =
false
1029 const SI_CHAR * a_pSection,
1030 const SI_CHAR * a_pKey,
1032 const SI_CHAR * a_pComment = NULL,
1033 bool a_bForceReplace =
false
1057 const SI_CHAR * a_pSection,
1058 const SI_CHAR * a_pKey,
1060 const SI_CHAR * a_pComment = NULL,
1061 bool a_bForceReplace =
false
1083 const SI_CHAR * a_pSection,
1084 const SI_CHAR * a_pKey,
1085 bool a_bRemoveEmpty =
false
1122 const SI_CHAR *& a_pSection,
1123 const SI_CHAR *& a_pKey,
1124 const SI_CHAR *& a_pVal,
1125 const SI_CHAR *& a_pComment
1151 const SI_CHAR * a_pSection,
1152 const SI_CHAR * a_pKey,
1153 const SI_CHAR * a_pValue,
1154 const SI_CHAR * a_pComment,
1155 bool a_bForceReplace,
1160 inline bool IsSpace(SI_CHAR ch)
const {
1161 return (ch ==
' ' || ch ==
'\t' || ch ==
'\r' || ch ==
'\n');
1165 inline bool IsComment(SI_CHAR ch)
const {
1166 return (ch ==
';' || ch ==
'#');
1171 inline void SkipNewLine(SI_CHAR *& a_pData)
const {
1172 a_pData += (*a_pData ==
'\r' && *(a_pData+1) ==
'\n') ? 2 : 1;
1176 SI_Error CopyString(
const SI_CHAR *& a_pString);
1179 void DeleteString(
const SI_CHAR * a_pString);
1182 bool IsLess(
const SI_CHAR * a_pLeft,
const SI_CHAR * a_pRight)
const {
1183 const static SI_STRLESS isLess = SI_STRLESS();
1184 return isLess(a_pLeft, a_pRight);
1187 bool IsMultiLineTag(
const SI_CHAR * a_pData)
const;
1188 bool IsMultiLineData(
const SI_CHAR * a_pData)
const;
1189 bool LoadMultiLineText(
1191 const SI_CHAR *& a_pVal,
1192 const SI_CHAR * a_pTagName,
1193 bool a_bAllowBlankLinesInComment =
false
1195 bool IsNewLineChar(SI_CHAR a_c)
const;
1197 bool OutputMultiLineText(
1198 OutputWriter & a_oOutput,
1199 Converter & a_oConverter,
1200 const SI_CHAR * a_pText
1218 const SI_CHAR * m_pFileComment;
1230 bool m_bStoreIsUtf8;
1233 bool m_bAllowMultiKey;
1236 bool m_bAllowMultiLine;
1251 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1254 bool a_bAllowMultiKey,
1255 bool a_bAllowMultiLine
1259 , m_pFileComment(NULL)
1260 , m_bStoreIsUtf8(a_bIsUtf8)
1261 , m_bAllowMultiKey(a_bAllowMultiKey)
1262 , m_bAllowMultiLine(a_bAllowMultiLine)
1267 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1273 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1281 m_pFileComment = NULL;
1282 if (!m_data.empty()) {
1283 m_data.erase(m_data.begin(), m_data.end());
1287 if (!m_strings.empty()) {
1288 typename TNamesDepend::iterator i = m_strings.begin();
1289 for (; i != m_strings.end(); ++i) {
1290 delete[]
const_cast<SI_CHAR*
>(i->pItem);
1292 m_strings.erase(m_strings.begin(), m_strings.end());
1296 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1299 const char * a_pszFile
1303 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1304 fopen_s(&fp, a_pszFile,
"rb");
1305 #else // !__STDC_WANT_SECURE_LIB__
1306 fp = fopen(a_pszFile,
"rb");
1307 #endif // __STDC_WANT_SECURE_LIB__
1316 #ifdef SI_HAS_WIDE_FILE
1317 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1320 const SI_WCHAR_T * a_pwszFile
1325 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1326 _wfopen_s(&fp, a_pwszFile, L
"rb");
1327 #else // !__STDC_WANT_SECURE_LIB__
1328 fp = _wfopen(a_pwszFile, L
"rb");
1329 #endif // __STDC_WANT_SECURE_LIB__
1334 #else // !_WIN32 (therefore SI_CONVERT_ICU)
1336 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
1337 return LoadFile(szFile);
1340 #endif // SI_HAS_WIDE_FILE
1342 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1349 int retval = fseek(a_fpFile, 0, SEEK_END);
1353 long lSize = ftell(a_fpFile);
1362 char * pData =
new char[lSize+1];
1369 fseek(a_fpFile, 0, SEEK_SET);
1370 size_t uRead = fread(pData,
sizeof(
char), lSize, a_fpFile);
1371 if (uRead != (
size_t) lSize) {
1377 SI_Error rc = LoadData(pData, uRead);
1382 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1385 const char * a_pData,
1389 SI_CONVERTER converter(m_bStoreIsUtf8);
1391 if (a_uDataLen == 0) {
1396 if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
1404 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
1405 if (uLen == (
size_t)(-1)) {
1411 SI_CHAR * pData =
new SI_CHAR[uLen+1];
1415 memset(pData, 0,
sizeof(SI_CHAR)*(uLen+1));
1418 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
1424 const static SI_CHAR empty = 0;
1425 SI_CHAR * pWork = pData;
1426 const SI_CHAR * pSection = ∅
1427 const SI_CHAR * pItem = NULL;
1428 const SI_CHAR * pVal = NULL;
1429 const SI_CHAR * pComment = NULL;
1433 bool bCopyStrings = (m_pData != NULL);
1437 SI_Error rc = FindFileComment(pWork, bCopyStrings);
1438 if (rc < 0)
return rc;
1441 while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
1442 rc = AddEntry(pSection, pItem, pVal, pComment,
false, bCopyStrings);
1443 if (rc < 0)
return rc;
1452 m_uDataLen = uLen+1;
1458 #ifdef SI_SUPPORT_IOSTREAMS
1459 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1462 std::istream & a_istream
1465 std::string strData;
1468 a_istream.get(szBuf,
sizeof(szBuf),
'\0');
1469 strData.append(szBuf);
1471 while (a_istream.good());
1472 return LoadData(strData);
1474 #endif // SI_SUPPORT_IOSTREAMS
1476 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1484 if (m_pFileComment) {
1490 if (!LoadMultiLineText(a_pData, m_pFileComment, NULL,
false)) {
1495 if (a_bCopyStrings) {
1496 SI_Error rc = CopyString(m_pFileComment);
1497 if (rc < 0)
return rc;
1503 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1507 const SI_CHAR *& a_pSection,
1508 const SI_CHAR *& a_pKey,
1509 const SI_CHAR *& a_pVal,
1510 const SI_CHAR *& a_pComment
1515 SI_CHAR * pTrail = NULL;
1518 while (*a_pData && IsSpace(*a_pData)) {
1527 if (IsComment(*a_pData)) {
1528 LoadMultiLineText(a_pData, a_pComment, NULL,
true);
1533 if (*a_pData ==
'[') {
1536 while (*a_pData && IsSpace(*a_pData)) {
1542 a_pSection = a_pData;
1543 while (*a_pData && *a_pData !=
']' && !IsNewLineChar(*a_pData)) {
1548 if (*a_pData !=
']') {
1553 pTrail = a_pData - 1;
1554 while (pTrail >= a_pSection && IsSpace(*pTrail)) {
1562 while (*a_pData && !IsNewLineChar(*a_pData)) {
1574 while (*a_pData && *a_pData !=
'=' && !IsNewLineChar(*a_pData)) {
1579 if (*a_pData !=
'=') {
1584 if (a_pKey == a_pData) {
1585 while (*a_pData && !IsNewLineChar(*a_pData)) {
1592 pTrail = a_pData - 1;
1593 while (pTrail >= a_pKey && IsSpace(*pTrail)) {
1601 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
1607 while (*a_pData && !IsNewLineChar(*a_pData)) {
1612 pTrail = a_pData - 1;
1614 SkipNewLine(a_pData);
1616 while (pTrail >= a_pVal && IsSpace(*pTrail)) {
1623 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
1625 const SI_CHAR * pTagName = a_pVal + 3;
1626 return LoadMultiLineText(a_pData, a_pVal, pTagName);
1636 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1639 const SI_CHAR * a_pVal
1643 if (*a_pVal++ !=
'<')
return false;
1644 if (*a_pVal++ !=
'<')
return false;
1645 if (*a_pVal++ !=
'<')
return false;
1649 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1652 const SI_CHAR * a_pData
1666 if (IsSpace(*a_pData)) {
1672 if (IsNewLineChar(*a_pData)) {
1679 if (IsSpace(*--a_pData)) {
1686 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1692 return (a_c ==
'\n' || a_c ==
'\r');
1695 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1699 const SI_CHAR *& a_pVal,
1700 const SI_CHAR * a_pTagName,
1701 bool a_bAllowBlankLinesInComment
1712 SI_CHAR * pDataLine = a_pData;
1713 SI_CHAR * pCurrLine;
1721 SI_CHAR cEndOfLineChar = *a_pData;
1725 if (!a_pTagName && !IsComment(*a_pData)) {
1727 if (!a_bAllowBlankLinesInComment) {
1734 SI_CHAR * pCurr = a_pData;
1736 while (IsSpace(*pCurr)) {
1737 if (IsNewLineChar(*pCurr)) {
1748 if (IsComment(*pCurr)) {
1749 for (; nNewLines > 0; --nNewLines) *pDataLine++ =
'\n';
1759 pCurrLine = a_pData;
1760 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
1763 if (pDataLine < pCurrLine) {
1764 size_t nLen = (size_t) (a_pData - pCurrLine);
1765 memmove(pDataLine, pCurrLine, nLen *
sizeof(SI_CHAR));
1766 pDataLine[nLen] =
'\0';
1770 cEndOfLineChar = *a_pData;
1777 (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
1784 if (!cEndOfLineChar) {
1790 pDataLine += (a_pData - pCurrLine);
1791 *a_pData = cEndOfLineChar;
1792 SkipNewLine(a_pData);
1793 *pDataLine++ =
'\n';
1797 if (a_pVal == a_pData) {
1806 *--pDataLine =
'\0';
1810 if (a_pTagName && cEndOfLineChar) {
1811 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
1812 *a_pData = cEndOfLineChar;
1813 SkipNewLine(a_pData);
1819 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1822 const SI_CHAR *& a_pString
1826 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
1827 uLen = strlen((
const char *)a_pString);
1829 else if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
1830 uLen = wcslen((
const wchar_t *)a_pString);
1833 for ( ; a_pString[uLen]; ++uLen) ;
1836 SI_CHAR * pCopy =
new SI_CHAR[uLen];
1840 memcpy(pCopy, a_pString,
sizeof(SI_CHAR)*uLen);
1841 m_strings.push_back(pCopy);
1846 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1849 const SI_CHAR * a_pSection,
1850 const SI_CHAR * a_pKey,
1851 const SI_CHAR * a_pValue,
1852 const SI_CHAR * a_pComment,
1853 bool a_bForceReplace,
1858 bool bInserted =
false;
1860 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
1864 if (a_bCopyStrings && a_pComment) {
1865 rc = CopyString(a_pComment);
1866 if (rc < 0)
return rc;
1870 typename TSection::iterator iSection = m_data.find(a_pSection);
1871 if (iSection == m_data.end()) {
1874 if (a_bCopyStrings) {
1875 rc = CopyString(a_pSection);
1876 if (rc < 0)
return rc;
1880 Entry oSection(a_pSection, ++m_nOrder);
1881 if (a_pComment && (!a_pKey || !a_pValue)) {
1882 oSection.pComment = a_pComment;
1885 typename TSection::value_type oEntry(oSection, TKeyVal());
1886 typedef typename TSection::iterator SectionIterator;
1887 std::pair<SectionIterator,bool> i = m_data.insert(oEntry);
1891 if (!a_pKey || !a_pValue) {
1897 TKeyVal & keyval = iSection->second;
1898 typename TKeyVal::iterator iKey = keyval.find(a_pKey);
1902 int nLoadOrder = ++m_nOrder;
1903 if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
1904 const SI_CHAR * pComment = NULL;
1905 while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
1906 if (iKey->first.nOrder < nLoadOrder) {
1907 nLoadOrder = iKey->first.nOrder;
1908 pComment = iKey->first.pComment;
1913 DeleteString(a_pComment);
1914 a_pComment = pComment;
1915 CopyString(a_pComment);
1917 Delete(a_pSection, a_pKey);
1918 iKey = keyval.end();
1922 bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
1923 if (a_bCopyStrings) {
1924 if (bForceCreateNewKey || iKey == keyval.end()) {
1928 rc = CopyString(a_pKey);
1929 if (rc < 0)
return rc;
1933 rc = CopyString(a_pValue);
1934 if (rc < 0)
return rc;
1938 if (iKey == keyval.end() || bForceCreateNewKey) {
1939 Entry oKey(a_pKey, nLoadOrder);
1941 oKey.pComment = a_pComment;
1943 typename TKeyVal::value_type oEntry(oKey,
static_cast<const SI_CHAR *
>(NULL));
1944 iKey = keyval.insert(oEntry);
1947 iKey->second = a_pValue;
1951 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1954 const SI_CHAR * a_pSection,
1955 const SI_CHAR * a_pKey,
1956 const SI_CHAR * a_pDefault,
1957 bool * a_pHasMultiple
1960 if (a_pHasMultiple) {
1961 *a_pHasMultiple =
false;
1963 if (!a_pSection || !a_pKey) {
1966 typename TSection::const_iterator iSection = m_data.find(a_pSection);
1967 if (iSection == m_data.end()) {
1970 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
1971 if (iKeyVal == iSection->second.end()) {
1976 if (m_bAllowMultiKey && a_pHasMultiple) {
1977 typename TKeyVal::const_iterator iTemp = iKeyVal;
1978 if (++iTemp != iSection->second.end()) {
1979 if (!IsLess(a_pKey, iTemp->first.pItem)) {
1980 *a_pHasMultiple =
true;
1985 return iKeyVal->second;
1988 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
1991 const SI_CHAR * a_pSection,
1992 const SI_CHAR * a_pKey,
1994 bool * a_pHasMultiple
1998 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
1999 if (!pszValue || !*pszValue)
return a_nDefault;
2002 char szValue[64] = { 0 };
2003 SI_CONVERTER c(m_bStoreIsUtf8);
2004 if (!c.ConvertToStore(pszValue, szValue,
sizeof(szValue))) {
2009 long nValue = a_nDefault;
2010 char * pszSuffix = szValue;
2011 if (szValue[0] ==
'0' && (szValue[1] ==
'x' || szValue[1] ==
'X')) {
2012 if (!szValue[2])
return a_nDefault;
2013 nValue = strtol(&szValue[2], &pszSuffix, 16);
2016 nValue = strtol(szValue, &pszSuffix, 10);
2027 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2030 const SI_CHAR * a_pSection,
2031 const SI_CHAR * a_pKey,
2033 const SI_CHAR * a_pComment,
2035 bool a_bForceReplace
2039 if (!a_pSection || !a_pKey)
return SI_FAIL;
2043 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2044 sprintf_s(szInput, a_bUseHex ?
"0x%lx" :
"%ld", a_nValue);
2045 #else // !__STDC_WANT_SECURE_LIB__
2046 sprintf(szInput, a_bUseHex ?
"0x%lx" :
"%ld", a_nValue);
2047 #endif // __STDC_WANT_SECURE_LIB__
2050 SI_CHAR szOutput[64];
2051 SI_CONVERTER c(m_bStoreIsUtf8);
2052 c.ConvertFromStore(szInput, strlen(szInput) + 1,
2053 szOutput,
sizeof(szOutput) /
sizeof(SI_CHAR));
2056 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
true);
2059 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2062 const SI_CHAR * a_pSection,
2063 const SI_CHAR * a_pKey,
2065 bool * a_pHasMultiple
2069 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2070 if (!pszValue || !*pszValue)
return a_nDefault;
2073 char szValue[64] = { 0 };
2074 SI_CONVERTER c(m_bStoreIsUtf8);
2075 if (!c.ConvertToStore(pszValue, szValue,
sizeof(szValue))) {
2079 char * pszSuffix = NULL;
2080 double nValue = strtod(szValue, &pszSuffix);
2083 if (!pszSuffix || *pszSuffix) {
2090 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2093 const SI_CHAR * a_pSection,
2094 const SI_CHAR * a_pKey,
2096 const SI_CHAR * a_pComment,
2097 bool a_bForceReplace
2101 if (!a_pSection || !a_pKey)
return SI_FAIL;
2105 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2106 sprintf_s(szInput,
"%f", a_nValue);
2107 #else // !__STDC_WANT_SECURE_LIB__
2108 sprintf(szInput,
"%f", a_nValue);
2109 #endif // __STDC_WANT_SECURE_LIB__
2112 SI_CHAR szOutput[64];
2113 SI_CONVERTER c(m_bStoreIsUtf8);
2114 c.ConvertFromStore(szInput, strlen(szInput) + 1,
2115 szOutput,
sizeof(szOutput) /
sizeof(SI_CHAR));
2118 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
true);
2121 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2124 const SI_CHAR * a_pSection,
2125 const SI_CHAR * a_pKey,
2127 bool * a_pHasMultiple
2131 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
2132 if (!pszValue || !*pszValue)
return a_bDefault;
2135 switch (pszValue[0]) {
2147 if (pszValue[1] ==
'n' || pszValue[1] ==
'N')
return true;
2148 if (pszValue[1] ==
'f' || pszValue[1] ==
'F')
return false;
2156 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2159 const SI_CHAR * a_pSection,
2160 const SI_CHAR * a_pKey,
2162 const SI_CHAR * a_pComment,
2163 bool a_bForceReplace
2167 if (!a_pSection || !a_pKey)
return SI_FAIL;
2170 const char * pszInput = a_bValue ?
"true" :
"false";
2173 SI_CHAR szOutput[64];
2174 SI_CONVERTER c(m_bStoreIsUtf8);
2175 c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
2176 szOutput,
sizeof(szOutput) /
sizeof(SI_CHAR));
2179 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace,
true);
2182 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2185 const SI_CHAR * a_pSection,
2186 const SI_CHAR * a_pKey,
2192 if (!a_pSection || !a_pKey) {
2195 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2196 if (iSection == m_data.end()) {
2199 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
2200 if (iKeyVal == iSection->second.end()) {
2205 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2206 if (m_bAllowMultiKey) {
2208 while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
2209 a_values.push_back(
Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
2217 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2220 const SI_CHAR * a_pSection
2227 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2228 if (iSection == m_data.end()) {
2231 const TKeyVal & section = iSection->second;
2235 if (!m_bAllowMultiKey || section.empty()) {
2236 return (
int) section.size();
2241 const SI_CHAR * pLastKey = NULL;
2242 typename TKeyVal::const_iterator iKeyVal = section.begin();
2243 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
2244 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2246 pLastKey = iKeyVal->first.pItem;
2252 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2255 const SI_CHAR * a_pSection
2259 typename TSection::const_iterator i = m_data.find(a_pSection);
2260 if (i != m_data.end()) {
2261 return &(i->second);
2267 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2274 typename TSection::const_iterator i = m_data.begin();
2275 for (
int n = 0; i != m_data.end(); ++i, ++n ) {
2276 a_names.push_back(i->first);
2280 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2283 const SI_CHAR * a_pSection,
2293 typename TSection::const_iterator iSection = m_data.find(a_pSection);
2294 if (iSection == m_data.end()) {
2298 const TKeyVal & section = iSection->second;
2299 const SI_CHAR * pLastKey = NULL;
2300 typename TKeyVal::const_iterator iKeyVal = section.begin();
2301 for (
int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) {
2302 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
2303 a_names.push_back(iKeyVal->first);
2304 pLastKey = iKeyVal->first.pItem;
2311 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2314 const char * a_pszFile,
2315 bool a_bAddSignature
2319 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2320 fopen_s(&fp, a_pszFile,
"wb");
2321 #else // !__STDC_WANT_SECURE_LIB__
2322 fp = fopen(a_pszFile,
"wb");
2323 #endif // __STDC_WANT_SECURE_LIB__
2325 SI_Error rc = SaveFile(fp, a_bAddSignature);
2330 #ifdef SI_HAS_WIDE_FILE
2331 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2334 const SI_WCHAR_T * a_pwszFile,
2335 bool a_bAddSignature
2340 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
2341 _wfopen_s(&fp, a_pwszFile, L
"wb");
2342 #else // !__STDC_WANT_SECURE_LIB__
2343 fp = _wfopen(a_pwszFile, L
"wb");
2344 #endif // __STDC_WANT_SECURE_LIB__
2346 SI_Error rc = SaveFile(fp, a_bAddSignature);
2349 #else // !_WIN32 (therefore SI_CONVERT_ICU)
2351 u_austrncpy(szFile, a_pwszFile,
sizeof(szFile));
2352 return SaveFile(szFile, a_bAddSignature);
2355 #endif // SI_HAS_WIDE_FILE
2357 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2361 bool a_bAddSignature
2365 return Save(writer, a_bAddSignature);
2368 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2372 bool a_bAddSignature
2378 if (m_bStoreIsUtf8 && a_bAddSignature) {
2384 GetAllSections(oSections);
2385 #if defined(_MSC_VER) && _MSC_VER <= 1200
2387 #elif defined(__BORLANDC__)
2394 bool bNeedNewLine =
false;
2395 if (m_pFileComment) {
2396 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
2399 bNeedNewLine =
true;
2403 typename TNamesDepend::const_iterator iSection = oSections.begin();
2404 for ( ; iSection != oSections.end(); ++iSection ) {
2406 if (iSection->pComment) {
2411 if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
2414 bNeedNewLine =
false;
2420 bNeedNewLine =
false;
2424 if (*iSection->pItem) {
2428 a_oOutput.
Write(
"[");
2430 a_oOutput.
Write(
"]");
2436 GetAllKeys(iSection->pItem, oKeys);
2437 #if defined(_MSC_VER) && _MSC_VER <= 1200
2439 #elif defined(__BORLANDC__)
2446 typename TNamesDepend::const_iterator iKey = oKeys.begin();
2447 for ( ; iKey != oKeys.end(); ++iKey) {
2450 GetAllValues(iSection->pItem, iKey->pItem, oValues);
2452 typename TNamesDepend::const_iterator iValue = oValues.begin();
2453 for ( ; iValue != oValues.end(); ++iValue) {
2455 if (iValue->pComment) {
2457 if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
2472 a_oOutput.
Write(m_bSpaces ?
" = " :
"=");
2473 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
2477 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
2480 a_oOutput.
Write(
"END_OF_TEXT");
2489 bNeedNewLine =
true;
2495 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2498 OutputWriter & a_oOutput,
2499 Converter & a_oConverter,
2500 const SI_CHAR * a_pText
2503 const SI_CHAR * pEndOfLine;
2504 SI_CHAR cEndOfLineChar = *a_pText;
2505 while (cEndOfLineChar) {
2507 pEndOfLine = a_pText;
2508 for (; *pEndOfLine && *pEndOfLine !=
'\n'; ++pEndOfLine) ;
2509 cEndOfLineChar = *pEndOfLine;
2512 *
const_cast<SI_CHAR*
>(pEndOfLine) = 0;
2513 if (!a_oConverter.ConvertToStore(a_pText)) {
2516 *
const_cast<SI_CHAR*
>(pEndOfLine) = cEndOfLineChar;
2517 a_pText += (pEndOfLine - a_pText) + 1;
2518 a_oOutput.Write(a_oConverter.Data());
2524 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2527 const SI_CHAR * a_pSection,
2528 const SI_CHAR * a_pKey,
2536 typename TSection::iterator iSection = m_data.find(a_pSection);
2537 if (iSection == m_data.end()) {
2543 typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
2544 if (iKeyVal == iSection->second.end()) {
2549 typename TKeyVal::iterator iDelete;
2551 iDelete = iKeyVal++;
2553 DeleteString(iDelete->first.pItem);
2554 DeleteString(iDelete->second);
2555 iSection->second.erase(iDelete);
2557 while (iKeyVal != iSection->second.end()
2558 && !IsLess(a_pKey, iKeyVal->first.pItem));
2563 if (!a_bRemoveEmpty || !iSection->second.empty()) {
2570 typename TKeyVal::iterator iKeyVal = iSection->second.begin();
2571 for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
2572 DeleteString(iKeyVal->first.pItem);
2573 DeleteString(iKeyVal->second);
2578 DeleteString(iSection->first.pItem);
2579 m_data.erase(iSection);
2584 template<
class SI_CHAR,
class SI_STRLESS,
class SI_CONVERTER>
2587 const SI_CHAR * a_pString
2593 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
2594 typename TNamesDepend::iterator i = m_strings.begin();
2595 for (;i != m_strings.end(); ++i) {
2596 if (a_pString == i->pItem) {
2597 delete[]
const_cast<SI_CHAR*
>(i->pItem);
2619 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2621 # define SI_CONVERT_WIN32
2623 # define SI_CONVERT_GENERIC
2632 template<
class SI_CHAR>
2634 bool operator()(
const SI_CHAR * pLeft,
const SI_CHAR * pRight)
const {
2636 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
2637 cmp = (long) *pLeft - (
long) *pRight;
2642 return *pRight != 0;
2652 template<
class SI_CHAR>
2655 return (ch < 'A' || ch >
'Z') ? ch : (ch -
'A' +
'a');
2657 bool operator()(
const SI_CHAR * pLeft,
const SI_CHAR * pRight)
const {
2659 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
2665 return *pRight != 0;
2672 template<
class SI_CHAR>
2674 bool m_bStoreIsUtf8;
2683 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
2701 const char * a_pInputData,
2702 size_t a_uInputDataLen)
2705 SI_ASSERT(a_uInputDataLen != (
size_t) -1);
2708 return a_uInputDataLen;
2725 const char * a_pInputData,
2726 size_t a_uInputDataLen,
2727 SI_CHAR * a_pOutputData,
2728 size_t a_uOutputDataSize)
2731 if (a_uInputDataLen > a_uOutputDataSize) {
2734 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
2749 const SI_CHAR * a_pInputData)
2752 return strlen((
const char *)a_pInputData) + 1;
2769 const SI_CHAR * a_pInputData,
2770 char * a_pOutputData,
2771 size_t a_uOutputDataSize)
2774 size_t uInputLen = strlen((
const char *)a_pInputData) + 1;
2775 if (uInputLen > a_uOutputDataSize) {
2780 memcpy(a_pOutputData, a_pInputData, uInputLen);
2789 #ifdef SI_CONVERT_GENERIC
2791 #define SI_Case SI_GenericCase
2792 #define SI_NoCase SI_GenericNoCase
2795 #include "ConvertUTF.h"
2801 template<
class SI_CHAR>
2803 bool m_bStoreIsUtf8;
2812 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
2830 const char * a_pInputData,
2831 size_t a_uInputDataLen)
2833 SI_ASSERT(a_uInputDataLen != (
size_t) -1);
2835 if (m_bStoreIsUtf8) {
2839 return a_uInputDataLen;
2842 #if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
2846 return a_uInputDataLen;
2849 return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
2867 const char * a_pInputData,
2868 size_t a_uInputDataLen,
2869 SI_CHAR * a_pOutputData,
2870 size_t a_uOutputDataSize)
2872 if (m_bStoreIsUtf8) {
2878 ConversionResult retval;
2879 const UTF8 * pUtf8 = (
const UTF8 *) a_pInputData;
2880 if (
sizeof(
wchar_t) ==
sizeof(UTF32)) {
2881 UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
2882 retval = ConvertUTF8toUTF32(
2883 &pUtf8, pUtf8 + a_uInputDataLen,
2884 &pUtf32, pUtf32 + a_uOutputDataSize,
2887 else if (
sizeof(
wchar_t) ==
sizeof(UTF16)) {
2888 UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
2889 retval = ConvertUTF8toUTF16(
2890 &pUtf8, pUtf8 + a_uInputDataLen,
2891 &pUtf16, pUtf16 + a_uOutputDataSize,
2894 return retval == conversionOK;
2898 size_t retval = mbstowcs(a_pOutputData,
2899 a_pInputData, a_uOutputDataSize);
2900 return retval != (size_t)(-1);
2914 const SI_CHAR * a_pInputData)
2916 if (m_bStoreIsUtf8) {
2919 while (a_pInputData[uLen]) {
2922 return (6 * uLen) + 1;
2925 size_t uLen = wcstombs(NULL, a_pInputData, 0);
2926 if (uLen == (
size_t)(-1)) {
2947 const SI_CHAR * a_pInputData,
2948 char * a_pOutputData,
2949 size_t a_uOutputDataSize
2952 if (m_bStoreIsUtf8) {
2954 size_t uInputLen = 0;
2955 while (a_pInputData[uInputLen]) {
2965 ConversionResult retval;
2966 UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
2967 if (
sizeof(
wchar_t) ==
sizeof(UTF32)) {
2968 const UTF32 * pUtf32 = (
const UTF32 *) a_pInputData;
2969 retval = ConvertUTF32toUTF8(
2970 &pUtf32, pUtf32 + uInputLen,
2971 &pUtf8, pUtf8 + a_uOutputDataSize,
2974 else if (
sizeof(
wchar_t) ==
sizeof(UTF16)) {
2975 const UTF16 * pUtf16 = (
const UTF16 *) a_pInputData;
2976 retval = ConvertUTF16toUTF8(
2977 &pUtf16, pUtf16 + uInputLen,
2978 &pUtf8, pUtf8 + a_uOutputDataSize,
2981 return retval == conversionOK;
2984 size_t retval = wcstombs(a_pOutputData,
2985 a_pInputData, a_uOutputDataSize);
2986 return retval != (size_t) -1;
2991 #endif // SI_CONVERT_GENERIC
2997 #ifdef SI_CONVERT_ICU
2999 #define SI_Case SI_GenericCase
3000 #define SI_NoCase SI_GenericNoCase
3002 #include <unicode/ucnv.h>
3007 template<
class SI_CHAR>
3009 const char * m_pEncoding;
3010 UConverter * m_pConverter;
3012 SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { }
3014 SI_ConvertW(
bool a_bStoreIsUtf8) : m_pConverter(NULL) {
3015 m_pEncoding = a_bStoreIsUtf8 ?
"UTF-8" : NULL;
3021 m_pEncoding = rhs.m_pEncoding;
3022 m_pConverter = NULL;
3025 ~
SI_ConvertW() {
if (m_pConverter) ucnv_close(m_pConverter); }
3041 const char * a_pInputData,
3042 size_t a_uInputDataLen)
3044 SI_ASSERT(a_uInputDataLen != (
size_t) -1);
3048 if (!m_pConverter) {
3049 nError = U_ZERO_ERROR;
3050 m_pConverter = ucnv_open(m_pEncoding, &nError);
3051 if (U_FAILURE(nError)) {
3056 nError = U_ZERO_ERROR;
3057 int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
3058 a_pInputData, (int32_t) a_uInputDataLen, &nError);
3059 if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3063 return (
size_t) nLen;
3080 const char * a_pInputData,
3081 size_t a_uInputDataLen,
3082 UChar * a_pOutputData,
3083 size_t a_uOutputDataSize)
3087 if (!m_pConverter) {
3088 nError = U_ZERO_ERROR;
3089 m_pConverter = ucnv_open(m_pEncoding, &nError);
3090 if (U_FAILURE(nError)) {
3095 nError = U_ZERO_ERROR;
3096 ucnv_toUChars(m_pConverter,
3097 a_pOutputData, (int32_t) a_uOutputDataSize,
3098 a_pInputData, (int32_t) a_uInputDataLen, &nError);
3099 if (U_FAILURE(nError)) {
3117 const UChar * a_pInputData)
3121 if (!m_pConverter) {
3122 nError = U_ZERO_ERROR;
3123 m_pConverter = ucnv_open(m_pEncoding, &nError);
3124 if (U_FAILURE(nError)) {
3129 nError = U_ZERO_ERROR;
3130 int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
3131 a_pInputData, -1, &nError);
3132 if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
3136 return (
size_t) nLen + 1;
3153 const UChar * a_pInputData,
3154 char * a_pOutputData,
3155 size_t a_uOutputDataSize)
3159 if (!m_pConverter) {
3160 nError = U_ZERO_ERROR;
3161 m_pConverter = ucnv_open(m_pEncoding, &nError);
3162 if (U_FAILURE(nError)) {
3167 nError = U_ZERO_ERROR;
3168 ucnv_fromUChars(m_pConverter,
3169 a_pOutputData, (int32_t) a_uOutputDataSize,
3170 a_pInputData, -1, &nError);
3171 if (U_FAILURE(nError)) {
3179 #endif // SI_CONVERT_ICU
3185 #ifdef SI_CONVERT_WIN32
3187 #define SI_Case SI_GenericCase
3196 #include <windows.h>
3198 # define SI_NoCase SI_GenericNoCase
3199 #else // !SI_NO_MBCS
3208 #include <mbstring.h>
3209 template<
class SI_CHAR>
3211 bool operator()(
const SI_CHAR * pLeft,
const SI_CHAR * pRight)
const {
3212 if (
sizeof(SI_CHAR) ==
sizeof(
char)) {
3213 return _mbsicmp((
const unsigned char *)pLeft,
3214 (
const unsigned char *)pRight) < 0;
3216 if (
sizeof(SI_CHAR) ==
sizeof(
wchar_t)) {
3217 return _wcsicmp((
const wchar_t *)pLeft,
3218 (
const wchar_t *)pRight) < 0;
3223 #endif // SI_NO_MBCS
3231 template<
class SI_CHAR>
3238 m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
3244 m_uCodePage = rhs.m_uCodePage;
3262 const char * a_pInputData,
3263 size_t a_uInputDataLen)
3265 SI_ASSERT(a_uInputDataLen != (
size_t) -1);
3267 int retval = MultiByteToWideChar(
3269 a_pInputData, (
int) a_uInputDataLen,
3271 return (
size_t)(retval > 0 ? retval : -1);
3288 const char * a_pInputData,
3289 size_t a_uInputDataLen,
3290 SI_CHAR * a_pOutputData,
3291 size_t a_uOutputDataSize)
3293 int nSize = MultiByteToWideChar(
3295 a_pInputData, (
int) a_uInputDataLen,
3296 (
wchar_t *) a_pOutputData, (
int) a_uOutputDataSize);
3311 const SI_CHAR * a_pInputData)
3313 int retval = WideCharToMultiByte(
3315 (
const wchar_t *) a_pInputData, -1,
3317 return (
size_t) (retval > 0 ? retval : -1);
3334 const SI_CHAR * a_pInputData,
3335 char * a_pOutputData,
3336 size_t a_uOutputDataSize)
3338 int retval = WideCharToMultiByte(
3340 (
const wchar_t *) a_pInputData, -1,
3341 a_pOutputData, (
int) a_uOutputDataSize, 0, 0);
3346 #endif // SI_CONVERT_WIN32
3358 #if defined(SI_CONVERT_ICU)
3371 # define CSimpleIni CSimpleIniW
3372 # define CSimpleIniCase CSimpleIniCaseW
3373 # define SI_NEWLINE SI_NEWLINE_W
3375 # define CSimpleIni CSimpleIniA
3376 # define CSimpleIniCase CSimpleIniCaseA
3377 # define SI_NEWLINE SI_NEWLINE_A
3381 # pragma warning (pop)
3384 #endif // INCLUDED_SimpleIni_h