00001
00191 #ifndef INCLUDED_SimpleIni_h
00192 #define INCLUDED_SimpleIni_h
00193
00194 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
00195 # pragma once
00196 #endif
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207 #ifdef _MSC_VER
00208 # pragma warning (push)
00209 # pragma warning (disable: 4127 4503 4702 4786)
00210 #endif
00211
00212 #include <cstring>
00213 #include <string>
00214 #include <map>
00215 #include <list>
00216 #include <algorithm>
00217 #include <stdio.h>
00218
00219 #ifdef SI_SUPPORT_IOSTREAMS
00220 # include <iostream>
00221 #endif // SI_SUPPORT_IOSTREAMS
00222
00223 #ifdef _DEBUG
00224 # ifndef assert
00225 # include <cassert>
00226 # endif
00227 # define SI_ASSERT(x) assert(x)
00228 #else
00229 # define SI_ASSERT(x)
00230 #endif
00231
00232 enum SI_Error {
00233 SI_OK = 0,
00234 SI_UPDATED = 1,
00235 SI_INSERTED = 2,
00236
00237
00238 SI_FAIL = -1,
00239 SI_NOMEM = -2,
00240 SI_FILE = -3
00241 };
00242
00243 #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
00244
00245 #ifdef _WIN32
00246 # define SI_NEWLINE_A "\r\n"
00247 # define SI_NEWLINE_W L"\r\n"
00248 #else // !_WIN32
00249 # define SI_NEWLINE_A "\n"
00250 # define SI_NEWLINE_W L"\n"
00251 #endif // _WIN32
00252
00253 #if defined(SI_CONVERT_ICU)
00254 # include <unicode/ustring.h>
00255 #endif
00256
00257 #if defined(_WIN32)
00258 # define SI_HAS_WIDE_FILE
00259 # define SI_WCHAR_T wchar_t
00260 #elif defined(SI_CONVERT_ICU)
00261 # define SI_HAS_WIDE_FILE
00262 # define SI_WCHAR_T UChar
00263 #endif
00264
00265
00266
00267
00268
00269
00289 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
00290 class CSimpleIniTempl
00291 {
00292 public:
00294 struct Entry {
00295 const SI_CHAR * pItem;
00296 const SI_CHAR * pComment;
00297 int nOrder;
00298
00299 Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0)
00300 : pItem(a_pszItem)
00301 , pComment(NULL)
00302 , nOrder(a_nOrder)
00303 { }
00304 Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder)
00305 : pItem(a_pszItem)
00306 , pComment(a_pszComment)
00307 , nOrder(a_nOrder)
00308 { }
00309 Entry(const Entry & rhs) { operator=(rhs); }
00310 Entry & operator=(const Entry & rhs) {
00311 pItem = rhs.pItem;
00312 pComment = rhs.pComment;
00313 nOrder = rhs.nOrder;
00314 return *this;
00315 }
00316
00317 #if defined(_MSC_VER) && _MSC_VER <= 1200
00318
00319 bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
00320 bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
00321 #endif
00322
00324 struct KeyOrder : std::binary_function<Entry, Entry, bool> {
00325 bool operator()(const Entry & lhs, const Entry & rhs) const {
00326 const static SI_STRLESS isLess = SI_STRLESS();
00327 return isLess(lhs.pItem, rhs.pItem);
00328 }
00329 };
00330
00332 struct LoadOrder : std::binary_function<Entry, Entry, bool> {
00333 bool operator()(const Entry & lhs, const Entry & rhs) const {
00334 if (lhs.nOrder != rhs.nOrder) {
00335 return lhs.nOrder < rhs.nOrder;
00336 }
00337 return KeyOrder()(lhs.pItem, rhs.pItem);
00338 }
00339 };
00340 };
00341
00343 typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder> TKeyVal;
00344
00346 typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder> TSection;
00347
00351 typedef std::list<Entry> TNamesDepend;
00352
00356 class OutputWriter {
00357 public:
00358 OutputWriter() { }
00359 virtual ~OutputWriter() { }
00360 virtual void Write(const char * a_pBuf) = 0;
00361 private:
00362 OutputWriter(const OutputWriter &);
00363 OutputWriter & operator=(const OutputWriter &);
00364 };
00365
00367 class FileWriter : public OutputWriter {
00368 FILE * m_file;
00369 public:
00370 FileWriter(FILE * a_file) : m_file(a_file) { }
00371 void Write(const char * a_pBuf) {
00372 fputs(a_pBuf, m_file);
00373 }
00374 private:
00375 FileWriter(const FileWriter &);
00376 FileWriter & operator=(const FileWriter &);
00377 };
00378
00380 class StringWriter : public OutputWriter {
00381 std::string & m_string;
00382 public:
00383 StringWriter(std::string & a_string) : m_string(a_string) { }
00384 void Write(const char * a_pBuf) {
00385 m_string.append(a_pBuf);
00386 }
00387 private:
00388 StringWriter(const StringWriter &);
00389 StringWriter & operator=(const StringWriter &);
00390 };
00391
00392 #ifdef SI_SUPPORT_IOSTREAMS
00393
00394 class StreamWriter : public OutputWriter {
00395 std::ostream & m_ostream;
00396 public:
00397 StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { }
00398 void Write(const char * a_pBuf) {
00399 m_ostream << a_pBuf;
00400 }
00401 private:
00402 StreamWriter(const StreamWriter &);
00403 StreamWriter & operator=(const StreamWriter &);
00404 };
00405 #endif // SI_SUPPORT_IOSTREAMS
00406
00410 class Converter : private SI_CONVERTER {
00411 public:
00412 Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
00413 m_scratch.resize(1024);
00414 }
00415 Converter(const Converter & rhs) { operator=(rhs); }
00416 Converter & operator=(const Converter & rhs) {
00417 m_scratch = rhs.m_scratch;
00418 return *this;
00419 }
00420 bool ConvertToStore(const SI_CHAR * a_pszString) {
00421 size_t uLen = SizeToStore(a_pszString);
00422 if (uLen == (size_t)(-1)) {
00423 return false;
00424 }
00425 while (uLen > m_scratch.size()) {
00426 m_scratch.resize(m_scratch.size() * 2);
00427 }
00428 return SI_CONVERTER::ConvertToStore(
00429 a_pszString,
00430 const_cast<char*>(m_scratch.data()),
00431 m_scratch.size());
00432 }
00433 const char * Data() { return m_scratch.data(); }
00434 private:
00435 std::string m_scratch;
00436 };
00437
00438 public:
00439
00440
00447 CSimpleIniTempl(
00448 bool a_bIsUtf8 = false,
00449 bool a_bMultiKey = false,
00450 bool a_bMultiLine = false
00451 );
00452
00454 ~CSimpleIniTempl();
00455
00457 void Reset();
00458
00459
00476 void SetUnicode(bool a_bIsUtf8 = true) {
00477 if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
00478 }
00479
00481 bool IsUnicode() const { return m_bStoreIsUtf8; }
00482
00501 void SetMultiKey(bool a_bAllowMultiKey = true) {
00502 m_bAllowMultiKey = a_bAllowMultiKey;
00503 }
00504
00506 bool IsMultiKey() const { return m_bAllowMultiKey; }
00507
00515 void SetMultiLine(bool a_bAllowMultiLine = true) {
00516 m_bAllowMultiLine = a_bAllowMultiLine;
00517 }
00518
00520 bool IsMultiLine() const { return m_bAllowMultiLine; }
00521
00528 void SetSpaces(bool a_bSpaces = true) {
00529 m_bSpaces = a_bSpaces;
00530 }
00531
00533 bool UsingSpaces() const { return m_bSpaces; }
00534
00535
00547 SI_Error LoadFile(
00548 const char * a_pszFile
00549 );
00550
00551 #ifdef SI_HAS_WIDE_FILE
00552
00558 SI_Error LoadFile(
00559 const SI_WCHAR_T * a_pwszFile
00560 );
00561 #endif // SI_HAS_WIDE_FILE
00562
00570 SI_Error LoadFile(
00571 FILE * a_fpFile
00572 );
00573
00574 #ifdef SI_SUPPORT_IOSTREAMS
00575
00581 SI_Error Load(
00582 std::istream & a_istream
00583 );
00584 #endif // SI_SUPPORT_IOSTREAMS
00585
00592 SI_Error Load(const std::string & a_strData) {
00593 return Load(a_strData.c_str(), a_strData.size());
00594 }
00595
00603 SI_Error Load(
00604 const char * a_pData,
00605 size_t a_uDataLen
00606 );
00607
00608
00624 SI_Error SaveFile(
00625 const char * a_pszFile,
00626 bool a_bAddSignature = true
00627 ) const;
00628
00629 #ifdef SI_HAS_WIDE_FILE
00630
00640 SI_Error SaveFile(
00641 const SI_WCHAR_T * a_pwszFile,
00642 bool a_bAddSignature = true
00643 ) const;
00644 #endif // _WIN32
00645
00658 SI_Error SaveFile(
00659 FILE * a_pFile,
00660 bool a_bAddSignature = false
00661 ) const;
00662
00694 SI_Error Save(
00695 OutputWriter & a_oOutput,
00696 bool a_bAddSignature = false
00697 ) const;
00698
00699 #ifdef SI_SUPPORT_IOSTREAMS
00700
00711 SI_Error Save(
00712 std::ostream & a_ostream,
00713 bool a_bAddSignature = false
00714 ) const
00715 {
00716 StreamWriter writer(a_ostream);
00717 return Save(writer, a_bAddSignature);
00718 }
00719 #endif // SI_SUPPORT_IOSTREAMS
00720
00732 SI_Error Save(
00733 std::string & a_sBuffer,
00734 bool a_bAddSignature = false
00735 ) const
00736 {
00737 StringWriter writer(a_sBuffer);
00738 return Save(writer, a_bAddSignature);
00739 }
00740
00741
00759 void GetAllSections(
00760 TNamesDepend & a_names
00761 ) const;
00762
00780 bool GetAllKeys(
00781 const SI_CHAR * a_pSection,
00782 TNamesDepend & a_names
00783 ) const;
00784
00801 bool GetAllValues(
00802 const SI_CHAR * a_pSection,
00803 const SI_CHAR * a_pKey,
00804 TNamesDepend & a_values
00805 ) const;
00806
00816 int GetSectionSize(
00817 const SI_CHAR * a_pSection
00818 ) const;
00819
00834 const TKeyVal * GetSection(
00835 const SI_CHAR * a_pSection
00836 ) const;
00837
00855 const SI_CHAR * GetValue(
00856 const SI_CHAR * a_pSection,
00857 const SI_CHAR * a_pKey,
00858 const SI_CHAR * a_pDefault = NULL,
00859 bool * a_pHasMultiple = NULL
00860 ) const;
00861
00875 long GetLongValue(
00876 const SI_CHAR * a_pSection,
00877 const SI_CHAR * a_pKey,
00878 long a_nDefault = 0,
00879 bool * a_pHasMultiple = NULL
00880 ) const;
00881
00900 bool GetBoolValue(
00901 const SI_CHAR * a_pSection,
00902 const SI_CHAR * a_pKey,
00903 bool a_bDefault = false,
00904 bool * a_pHasMultiple = NULL
00905 ) const;
00906
00936 SI_Error SetValue(
00937 const SI_CHAR * a_pSection,
00938 const SI_CHAR * a_pKey,
00939 const SI_CHAR * a_pValue,
00940 const SI_CHAR * a_pComment = NULL,
00941 bool a_bForceReplace = false
00942 )
00943 {
00944 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true);
00945 }
00946
00970 SI_Error SetLongValue(
00971 const SI_CHAR * a_pSection,
00972 const SI_CHAR * a_pKey,
00973 long a_nValue,
00974 const SI_CHAR * a_pComment = NULL,
00975 bool a_bUseHex = false,
00976 bool a_bForceReplace = false
00977 );
00978
00999 SI_Error SetBoolValue(
01000 const SI_CHAR * a_pSection,
01001 const SI_CHAR * a_pKey,
01002 bool a_bValue,
01003 const SI_CHAR * a_pComment = NULL,
01004 bool a_bForceReplace = false
01005 );
01006
01025 bool Delete(
01026 const SI_CHAR * a_pSection,
01027 const SI_CHAR * a_pKey,
01028 bool a_bRemoveEmpty = false
01029 );
01030
01031
01040 Converter GetConverter() const {
01041 return Converter(m_bStoreIsUtf8);
01042 }
01043
01044
01047 private:
01048
01049 CSimpleIniTempl(const CSimpleIniTempl &);
01050 CSimpleIniTempl & operator=(const CSimpleIniTempl &);
01051
01054 SI_Error FindFileComment(
01055 SI_CHAR *& a_pData,
01056 bool a_bCopyStrings
01057 );
01058
01063 bool FindEntry(
01064 SI_CHAR *& a_pData,
01065 const SI_CHAR *& a_pSection,
01066 const SI_CHAR *& a_pKey,
01067 const SI_CHAR *& a_pVal,
01068 const SI_CHAR *& a_pComment
01069 ) const;
01070
01093 SI_Error AddEntry(
01094 const SI_CHAR * a_pSection,
01095 const SI_CHAR * a_pKey,
01096 const SI_CHAR * a_pValue,
01097 const SI_CHAR * a_pComment,
01098 bool a_bForceReplace,
01099 bool a_bCopyStrings
01100 );
01101
01103 inline bool IsSpace(SI_CHAR ch) const {
01104 return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
01105 }
01106
01108 inline bool IsComment(SI_CHAR ch) const {
01109 return (ch == ';' || ch == '#');
01110 }
01111
01112
01114 inline void SkipNewLine(SI_CHAR *& a_pData) const {
01115 a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1;
01116 }
01117
01119 SI_Error CopyString(const SI_CHAR *& a_pString);
01120
01122 void DeleteString(const SI_CHAR * a_pString);
01123
01125 bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const {
01126 const static SI_STRLESS isLess = SI_STRLESS();
01127 return isLess(a_pLeft, a_pRight);
01128 }
01129
01130 bool IsMultiLineTag(const SI_CHAR * a_pData) const;
01131 bool IsMultiLineData(const SI_CHAR * a_pData) const;
01132 bool LoadMultiLineText(
01133 SI_CHAR *& a_pData,
01134 const SI_CHAR *& a_pVal,
01135 const SI_CHAR * a_pTagName,
01136 bool a_bAllowBlankLinesInComment = false
01137 ) const;
01138 bool IsNewLineChar(SI_CHAR a_c) const;
01139
01140 bool OutputMultiLineText(
01141 OutputWriter & a_oOutput,
01142 Converter & a_oConverter,
01143 const SI_CHAR * a_pText
01144 ) const;
01145
01146 private:
01152 SI_CHAR * m_pData;
01153
01158 size_t m_uDataLen;
01159
01161 const SI_CHAR * m_pFileComment;
01162
01164 TSection m_data;
01165
01170 TNamesDepend m_strings;
01171
01173 bool m_bStoreIsUtf8;
01174
01176 bool m_bAllowMultiKey;
01177
01179 bool m_bAllowMultiLine;
01180
01182 bool m_bSpaces;
01183
01187 int m_nOrder;
01188 };
01189
01190
01191
01192
01193
01194 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01195 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CSimpleIniTempl(
01196 bool a_bIsUtf8,
01197 bool a_bAllowMultiKey,
01198 bool a_bAllowMultiLine
01199 )
01200 : m_pData(0)
01201 , m_uDataLen(0)
01202 , m_pFileComment(NULL)
01203 , m_bStoreIsUtf8(a_bIsUtf8)
01204 , m_bAllowMultiKey(a_bAllowMultiKey)
01205 , m_bAllowMultiLine(a_bAllowMultiLine)
01206 , m_bSpaces(true)
01207 , m_nOrder(0)
01208 { }
01209
01210 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01211 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::~CSimpleIniTempl()
01212 {
01213 Reset();
01214 }
01215
01216 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01217 void
01218 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Reset()
01219 {
01220
01221 delete[] m_pData;
01222 m_pData = NULL;
01223 m_uDataLen = 0;
01224 m_pFileComment = NULL;
01225 if (!m_data.empty()) {
01226 m_data.erase(m_data.begin(), m_data.end());
01227 }
01228
01229
01230 if (!m_strings.empty()) {
01231 typename TNamesDepend::iterator i = m_strings.begin();
01232 for (; i != m_strings.end(); ++i) {
01233 delete[] const_cast<SI_CHAR*>(i->pItem);
01234 }
01235 m_strings.erase(m_strings.begin(), m_strings.end());
01236 }
01237 }
01238
01239 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01240 SI_Error
01241 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
01242 const char * a_pszFile
01243 )
01244 {
01245 FILE * fp = NULL;
01246 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
01247 fopen_s(&fp, a_pszFile, "rb");
01248 #else // !__STDC_WANT_SECURE_LIB__
01249 fp = fopen(a_pszFile, "rb");
01250 #endif // __STDC_WANT_SECURE_LIB__
01251 if (!fp) {
01252 return SI_FILE;
01253 }
01254 SI_Error rc = LoadFile(fp);
01255 fclose(fp);
01256 return rc;
01257 }
01258
01259 #ifdef SI_HAS_WIDE_FILE
01260 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01261 SI_Error
01262 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
01263 const SI_WCHAR_T * a_pwszFile
01264 )
01265 {
01266 #ifdef _WIN32
01267 FILE * fp = NULL;
01268 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
01269 _wfopen_s(&fp, a_pwszFile, L"rb");
01270 #else // !__STDC_WANT_SECURE_LIB__
01271 fp = _wfopen(a_pwszFile, L"rb");
01272 #endif // __STDC_WANT_SECURE_LIB__
01273 if (!fp) return SI_FILE;
01274 SI_Error rc = LoadFile(fp);
01275 fclose(fp);
01276 return rc;
01277 #else // !_WIN32 (therefore SI_CONVERT_ICU)
01278 char szFile[256];
01279 u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
01280 return LoadFile(szFile);
01281 #endif // _WIN32
01282 }
01283 #endif // SI_HAS_WIDE_FILE
01284
01285 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01286 SI_Error
01287 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
01288 FILE * a_fpFile
01289 )
01290 {
01291
01292 int retval = fseek(a_fpFile, 0, SEEK_END);
01293 if (retval != 0) {
01294 return SI_FILE;
01295 }
01296 long lSize = ftell(a_fpFile);
01297 if (lSize < 0) {
01298 return SI_FILE;
01299 }
01300 if (lSize == 0) {
01301 return SI_OK;
01302 }
01303 char * pData = new char[lSize];
01304 if (!pData) {
01305 return SI_NOMEM;
01306 }
01307 fseek(a_fpFile, 0, SEEK_SET);
01308 size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
01309 if (uRead != (size_t) lSize) {
01310 delete[] pData;
01311 return SI_FILE;
01312 }
01313
01314
01315 SI_Error rc = Load(pData, uRead);
01316 delete[] pData;
01317 return rc;
01318 }
01319
01320 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01321 SI_Error
01322 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
01323 const char * a_pData,
01324 size_t a_uDataLen
01325 )
01326 {
01327 SI_CONVERTER converter(m_bStoreIsUtf8);
01328
01329 if (a_uDataLen == 0) {
01330 return SI_OK;
01331 }
01332
01333
01334 if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
01335 if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
01336 a_pData += 3;
01337 a_uDataLen -= 3;
01338 }
01339 }
01340
01341
01342 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
01343 if (uLen == (size_t)(-1)) {
01344 return SI_FAIL;
01345 }
01346
01347
01348
01349 SI_CHAR * pData = new SI_CHAR[uLen+1];
01350 if (!pData) {
01351 return SI_NOMEM;
01352 }
01353 memset(pData, 0, sizeof(SI_CHAR)*(uLen+1));
01354
01355
01356 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
01357 delete[] pData;
01358 return SI_FAIL;
01359 }
01360
01361
01362 const static SI_CHAR empty = 0;
01363 SI_CHAR * pWork = pData;
01364 const SI_CHAR * pSection = ∅
01365 const SI_CHAR * pItem = NULL;
01366 const SI_CHAR * pVal = NULL;
01367 const SI_CHAR * pComment = NULL;
01368
01369
01370
01371 bool bCopyStrings = (m_pData != NULL);
01372
01373
01374
01375 SI_Error rc = FindFileComment(pWork, bCopyStrings);
01376 if (rc < 0) return rc;
01377
01378
01379 while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
01380 rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings);
01381 if (rc < 0) return rc;
01382 }
01383
01384
01385 if (bCopyStrings) {
01386 delete[] pData;
01387 }
01388 else {
01389 m_pData = pData;
01390 m_uDataLen = uLen+1;
01391 }
01392
01393 return SI_OK;
01394 }
01395
01396 #ifdef SI_SUPPORT_IOSTREAMS
01397 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01398 SI_Error
01399 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
01400 std::istream & a_istream
01401 )
01402 {
01403 std::string strData;
01404 char szBuf[512];
01405 do {
01406 a_istream.get(szBuf, sizeof(szBuf), '\0');
01407 strData.append(szBuf);
01408 }
01409 while (a_istream.good());
01410 return Load(strData);
01411 }
01412 #endif // SI_SUPPORT_IOSTREAMS
01413
01414 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01415 SI_Error
01416 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindFileComment(
01417 SI_CHAR *& a_pData,
01418 bool a_bCopyStrings
01419 )
01420 {
01421
01422 if (m_pFileComment) {
01423 return SI_OK;
01424 }
01425
01426
01427
01428 if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
01429 return SI_OK;
01430 }
01431
01432
01433 if (a_bCopyStrings) {
01434 SI_Error rc = CopyString(m_pFileComment);
01435 if (rc < 0) return rc;
01436 }
01437
01438 return SI_OK;
01439 }
01440
01441 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01442 bool
01443 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
01444 SI_CHAR *& a_pData,
01445 const SI_CHAR *& a_pSection,
01446 const SI_CHAR *& a_pKey,
01447 const SI_CHAR *& a_pVal,
01448 const SI_CHAR *& a_pComment
01449 ) const
01450 {
01451 a_pComment = NULL;
01452
01453 SI_CHAR * pTrail = NULL;
01454 while (*a_pData) {
01455
01456 while (*a_pData && IsSpace(*a_pData)) {
01457 ++a_pData;
01458 }
01459 if (!*a_pData) {
01460 break;
01461 }
01462
01463
01464
01465 if (IsComment(*a_pData)) {
01466 LoadMultiLineText(a_pData, a_pComment, NULL, true);
01467 continue;
01468 }
01469
01470
01471 if (*a_pData == '[') {
01472
01473 ++a_pData;
01474 while (*a_pData && IsSpace(*a_pData)) {
01475 ++a_pData;
01476 }
01477
01478
01479
01480 a_pSection = a_pData;
01481 while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
01482 ++a_pData;
01483 }
01484
01485
01486 if (*a_pData != ']') {
01487 continue;
01488 }
01489
01490
01491 pTrail = a_pData - 1;
01492 while (pTrail >= a_pSection && IsSpace(*pTrail)) {
01493 --pTrail;
01494 }
01495 ++pTrail;
01496 *pTrail = 0;
01497
01498
01499 ++a_pData;
01500 while (*a_pData && !IsNewLineChar(*a_pData)) {
01501 ++a_pData;
01502 }
01503
01504 a_pKey = NULL;
01505 a_pVal = NULL;
01506 return true;
01507 }
01508
01509
01510
01511 a_pKey = a_pData;
01512 while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
01513 ++a_pData;
01514 }
01515
01516
01517 if (*a_pData != '=') {
01518 continue;
01519 }
01520
01521
01522 if (a_pKey == a_pData) {
01523 while (*a_pData && !IsNewLineChar(*a_pData)) {
01524 ++a_pData;
01525 }
01526 continue;
01527 }
01528
01529
01530 pTrail = a_pData - 1;
01531 while (pTrail >= a_pKey && IsSpace(*pTrail)) {
01532 --pTrail;
01533 }
01534 ++pTrail;
01535 *pTrail = 0;
01536
01537
01538 ++a_pData;
01539 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
01540 ++a_pData;
01541 }
01542
01543
01544 a_pVal = a_pData;
01545 while (*a_pData && !IsNewLineChar(*a_pData)) {
01546 ++a_pData;
01547 }
01548
01549
01550 pTrail = a_pData - 1;
01551 if (*a_pData) {
01552 SkipNewLine(a_pData);
01553 }
01554 while (pTrail >= a_pVal && IsSpace(*pTrail)) {
01555 --pTrail;
01556 }
01557 ++pTrail;
01558 *pTrail = 0;
01559
01560
01561 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
01562
01563 const SI_CHAR * pTagName = a_pVal + 3;
01564 return LoadMultiLineText(a_pData, a_pVal, pTagName);
01565 }
01566
01567
01568 return true;
01569 }
01570
01571 return false;
01572 }
01573
01574 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01575 bool
01576 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineTag(
01577 const SI_CHAR * a_pVal
01578 ) const
01579 {
01580
01581 if (*a_pVal++ != '<') return false;
01582 if (*a_pVal++ != '<') return false;
01583 if (*a_pVal++ != '<') return false;
01584 return true;
01585 }
01586
01587 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01588 bool
01589 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineData(
01590 const SI_CHAR * a_pData
01591 ) const
01592 {
01593
01594
01595
01596
01597
01598
01599 if (!*a_pData) {
01600 return false;
01601 }
01602
01603
01604 if (IsSpace(*a_pData)) {
01605 return true;
01606 }
01607
01608
01609 while (*a_pData) {
01610 if (IsNewLineChar(*a_pData)) {
01611 return true;
01612 }
01613 ++a_pData;
01614 }
01615
01616
01617 if (IsSpace(*--a_pData)) {
01618 return true;
01619 }
01620
01621 return false;
01622 }
01623
01624 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01625 bool
01626 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsNewLineChar(
01627 SI_CHAR a_c
01628 ) const
01629 {
01630 return (a_c == '\n' || a_c == '\r');
01631 }
01632
01633 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01634 bool
01635 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadMultiLineText(
01636 SI_CHAR *& a_pData,
01637 const SI_CHAR *& a_pVal,
01638 const SI_CHAR * a_pTagName,
01639 bool a_bAllowBlankLinesInComment
01640 ) const
01641 {
01642
01643
01644
01645
01646
01647
01648
01649
01650 SI_CHAR * pDataLine = a_pData;
01651 SI_CHAR * pCurrLine;
01652
01653
01654 a_pVal = a_pData;
01655
01656
01657
01658
01659 SI_CHAR cEndOfLineChar = *a_pData;
01660 for(;;) {
01661
01662
01663 if (!a_pTagName && !IsComment(*a_pData)) {
01664
01665 if (!a_bAllowBlankLinesInComment) {
01666 break;
01667 }
01668
01669
01670
01671
01672 SI_CHAR * pCurr = a_pData;
01673 int nNewLines = 0;
01674 while (IsSpace(*pCurr)) {
01675 if (IsNewLineChar(*pCurr)) {
01676 ++nNewLines;
01677 SkipNewLine(pCurr);
01678 }
01679 else {
01680 ++pCurr;
01681 }
01682 }
01683
01684
01685
01686 if (IsComment(*pCurr)) {
01687 for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
01688 a_pData = pCurr;
01689 continue;
01690 }
01691
01692
01693 break;
01694 }
01695
01696
01697 pCurrLine = a_pData;
01698 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
01699
01700
01701 if (pDataLine < pCurrLine) {
01702 size_t nLen = (size_t) (a_pData - pCurrLine);
01703 memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR));
01704 pDataLine[nLen] = '\0';
01705 }
01706
01707
01708 cEndOfLineChar = *a_pData;
01709 *a_pData = 0;
01710
01711
01712
01713
01714 if (a_pTagName &&
01715 (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
01716 {
01717 break;
01718 }
01719
01720
01721
01722 if (!cEndOfLineChar) {
01723 return true;
01724 }
01725
01726
01727
01728 pDataLine += (a_pData - pCurrLine);
01729 *a_pData = cEndOfLineChar;
01730 SkipNewLine(a_pData);
01731 *pDataLine++ = '\n';
01732 }
01733
01734
01735 if (a_pVal == a_pData) {
01736 a_pVal = NULL;
01737 return false;
01738 }
01739
01740
01741
01742
01743
01744 *--pDataLine = '\0';
01745
01746
01747
01748 if (a_pTagName && cEndOfLineChar) {
01749 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
01750 *a_pData = cEndOfLineChar;
01751 SkipNewLine(a_pData);
01752 }
01753
01754 return true;
01755 }
01756
01757 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01758 SI_Error
01759 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CopyString(
01760 const SI_CHAR *& a_pString
01761 )
01762 {
01763 size_t uLen = 0;
01764 if (sizeof(SI_CHAR) == sizeof(char)) {
01765 uLen = strlen((const char *)a_pString);
01766 }
01767 else if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
01768 uLen = wcslen((const wchar_t *)a_pString);
01769 }
01770 else {
01771 for ( ; a_pString[uLen]; ++uLen) ;
01772 }
01773 ++uLen;
01774 SI_CHAR * pCopy = new SI_CHAR[uLen];
01775 if (!pCopy) {
01776 return SI_NOMEM;
01777 }
01778 memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen);
01779 m_strings.push_back(pCopy);
01780 a_pString = pCopy;
01781 return SI_OK;
01782 }
01783
01784 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01785 SI_Error
01786 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
01787 const SI_CHAR * a_pSection,
01788 const SI_CHAR * a_pKey,
01789 const SI_CHAR * a_pValue,
01790 const SI_CHAR * a_pComment,
01791 bool a_bForceReplace,
01792 bool a_bCopyStrings
01793 )
01794 {
01795 SI_Error rc;
01796 bool bInserted = false;
01797
01798 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
01799
01800
01801
01802 if (a_bCopyStrings && a_pComment) {
01803 rc = CopyString(a_pComment);
01804 if (rc < 0) return rc;
01805 }
01806
01807
01808 typename TSection::iterator iSection = m_data.find(a_pSection);
01809 if (iSection == m_data.end()) {
01810
01811
01812 if (a_bCopyStrings) {
01813 rc = CopyString(a_pSection);
01814 if (rc < 0) return rc;
01815 }
01816
01817
01818 Entry oSection(a_pSection, ++m_nOrder);
01819 if (a_pComment && (!a_pKey || !a_pValue)) {
01820 oSection.pComment = a_pComment;
01821 }
01822
01823 typename TSection::value_type oEntry(oSection, TKeyVal());
01824 typedef typename TSection::iterator SectionIterator;
01825 std::pair<SectionIterator,bool> i = m_data.insert(oEntry);
01826 iSection = i.first;
01827 bInserted = true;
01828 }
01829 if (!a_pKey || !a_pValue) {
01830
01831 return bInserted ? SI_INSERTED : SI_UPDATED;
01832 }
01833
01834
01835 TKeyVal & keyval = iSection->second;
01836 typename TKeyVal::iterator iKey = keyval.find(a_pKey);
01837
01838
01839
01840 int nLoadOrder = ++m_nOrder;
01841 if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
01842 const SI_CHAR * pComment = NULL;
01843 while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
01844 if (iKey->first.nOrder < nLoadOrder) {
01845 nLoadOrder = iKey->first.nOrder;
01846 pComment = iKey->first.pComment;
01847 }
01848 ++iKey;
01849 }
01850 if (pComment) {
01851 DeleteString(a_pComment);
01852 a_pComment = pComment;
01853 CopyString(a_pComment);
01854 }
01855 Delete(a_pSection, a_pKey);
01856 iKey = keyval.end();
01857 }
01858
01859
01860 bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
01861 if (a_bCopyStrings) {
01862 if (bForceCreateNewKey || iKey == keyval.end()) {
01863
01864
01865
01866 rc = CopyString(a_pKey);
01867 if (rc < 0) return rc;
01868 }
01869
01870
01871 rc = CopyString(a_pValue);
01872 if (rc < 0) return rc;
01873 }
01874
01875
01876 if (iKey == keyval.end() || bForceCreateNewKey) {
01877 Entry oKey(a_pKey, nLoadOrder);
01878 if (a_pComment) {
01879 oKey.pComment = a_pComment;
01880 }
01881 typename TKeyVal::value_type oEntry(oKey, NULL);
01882 iKey = keyval.insert(oEntry);
01883 bInserted = true;
01884 }
01885 iKey->second = a_pValue;
01886 return bInserted ? SI_INSERTED : SI_UPDATED;
01887 }
01888
01889 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01890 const SI_CHAR *
01891 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetValue(
01892 const SI_CHAR * a_pSection,
01893 const SI_CHAR * a_pKey,
01894 const SI_CHAR * a_pDefault,
01895 bool * a_pHasMultiple
01896 ) const
01897 {
01898 if (a_pHasMultiple) {
01899 *a_pHasMultiple = false;
01900 }
01901 if (!a_pSection || !a_pKey) {
01902 return a_pDefault;
01903 }
01904 typename TSection::const_iterator iSection = m_data.find(a_pSection);
01905 if (iSection == m_data.end()) {
01906 return a_pDefault;
01907 }
01908 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
01909 if (iKeyVal == iSection->second.end()) {
01910 return a_pDefault;
01911 }
01912
01913
01914 if (m_bAllowMultiKey && a_pHasMultiple) {
01915 typename TKeyVal::const_iterator iTemp = iKeyVal;
01916 if (++iTemp != iSection->second.end()) {
01917 if (!IsLess(a_pKey, iTemp->first.pItem)) {
01918 *a_pHasMultiple = true;
01919 }
01920 }
01921 }
01922
01923 return iKeyVal->second;
01924 }
01925
01926 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01927 long
01928 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetLongValue(
01929 const SI_CHAR * a_pSection,
01930 const SI_CHAR * a_pKey,
01931 long a_nDefault,
01932 bool * a_pHasMultiple
01933 ) const
01934 {
01935
01936 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
01937 if (!pszValue || !*pszValue) return a_nDefault;
01938
01939
01940 char szValue[64] = { 0 };
01941 SI_CONVERTER c(m_bStoreIsUtf8);
01942 if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
01943 return a_nDefault;
01944 }
01945
01946
01947 long nValue = a_nDefault;
01948 char * pszSuffix = szValue;
01949 if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
01950 if (!szValue[2]) return a_nDefault;
01951 nValue = strtol(&szValue[2], &pszSuffix, 16);
01952 }
01953 else {
01954 nValue = strtol(szValue, &pszSuffix, 10);
01955 }
01956
01957
01958 if (*pszSuffix) {
01959 return a_nDefault;
01960 }
01961
01962 return nValue;
01963 }
01964
01965 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01966 SI_Error
01967 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
01968 const SI_CHAR * a_pSection,
01969 const SI_CHAR * a_pKey,
01970 long a_nValue,
01971 const SI_CHAR * a_pComment,
01972 bool a_bUseHex,
01973 bool a_bForceReplace
01974 )
01975 {
01976
01977 if (!a_pSection || !a_pKey) return SI_FAIL;
01978
01979
01980 char szInput[64];
01981 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
01982 sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
01983 #else // !__STDC_WANT_SECURE_LIB__
01984 sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
01985 #endif // __STDC_WANT_SECURE_LIB__
01986
01987
01988 SI_CHAR szOutput[64];
01989 SI_CONVERTER c(m_bStoreIsUtf8);
01990 c.ConvertFromStore(szInput, strlen(szInput) + 1,
01991 szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
01992
01993
01994 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
01995 }
01996
01997 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
01998 bool
01999 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetBoolValue(
02000 const SI_CHAR * a_pSection,
02001 const SI_CHAR * a_pKey,
02002 bool a_bDefault,
02003 bool * a_pHasMultiple
02004 ) const
02005 {
02006
02007 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
02008 if (!pszValue || !*pszValue) return a_bDefault;
02009
02010
02011 switch (pszValue[0]) {
02012 case 't': case 'T':
02013 case 'y': case 'Y':
02014 case '1':
02015 return true;
02016
02017 case 'f': case 'F':
02018 case 'n': case 'N':
02019 case '0':
02020 return false;
02021
02022 case 'o': case 'O':
02023 if (pszValue[1] == 'n' || pszValue[1] == 'N') return true;
02024 if (pszValue[1] == 'f' || pszValue[1] == 'F') return false;
02025 break;
02026 }
02027
02028
02029 return a_bDefault;
02030 }
02031
02032 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02033 SI_Error
02034 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetBoolValue(
02035 const SI_CHAR * a_pSection,
02036 const SI_CHAR * a_pKey,
02037 bool a_bValue,
02038 const SI_CHAR * a_pComment,
02039 bool a_bForceReplace
02040 )
02041 {
02042
02043 if (!a_pSection || !a_pKey) return SI_FAIL;
02044
02045
02046 const char * pszInput = a_bValue ? "true" : "false";
02047
02048
02049 SI_CHAR szOutput[64];
02050 SI_CONVERTER c(m_bStoreIsUtf8);
02051 c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
02052 szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
02053
02054
02055 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
02056 }
02057
02058 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02059 bool
02060 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllValues(
02061 const SI_CHAR * a_pSection,
02062 const SI_CHAR * a_pKey,
02063 TNamesDepend & a_values
02064 ) const
02065 {
02066 a_values.clear();
02067
02068 if (!a_pSection || !a_pKey) {
02069 return false;
02070 }
02071 typename TSection::const_iterator iSection = m_data.find(a_pSection);
02072 if (iSection == m_data.end()) {
02073 return false;
02074 }
02075 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
02076 if (iKeyVal == iSection->second.end()) {
02077 return false;
02078 }
02079
02080
02081 a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
02082 if (m_bAllowMultiKey) {
02083 ++iKeyVal;
02084 while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
02085 a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
02086 ++iKeyVal;
02087 }
02088 }
02089
02090 return true;
02091 }
02092
02093 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02094 int
02095 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSectionSize(
02096 const SI_CHAR * a_pSection
02097 ) const
02098 {
02099 if (!a_pSection) {
02100 return -1;
02101 }
02102
02103 typename TSection::const_iterator iSection = m_data.find(a_pSection);
02104 if (iSection == m_data.end()) {
02105 return -1;
02106 }
02107 const TKeyVal & section = iSection->second;
02108
02109
02110
02111 if (!m_bAllowMultiKey || section.empty()) {
02112 return (int) section.size();
02113 }
02114
02115
02116 int nCount = 0;
02117 const SI_CHAR * pLastKey = NULL;
02118 typename TKeyVal::const_iterator iKeyVal = section.begin();
02119 for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
02120 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
02121 ++nCount;
02122 pLastKey = iKeyVal->first.pItem;
02123 }
02124 }
02125 return nCount;
02126 }
02127
02128 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02129 const typename CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::TKeyVal *
02130 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSection(
02131 const SI_CHAR * a_pSection
02132 ) const
02133 {
02134 if (a_pSection) {
02135 typename TSection::const_iterator i = m_data.find(a_pSection);
02136 if (i != m_data.end()) {
02137 return &(i->second);
02138 }
02139 }
02140 return 0;
02141 }
02142
02143 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02144 void
02145 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllSections(
02146 TNamesDepend & a_names
02147 ) const
02148 {
02149 a_names.clear();
02150 typename TSection::const_iterator i = m_data.begin();
02151 for (int n = 0; i != m_data.end(); ++i, ++n ) {
02152 a_names.push_back(i->first);
02153 }
02154 }
02155
02156 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02157 bool
02158 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllKeys(
02159 const SI_CHAR * a_pSection,
02160 TNamesDepend & a_names
02161 ) const
02162 {
02163 a_names.clear();
02164
02165 if (!a_pSection) {
02166 return false;
02167 }
02168
02169 typename TSection::const_iterator iSection = m_data.find(a_pSection);
02170 if (iSection == m_data.end()) {
02171 return false;
02172 }
02173
02174 const TKeyVal & section = iSection->second;
02175 const SI_CHAR * pLastKey = NULL;
02176 typename TKeyVal::const_iterator iKeyVal = section.begin();
02177 for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) {
02178 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
02179 a_names.push_back(iKeyVal->first);
02180 pLastKey = iKeyVal->first.pItem;
02181 }
02182 }
02183
02184 return true;
02185 }
02186
02187 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02188 SI_Error
02189 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
02190 const char * a_pszFile,
02191 bool a_bAddSignature
02192 ) const
02193 {
02194 FILE * fp = NULL;
02195 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
02196 fopen_s(&fp, a_pszFile, "wb");
02197 #else // !__STDC_WANT_SECURE_LIB__
02198 fp = fopen(a_pszFile, "wb");
02199 #endif // __STDC_WANT_SECURE_LIB__
02200 if (!fp) return SI_FILE;
02201 SI_Error rc = SaveFile(fp, a_bAddSignature);
02202 fclose(fp);
02203 return rc;
02204 }
02205
02206 #ifdef SI_HAS_WIDE_FILE
02207 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02208 SI_Error
02209 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
02210 const SI_WCHAR_T * a_pwszFile,
02211 bool a_bAddSignature
02212 ) const
02213 {
02214 #ifdef _WIN32
02215 FILE * fp = _wfopen(a_pwszFile, L"wb");
02216 if (!fp) return SI_FILE;
02217 SI_Error rc = SaveFile(fp, a_bAddSignature);
02218 fclose(fp);
02219 return rc;
02220 #else // !_WIN32 (therefore SI_CONVERT_ICU)
02221 char szFile[256];
02222 u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
02223 return SaveFile(szFile, a_bAddSignature);
02224 #endif // _WIN32
02225 }
02226 #endif // SI_HAS_WIDE_FILE
02227
02228 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02229 SI_Error
02230 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
02231 FILE * a_pFile,
02232 bool a_bAddSignature
02233 ) const
02234 {
02235 FileWriter writer(a_pFile);
02236 return Save(writer, a_bAddSignature);
02237 }
02238
02239 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02240 SI_Error
02241 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
02242 OutputWriter & a_oOutput,
02243 bool a_bAddSignature
02244 ) const
02245 {
02246 Converter convert(m_bStoreIsUtf8);
02247
02248
02249 if (m_bStoreIsUtf8 && a_bAddSignature) {
02250 a_oOutput.Write(SI_UTF8_SIGNATURE);
02251 }
02252
02253
02254 TNamesDepend oSections;
02255 GetAllSections(oSections);
02256 #if defined(_MSC_VER) && _MSC_VER <= 1200
02257 oSections.sort();
02258 #elif defined(__BORLANDC__)
02259 oSections.sort(Entry::LoadOrder());
02260 #else
02261 oSections.sort(typename Entry::LoadOrder());
02262 #endif
02263
02264
02265 bool bNeedNewLine = false;
02266 if (m_pFileComment) {
02267 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
02268 return SI_FAIL;
02269 }
02270 bNeedNewLine = true;
02271 }
02272
02273
02274 typename TNamesDepend::const_iterator iSection = oSections.begin();
02275 for ( ; iSection != oSections.end(); ++iSection ) {
02276
02277 if (iSection->pComment) {
02278 if (bNeedNewLine) {
02279 a_oOutput.Write(SI_NEWLINE_A);
02280 a_oOutput.Write(SI_NEWLINE_A);
02281 }
02282 if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
02283 return SI_FAIL;
02284 }
02285 bNeedNewLine = false;
02286 }
02287
02288 if (bNeedNewLine) {
02289 a_oOutput.Write(SI_NEWLINE_A);
02290 a_oOutput.Write(SI_NEWLINE_A);
02291 bNeedNewLine = false;
02292 }
02293
02294
02295 if (*iSection->pItem) {
02296 if (!convert.ConvertToStore(iSection->pItem)) {
02297 return SI_FAIL;
02298 }
02299 a_oOutput.Write("[");
02300 a_oOutput.Write(convert.Data());
02301 a_oOutput.Write("]");
02302 a_oOutput.Write(SI_NEWLINE_A);
02303 }
02304
02305
02306 TNamesDepend oKeys;
02307 GetAllKeys(iSection->pItem, oKeys);
02308 #if defined(_MSC_VER) && _MSC_VER <= 1200
02309 oKeys.sort();
02310 #elif defined(__BORLANDC__)
02311 oKeys.sort(Entry::LoadOrder());
02312 #else
02313 oKeys.sort(typename Entry::LoadOrder());
02314 #endif
02315
02316
02317 typename TNamesDepend::const_iterator iKey = oKeys.begin();
02318 for ( ; iKey != oKeys.end(); ++iKey) {
02319
02320 TNamesDepend oValues;
02321 GetAllValues(iSection->pItem, iKey->pItem, oValues);
02322
02323 typename TNamesDepend::const_iterator iValue = oValues.begin();
02324 for ( ; iValue != oValues.end(); ++iValue) {
02325
02326 if (iValue->pComment) {
02327 a_oOutput.Write(SI_NEWLINE_A);
02328 if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
02329 return SI_FAIL;
02330 }
02331 }
02332
02333
02334 if (!convert.ConvertToStore(iKey->pItem)) {
02335 return SI_FAIL;
02336 }
02337 a_oOutput.Write(convert.Data());
02338
02339
02340 if (!convert.ConvertToStore(iValue->pItem)) {
02341 return SI_FAIL;
02342 }
02343 a_oOutput.Write(m_bSpaces ? " = " : "=");
02344 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
02345
02346
02347 a_oOutput.Write("<<<SI-END-OF-MULTILINE-TEXT" SI_NEWLINE_A);
02348 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
02349 return SI_FAIL;
02350 }
02351 a_oOutput.Write("SI-END-OF-MULTILINE-TEXT");
02352 }
02353 else {
02354 a_oOutput.Write(convert.Data());
02355 }
02356 a_oOutput.Write(SI_NEWLINE_A);
02357 }
02358 }
02359
02360 bNeedNewLine = true;
02361 }
02362
02363 return SI_OK;
02364 }
02365
02366 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02367 bool
02368 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::OutputMultiLineText(
02369 OutputWriter & a_oOutput,
02370 Converter & a_oConverter,
02371 const SI_CHAR * a_pText
02372 ) const
02373 {
02374 const SI_CHAR * pEndOfLine;
02375 SI_CHAR cEndOfLineChar = *a_pText;
02376 while (cEndOfLineChar) {
02377
02378 pEndOfLine = a_pText;
02379 for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) ;
02380 cEndOfLineChar = *pEndOfLine;
02381
02382
02383 *const_cast<SI_CHAR*>(pEndOfLine) = 0;
02384 if (!a_oConverter.ConvertToStore(a_pText)) {
02385 return false;
02386 }
02387 *const_cast<SI_CHAR*>(pEndOfLine) = cEndOfLineChar;
02388 a_pText += (pEndOfLine - a_pText) + 1;
02389 a_oOutput.Write(a_oConverter.Data());
02390 a_oOutput.Write(SI_NEWLINE_A);
02391 }
02392 return true;
02393 }
02394
02395 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02396 bool
02397 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Delete(
02398 const SI_CHAR * a_pSection,
02399 const SI_CHAR * a_pKey,
02400 bool a_bRemoveEmpty
02401 )
02402 {
02403 if (!a_pSection) {
02404 return false;
02405 }
02406
02407 typename TSection::iterator iSection = m_data.find(a_pSection);
02408 if (iSection == m_data.end()) {
02409 return false;
02410 }
02411
02412
02413 if (a_pKey) {
02414 typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
02415 if (iKeyVal == iSection->second.end()) {
02416 return false;
02417 }
02418
02419
02420 typename TKeyVal::iterator iDelete;
02421 do {
02422 iDelete = iKeyVal++;
02423
02424 DeleteString(iDelete->first.pItem);
02425 DeleteString(iDelete->second);
02426 iSection->second.erase(iDelete);
02427 }
02428 while (iKeyVal != iSection->second.end()
02429 && !IsLess(a_pKey, iKeyVal->first.pItem));
02430
02431
02432
02433
02434 if (!a_bRemoveEmpty || !iSection->second.empty()) {
02435 return true;
02436 }
02437 }
02438 else {
02439
02440
02441 typename TKeyVal::iterator iKeyVal = iSection->second.begin();
02442 for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
02443 DeleteString(iKeyVal->first.pItem);
02444 DeleteString(iKeyVal->second);
02445 }
02446 }
02447
02448
02449 DeleteString(iSection->first.pItem);
02450 m_data.erase(iSection);
02451
02452 return true;
02453 }
02454
02455 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
02456 void
02457 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteString(
02458 const SI_CHAR * a_pString
02459 )
02460 {
02461
02462
02463
02464 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
02465 typename TNamesDepend::iterator i = m_strings.begin();
02466 for (;i != m_strings.end(); ++i) {
02467 if (a_pString == i->pItem) {
02468 delete[] const_cast<SI_CHAR*>(i->pItem);
02469 m_strings.erase(i);
02470 break;
02471 }
02472 }
02473 }
02474 }
02475
02476
02477
02478
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
02491 # ifdef _WIN32
02492 # define SI_CONVERT_WIN32
02493 # else
02494 # define SI_CONVERT_GENERIC
02495 # endif
02496 #endif
02497
02503 template<class SI_CHAR>
02504 struct SI_GenericCase {
02505 bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
02506 long cmp;
02507 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
02508 cmp = (long) *pLeft - (long) *pRight;
02509 if (cmp != 0) {
02510 return cmp < 0;
02511 }
02512 }
02513 return *pRight != 0;
02514 }
02515 };
02516
02523 template<class SI_CHAR>
02524 struct SI_GenericNoCase {
02525 inline SI_CHAR locase(SI_CHAR ch) const {
02526 return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a');
02527 }
02528 bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
02529 long cmp;
02530 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
02531 cmp = (long) locase(*pLeft) - (long) locase(*pRight);
02532 if (cmp != 0) {
02533 return cmp < 0;
02534 }
02535 }
02536 return *pRight != 0;
02537 }
02538 };
02539
02543 template<class SI_CHAR>
02544 class SI_ConvertA {
02545 bool m_bStoreIsUtf8;
02546 protected:
02547 SI_ConvertA() { }
02548 public:
02549 SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
02550
02551
02552 SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); }
02553 SI_ConvertA & operator=(const SI_ConvertA & rhs) {
02554 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
02555 return *this;
02556 }
02557
02571 size_t SizeFromStore(
02572 const char * a_pInputData,
02573 size_t a_uInputDataLen)
02574 {
02575 (void)a_pInputData;
02576 SI_ASSERT(a_uInputDataLen != (size_t) -1);
02577
02578
02579 return a_uInputDataLen;
02580 }
02581
02595 bool ConvertFromStore(
02596 const char * a_pInputData,
02597 size_t a_uInputDataLen,
02598 SI_CHAR * a_pOutputData,
02599 size_t a_uOutputDataSize)
02600 {
02601
02602 if (a_uInputDataLen > a_uOutputDataSize) {
02603 return false;
02604 }
02605 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
02606 return true;
02607 }
02608
02619 size_t SizeToStore(
02620 const SI_CHAR * a_pInputData)
02621 {
02622
02623 return strlen((const char *)a_pInputData) + 1;
02624 }
02625
02639 bool ConvertToStore(
02640 const SI_CHAR * a_pInputData,
02641 char * a_pOutputData,
02642 size_t a_uOutputDataSize)
02643 {
02644
02645 size_t uInputLen = strlen((const char *)a_pInputData) + 1;
02646 if (uInputLen > a_uOutputDataSize) {
02647 return false;
02648 }
02649
02650
02651 memcpy(a_pOutputData, a_pInputData, uInputLen);
02652 return true;
02653 }
02654 };
02655
02656
02657
02658
02659
02660 #ifdef SI_CONVERT_GENERIC
02661
02662 #define SI_Case SI_GenericCase
02663 #define SI_NoCase SI_GenericNoCase
02664
02665 #include <wchar.h>
02666 #include "ConvertUTF.h"
02667
02672 template<class SI_CHAR>
02673 class SI_ConvertW {
02674 bool m_bStoreIsUtf8;
02675 protected:
02676 SI_ConvertW() { }
02677 public:
02678 SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
02679
02680
02681 SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
02682 SI_ConvertW & operator=(const SI_ConvertW & rhs) {
02683 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
02684 return *this;
02685 }
02686
02700 size_t SizeFromStore(
02701 const char * a_pInputData,
02702 size_t a_uInputDataLen)
02703 {
02704 SI_ASSERT(a_uInputDataLen != (size_t) -1);
02705
02706 if (m_bStoreIsUtf8) {
02707
02708
02709
02710 return a_uInputDataLen;
02711 }
02712 else {
02713 return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
02714 }
02715 }
02716
02730 bool ConvertFromStore(
02731 const char * a_pInputData,
02732 size_t a_uInputDataLen,
02733 SI_CHAR * a_pOutputData,
02734 size_t a_uOutputDataSize)
02735 {
02736 if (m_bStoreIsUtf8) {
02737
02738
02739
02740
02741
02742 ConversionResult retval;
02743 const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
02744 if (sizeof(wchar_t) == sizeof(UTF32)) {
02745 UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
02746 retval = ConvertUTF8toUTF32(
02747 &pUtf8, pUtf8 + a_uInputDataLen,
02748 &pUtf32, pUtf32 + a_uOutputDataSize,
02749 lenientConversion);
02750 }
02751 else if (sizeof(wchar_t) == sizeof(UTF16)) {
02752 UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
02753 retval = ConvertUTF8toUTF16(
02754 &pUtf8, pUtf8 + a_uInputDataLen,
02755 &pUtf16, pUtf16 + a_uOutputDataSize,
02756 lenientConversion);
02757 }
02758 return retval == conversionOK;
02759 }
02760 else {
02761 size_t retval = mbstowcs(a_pOutputData,
02762 a_pInputData, a_uOutputDataSize);
02763 return retval != (size_t)(-1);
02764 }
02765 }
02766
02777 size_t SizeToStore(
02778 const SI_CHAR * a_pInputData)
02779 {
02780 if (m_bStoreIsUtf8) {
02781
02782 size_t uLen = 0;
02783 while (a_pInputData[uLen]) {
02784 ++uLen;
02785 }
02786 return (6 * uLen) + 1;
02787 }
02788 else {
02789 size_t uLen = wcstombs(NULL, a_pInputData, 0);
02790 if (uLen == (size_t)(-1)) {
02791 return uLen;
02792 }
02793 return uLen + 1;
02794 }
02795 }
02796
02810 bool ConvertToStore(
02811 const SI_CHAR * a_pInputData,
02812 char * a_pOutputData,
02813 size_t a_uOutputDataSize
02814 )
02815 {
02816 if (m_bStoreIsUtf8) {
02817
02818 size_t uInputLen = 0;
02819 while (a_pInputData[uInputLen]) {
02820 ++uInputLen;
02821 }
02822 ++uInputLen;
02823
02824
02825
02826
02827
02828
02829 ConversionResult retval;
02830 UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
02831 if (sizeof(wchar_t) == sizeof(UTF32)) {
02832 const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
02833 retval = ConvertUTF32toUTF8(
02834 &pUtf32, pUtf32 + uInputLen,
02835 &pUtf8, pUtf8 + a_uOutputDataSize,
02836 lenientConversion);
02837 }
02838 else if (sizeof(wchar_t) == sizeof(UTF16)) {
02839 const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
02840 retval = ConvertUTF16toUTF8(
02841 &pUtf16, pUtf16 + uInputLen,
02842 &pUtf8, pUtf8 + a_uOutputDataSize,
02843 lenientConversion);
02844 }
02845 return retval == conversionOK;
02846 }
02847 else {
02848 size_t retval = wcstombs(a_pOutputData,
02849 a_pInputData, a_uOutputDataSize);
02850 return retval != (size_t) -1;
02851 }
02852 }
02853 };
02854
02855 #endif // SI_CONVERT_GENERIC
02856
02857
02858
02859
02860
02861 #ifdef SI_CONVERT_ICU
02862
02863 #define SI_Case SI_GenericCase
02864 #define SI_NoCase SI_GenericNoCase
02865
02866 #include <unicode/ucnv.h>
02867
02871 template<class SI_CHAR>
02872 class SI_ConvertW {
02873 const char * m_pEncoding;
02874 UConverter * m_pConverter;
02875 protected:
02876 SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { }
02877 public:
02878 SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) {
02879 m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL;
02880 }
02881
02882
02883 SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
02884 SI_ConvertW & operator=(const SI_ConvertW & rhs) {
02885 m_pEncoding = rhs.m_pEncoding;
02886 m_pConverter = NULL;
02887 return *this;
02888 }
02889 ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); }
02890
02904 size_t SizeFromStore(
02905 const char * a_pInputData,
02906 size_t a_uInputDataLen)
02907 {
02908 SI_ASSERT(a_uInputDataLen != (size_t) -1);
02909
02910 UErrorCode nError;
02911
02912 if (!m_pConverter) {
02913 nError = U_ZERO_ERROR;
02914 m_pConverter = ucnv_open(m_pEncoding, &nError);
02915 if (U_FAILURE(nError)) {
02916 return (size_t) -1;
02917 }
02918 }
02919
02920 nError = U_ZERO_ERROR;
02921 ucnv_resetToUnicode(m_pConverter);
02922 int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
02923 a_pInputData, (int32_t) a_uInputDataLen, &nError);
02924 if (nError != U_BUFFER_OVERFLOW_ERROR) {
02925 return (size_t) -1;
02926 }
02927
02928 return (size_t) nLen;
02929 }
02930
02944 bool ConvertFromStore(
02945 const char * a_pInputData,
02946 size_t a_uInputDataLen,
02947 UChar * a_pOutputData,
02948 size_t a_uOutputDataSize)
02949 {
02950 UErrorCode nError;
02951
02952 if (!m_pConverter) {
02953 nError = U_ZERO_ERROR;
02954 m_pConverter = ucnv_open(m_pEncoding, &nError);
02955 if (U_FAILURE(nError)) {
02956 return false;
02957 }
02958 }
02959
02960 nError = U_ZERO_ERROR;
02961 ucnv_resetToUnicode(m_pConverter);
02962 ucnv_toUChars(m_pConverter,
02963 a_pOutputData, (int32_t) a_uOutputDataSize,
02964 a_pInputData, (int32_t) a_uInputDataLen, &nError);
02965 if (U_FAILURE(nError)) {
02966 return false;
02967 }
02968
02969 return true;
02970 }
02971
02982 size_t SizeToStore(
02983 const UChar * a_pInputData)
02984 {
02985 UErrorCode nError;
02986
02987 if (!m_pConverter) {
02988 nError = U_ZERO_ERROR;
02989 m_pConverter = ucnv_open(m_pEncoding, &nError);
02990 if (U_FAILURE(nError)) {
02991 return (size_t) -1;
02992 }
02993 }
02994
02995 nError = U_ZERO_ERROR;
02996 ucnv_resetFromUnicode(m_pConverter);
02997 int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
02998 a_pInputData, -1, &nError);
02999 if (nError != U_BUFFER_OVERFLOW_ERROR) {
03000 return (size_t) -1;
03001 }
03002
03003 return (size_t) nLen + 1;
03004 }
03005
03019 bool ConvertToStore(
03020 const UChar * a_pInputData,
03021 char * a_pOutputData,
03022 size_t a_uOutputDataSize)
03023 {
03024 UErrorCode nError;
03025
03026 if (!m_pConverter) {
03027 nError = U_ZERO_ERROR;
03028 m_pConverter = ucnv_open(m_pEncoding, &nError);
03029 if (U_FAILURE(nError)) {
03030 return false;
03031 }
03032 }
03033
03034 nError = U_ZERO_ERROR;
03035 ucnv_resetFromUnicode(m_pConverter);
03036 ucnv_fromUChars(m_pConverter,
03037 a_pOutputData, (int32_t) a_uOutputDataSize,
03038 a_pInputData, -1, &nError);
03039 if (U_FAILURE(nError)) {
03040 return false;
03041 }
03042
03043 return true;
03044 }
03045 };
03046
03047 #endif // SI_CONVERT_ICU
03048
03049
03050
03051
03052
03053 #ifdef SI_CONVERT_WIN32
03054
03055 #define SI_Case SI_GenericCase
03056
03057
03058 #ifdef _WIN32_WCE
03059 # ifndef SI_NO_MBCS
03060 # define SI_NO_MBCS
03061 # endif
03062 #endif
03063
03064 #include <windows.h>
03065 #ifdef SI_NO_MBCS
03066 # define SI_NoCase SI_GenericNoCase
03067 #else // !SI_NO_MBCS
03068
03076 #include <mbstring.h>
03077 template<class SI_CHAR>
03078 struct SI_NoCase {
03079 bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
03080 if (sizeof(SI_CHAR) == sizeof(char)) {
03081 return _mbsicmp((const unsigned char *)pLeft,
03082 (const unsigned char *)pRight) < 0;
03083 }
03084 if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
03085 return _wcsicmp((const wchar_t *)pLeft,
03086 (const wchar_t *)pRight) < 0;
03087 }
03088 return SI_GenericNoCase<SI_CHAR>()(pLeft, pRight);
03089 }
03090 };
03091 #endif // SI_NO_MBCS
03092
03099 template<class SI_CHAR>
03100 class SI_ConvertW {
03101 UINT m_uCodePage;
03102 protected:
03103 SI_ConvertW() { }
03104 public:
03105 SI_ConvertW(bool a_bStoreIsUtf8) {
03106 m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
03107 }
03108
03109
03110 SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
03111 SI_ConvertW & operator=(const SI_ConvertW & rhs) {
03112 m_uCodePage = rhs.m_uCodePage;
03113 return *this;
03114 }
03115
03129 size_t SizeFromStore(
03130 const char * a_pInputData,
03131 size_t a_uInputDataLen)
03132 {
03133 SI_ASSERT(a_uInputDataLen != (size_t) -1);
03134
03135 int retval = MultiByteToWideChar(
03136 m_uCodePage, 0,
03137 a_pInputData, (int) a_uInputDataLen,
03138 0, 0);
03139 return (size_t)(retval > 0 ? retval : -1);
03140 }
03141
03155 bool ConvertFromStore(
03156 const char * a_pInputData,
03157 size_t a_uInputDataLen,
03158 SI_CHAR * a_pOutputData,
03159 size_t a_uOutputDataSize)
03160 {
03161 int nSize = MultiByteToWideChar(
03162 m_uCodePage, 0,
03163 a_pInputData, (int) a_uInputDataLen,
03164 (wchar_t *) a_pOutputData, (int) a_uOutputDataSize);
03165 return (nSize > 0);
03166 }
03167
03178 size_t SizeToStore(
03179 const SI_CHAR * a_pInputData)
03180 {
03181 int retval = WideCharToMultiByte(
03182 m_uCodePage, 0,
03183 (const wchar_t *) a_pInputData, -1,
03184 0, 0, 0, 0);
03185 return (size_t) (retval > 0 ? retval : -1);
03186 }
03187
03201 bool ConvertToStore(
03202 const SI_CHAR * a_pInputData,
03203 char * a_pOutputData,
03204 size_t a_uOutputDataSize)
03205 {
03206 int retval = WideCharToMultiByte(
03207 m_uCodePage, 0,
03208 (const wchar_t *) a_pInputData, -1,
03209 a_pOutputData, (int) a_uOutputDataSize, 0, 0);
03210 return retval > 0;
03211 }
03212 };
03213
03214 #endif // SI_CONVERT_WIN32
03215
03216
03217
03218
03219
03220
03221 typedef CSimpleIniTempl<char,
03222 SI_NoCase<char>,SI_ConvertA<char> > CSimpleIniA;
03223 typedef CSimpleIniTempl<char,
03224 SI_Case<char>,SI_ConvertA<char> > CSimpleIniCaseA;
03225
03226 #if defined(SI_CONVERT_ICU)
03227 typedef CSimpleIniTempl<UChar,
03228 SI_NoCase<UChar>,SI_ConvertW<UChar> > CSimpleIniW;
03229 typedef CSimpleIniTempl<UChar,
03230 SI_Case<UChar>,SI_ConvertW<UChar> > CSimpleIniCaseW;
03231 #else
03232 typedef CSimpleIniTempl<wchar_t,
03233 SI_NoCase<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniW;
03234 typedef CSimpleIniTempl<wchar_t,
03235 SI_Case<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniCaseW;
03236 #endif
03237
03238 #ifdef _UNICODE
03239 # define CSimpleIni CSimpleIniW
03240 # define CSimpleIniCase CSimpleIniCaseW
03241 # define SI_NEWLINE SI_NEWLINE_W
03242 #else // !_UNICODE
03243 # define CSimpleIni CSimpleIniA
03244 # define CSimpleIniCase CSimpleIniCaseA
03245 # define SI_NEWLINE SI_NEWLINE_A
03246 #endif // _UNICODE
03247
03248 #ifdef _MSC_VER
03249 # pragma warning (pop)
03250 #endif
03251
03252 #endif // INCLUDED_SimpleIni_h
03253