4 <tr><th>Library <td>SimpleIni
5 <tr><th>File <td>SimpleIni.h
6 <tr><th>Author <td>Brodie Thiesfield [code at jellycan dot com]
7 <tr><th>Source <td>http://code.jellycan.com/simpleini/
8 <tr><th>Version <td>4.5
11 Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation.
13 @section intro INTRODUCTION
15 This component allows an INI-style configuration file to be used on both
16 Windows and Linux/Unix. It is fast, simple and source code using this
17 component will compile unchanged on either OS.
20 @section features FEATURES
22 - MIT Licence allows free use in all software (including GPL and commercial)
23 - multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix)
24 - loading and saving of INI-style configuration files
25 - configuration files can have any newline format on all platforms
26 - liberal acceptance of file format
27 - key/values with no section
28 - removal of whitespace around sections, keys and values
29 - support for multi-line values (values with embedded newline characters)
30 - optional support for multiple keys with the same name
31 - optional case-insensitive sections and keys (for ASCII characters only)
32 - saves files with sections and keys in the same order as they were loaded
33 - preserves comments on the file, section and keys where possible.
34 - supports both char or wchar_t programming interfaces
35 - supports both MBCS (system locale) and UTF-8 file encodings
36 - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file
37 - support for non-ASCII characters in section, keys, values and comments
38 - support for non-standard character types or file encodings
39 via user-written converter classes
40 - support for adding/modifying values programmatically
41 - compiles cleanly in the following compilers:
42 - Windows/VC6 (warning level 3)
43 - Windows/VC.NET 2003 (warning level 4)
44 - Windows/VC 2005 (warning level 4)
48 @section usage USAGE SUMMARY
50 -# Define the appropriate symbol for the converter you wish to use and
51 include the SimpleIni.h header file. If no specific converter is defined
52 then the default converter is used. The default conversion mode uses
53 SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other
54 platforms. If you are using ICU then SI_CONVERT_ICU is supported on all
56 -# Declare an instance the appropriate class. Note that the following
57 definitions are just shortcuts for commonly used types. Other types
58 (PRUnichar, unsigned short, unsigned char) are also possible.
60 <tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef
61 <tr><th>SI_CONVERT_GENERIC
62 <tr><td>char <td>No <td>Yes <td>Yes #1 <td>CSimpleIniA
63 <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
64 <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
65 <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
66 <tr><th>SI_CONVERT_WIN32
67 <tr><td>char <td>No <td>No #2 <td>Yes <td>CSimpleIniA
68 <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
69 <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
70 <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
71 <tr><th>SI_CONVERT_ICU
72 <tr><td>char <td>No <td>Yes <td>Yes <td>CSimpleIniA
73 <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
74 <tr><td>UChar <td>No <td>Yes <td>Yes <td>CSimpleIniW
75 <tr><td>UChar <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
77 #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.<br>
78 #2 Only affects Windows. On Windows this uses MBCS functions and
79 so may fold case incorrectly leading to uncertain results.
80 -# Call Load() or LoadFile() to load and parse the INI configuration file
81 -# Access and modify the data of the file using the following functions
83 <tr><td>GetAllSections <td>Return all section names
84 <tr><td>GetAllKeys <td>Return all key names within a section
85 <tr><td>GetAllValues <td>Return all values within a section & key
86 <tr><td>GetSection <td>Return all key names and values in a section
87 <tr><td>GetSectionSize <td>Return the number of keys in a section
88 <tr><td>GetValue <td>Return a value for a section & key
89 <tr><td>SetValue <td>Add or update a value for a section & key
90 <tr><td>Delete <td>Remove a section, or a key from a section
92 -# Call Save() or SaveFile() to save the INI configuration data
94 @section iostreams IO STREAMS
96 SimpleIni supports reading from and writing to STL IO streams. Enable this
97 by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header
98 file. Ensure that if the streams are backed by a file (e.g. ifstream or
99 ofstream) then the flag ios_base::binary has been used when the file was
102 @section multiline MULTI-LINE VALUES
104 Values that span multiple lines are created using the following format.
108 .... multiline value ....
113 - The text used for ENDTAG can be anything and is used to find
114 where the multi-line text ends.
115 - The newline after ENDTAG in the start tag, and the newline
116 before ENDTAG in the end tag is not included in the data value.
117 - The ending tag must be on it's own line with no whitespace before
119 - The multi-line value is modified at load so that each line in the value
120 is delimited by a single '\\n' character on all platforms. At save time
121 it will be converted into the newline format used by the current
124 @section comments COMMENTS
126 Comments are preserved in the file within the following restrictions:
127 - Every file may have a single "file comment". It must start with the
128 first character in the file, and will end with the first non-comment
130 - Every section may have a single "section comment". It will start
131 with the first comment line following the file comment, or the last
132 data entry. It ends at the beginning of the section.
133 - Every key may have a single "key comment". This comment will start
134 with the first comment line following the section start, or the file
135 comment if there is no section name.
136 - MultiKey entries may have only a single comment and will take the
137 comment associated with the first key found.
138 - Comments are set at the time that the file, section or key is first
139 created. The only way to modify a comment on a section or a key is to
140 delete that entry and recreate it with the new comment. There is no
141 way to change the file comment.
143 @section save SAVE ORDER
145 The sections and keys are written out in the same order as they were
146 read in from the file. Sections and keys added to the data after the
147 file has been loaded will be added to the end of the file when it is
148 written. There is no way to specify the location of a section or key
149 other than in first-created, first-saved order.
153 - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
154 Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
155 - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
156 - When using SI_CONVERT_ICU, ICU header files must be on the include
157 path and icuuc.lib must be linked in.
158 - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
159 you should use SI_CONVERT_GENERIC.
160 - The collation (sorting) order used for sections and keys returned from
161 iterators is NOT DEFINED. If collation order of the text is important
162 then it should be done yourself by either supplying a replacement
163 SI_STRLESS class, or by sorting the strings external to this library.
164 - Usage of the <mbstring.h> header on Windows can be disabled by defining
165 SI_NO_MBCS. This is defined automatically on Windows CE platforms.
168 @section licence MIT LICENCE
170 The licence text below is the boilerplate "MIT Licence" used from:
171 http://www.opensource.org/licenses/mit-license.php
173 Copyright (c) 2006, Brodie Thiesfield
175 Permission is hereby granted, free of charge, to any person obtaining a copy
176 of this software and associated documentation files (the "Software"), to deal
177 in the Software without restriction, including without limitation the rights
178 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
179 copies of the Software, and to permit persons to whom the Software is furnished
180 to do so, subject to the following conditions:
182 The above copyright notice and this permission notice shall be included in
183 all copies or substantial portions of the Software.
185 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
186 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
187 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
188 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
189 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
190 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
193 #ifndef INCLUDED_SimpleIni_h
194 #define INCLUDED_SimpleIni_h
196 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
200 // Disable these warnings in MSVC:
201 // 4127 "conditional expression is constant" as the conversion classes trigger
202 // it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
203 // be optimized away in a release build.
204 // 4503 'insert' : decorated name length exceeded, name was truncated
205 // 4702 "unreachable code" as the MS STL header causes it in release mode.
206 // Again, the code causing the warning will be cleaned up by the compiler.
207 // 4786 "identifier truncated to 256 characters" as this is thrown hundreds
208 // of times VC6 as soon as STL is used.
210 # pragma warning (push)
211 # pragma warning (disable: 4127 4503 4702 4786)
220 #ifdef SI_SUPPORT_IOSTREAMS
222 #endif // SI_SUPPORT_IOSTREAMS
228 # define SI_ASSERT(x) assert(x)
230 # define SI_ASSERT(x)
234 SI_OK
= 0, //!< No error
235 SI_UPDATED
= 1, //!< An existing value was updated
236 SI_INSERTED
= 2, //!< A new value was inserted
238 // note: test for any error with (retval < 0)
239 SI_FAIL
= -1, //!< Generic failure
240 SI_NOMEM
= -2, //!< Out of memory error
241 SI_FILE
= -3 //!< File error (see errno for detail error)
244 #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
247 # define SI_NEWLINE_A "\r\n"
248 # define SI_NEWLINE_W L"\r\n"
250 # define SI_NEWLINE_A "\n"
251 # define SI_NEWLINE_W L"\n"
254 #if defined(SI_CONVERT_ICU)
255 # include <unicode/ustring.h>
259 # define SI_HAS_WIDE_FILE
260 # define SI_WCHAR_T wchar_t
261 #elif defined(SI_CONVERT_ICU)
262 # define SI_HAS_WIDE_FILE
263 # define SI_WCHAR_T UChar
267 // ---------------------------------------------------------------------------
268 // MAIN TEMPLATE CLASS
269 // ---------------------------------------------------------------------------
271 /** Simple INI file reader.
273 This can be instantiated with the choice of unicode or native characterset,
274 and case sensitive or insensitive comparisons of section and key names.
275 The supported combinations are pre-defined with the following typedefs:
278 <tr><th>Interface <th>Case-sensitive <th>Typedef
279 <tr><td>char <td>No <td>CSimpleIniA
280 <tr><td>char <td>Yes <td>CSimpleIniCaseA
281 <tr><td>wchar_t <td>No <td>CSimpleIniW
282 <tr><td>wchar_t <td>Yes <td>CSimpleIniCaseW
285 Note that using other types for the SI_CHAR is supported. For instance,
286 unsigned char, unsigned short, etc. Note that where the alternative type
287 is a different size to char/wchar_t you may need to supply new helper
288 classes for SI_STRLESS and SI_CONVERTER.
290 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
291 class CSimpleIniTempl
296 const SI_CHAR
* pItem
;
297 const SI_CHAR
* pComment
;
300 Entry(const SI_CHAR
* a_pszItem
= NULL
, int a_nOrder
= 0)
305 Entry(const Entry
& rhs
) { operator=(rhs
); }
306 Entry
& operator=(const Entry
& rhs
) {
308 pComment
= rhs
.pComment
;
313 #if defined(_MSC_VER) && _MSC_VER <= 1200
314 /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
315 bool operator<(const Entry
& rhs
) const { return LoadOrder()(*this, rhs
); }
316 bool operator>(const Entry
& rhs
) const { return LoadOrder()(rhs
, *this); }
319 /** Strict less ordering by name of key only */
320 struct KeyOrder
: std::binary_function
<Entry
, Entry
, bool> {
321 bool operator()(const Entry
& lhs
, const Entry
& rhs
) const {
322 const static SI_STRLESS isLess
= SI_STRLESS();
323 return isLess(lhs
.pItem
, rhs
.pItem
);
327 /** Strict less ordering by order, and then name of key */
328 struct LoadOrder
: std::binary_function
<Entry
, Entry
, bool> {
329 bool operator()(const Entry
& lhs
, const Entry
& rhs
) const {
330 if (lhs
.nOrder
!= rhs
.nOrder
) {
331 return lhs
.nOrder
< rhs
.nOrder
;
333 return KeyOrder()(lhs
.pItem
, rhs
.pItem
);
338 /** map keys to values */
339 typedef std::multimap
<Entry
,const SI_CHAR
*,typename
Entry::KeyOrder
> TKeyVal
;
341 /** map sections to key/value map */
342 typedef std::map
<Entry
,TKeyVal
,typename
Entry::KeyOrder
> TSection
;
344 /** set of dependent string pointers. Note that these pointers are
345 dependent on memory owned by CSimpleIni.
347 typedef std::list
<Entry
> TNamesDepend
;
349 /** interface definition for the OutputWriter object to pass to Save()
350 in order to output the INI file data.
355 virtual ~OutputWriter() { }
356 virtual void Write(const char * a_pBuf
) = 0;
358 OutputWriter(const OutputWriter
&); // disable
359 OutputWriter
& operator=(const OutputWriter
&); // disable
362 /** OutputWriter class to write the INI data to a file */
363 class FileWriter
: public OutputWriter
{
366 FileWriter(FILE * a_file
) : m_file(a_file
) { }
367 void Write(const char * a_pBuf
) {
368 fputs(a_pBuf
, m_file
);
371 FileWriter(const FileWriter
&); // disable
372 FileWriter
& operator=(const FileWriter
&); // disable
375 /** OutputWriter class to write the INI data to a string */
376 class StringWriter
: public OutputWriter
{
377 std::string
& m_string
;
379 StringWriter(std::string
& a_string
) : m_string(a_string
) { }
380 void Write(const char * a_pBuf
) {
381 m_string
.append(a_pBuf
);
384 StringWriter(const StringWriter
&); // disable
385 StringWriter
& operator=(const StringWriter
&); // disable
388 #ifdef SI_SUPPORT_IOSTREAMS
389 /** OutputWriter class to write the INI data to an ostream */
390 class StreamWriter
: public OutputWriter
{
391 std::ostream
& m_ostream
;
393 StreamWriter(std::ostream
& a_ostream
) : m_ostream(a_ostream
) { }
394 void Write(const char * a_pBuf
) {
398 StreamWriter(const StreamWriter
&); // disable
399 StreamWriter
& operator=(const StreamWriter
&); // disable
401 #endif // SI_SUPPORT_IOSTREAMS
403 /** Characterset conversion utility class to convert strings to the
404 same format as is used for the storage.
406 class Converter
: private SI_CONVERTER
{
408 Converter(bool a_bStoreIsUtf8
) : SI_CONVERTER(a_bStoreIsUtf8
) {
409 m_scratch
.resize(1024);
411 Converter(const Converter
& rhs
) { operator=(rhs
); }
412 Converter
& operator=(const Converter
& rhs
) {
413 m_scratch
= rhs
.m_scratch
;
416 bool ConvertToStore(const SI_CHAR
* a_pszString
) {
417 size_t uLen
= SizeToStore(a_pszString
);
418 if (uLen
== (size_t)(-1)) {
421 while (uLen
> m_scratch
.size()) {
422 m_scratch
.resize(m_scratch
.size() * 2);
424 return SI_CONVERTER::ConvertToStore(
426 const_cast<char*>(m_scratch
.data()),
429 const char * Data() { return m_scratch
.data(); }
431 std::string m_scratch
;
435 /*-----------------------------------------------------------------------*/
437 /** Default constructor.
439 @param a_bIsUtf8 See the method SetUnicode() for details.
440 @param a_bMultiKey See the method SetMultiKey() for details.
441 @param a_bMultiLine See the method SetMultiLine() for details.
444 bool a_bIsUtf8
= false,
445 bool a_bMultiKey
= false,
446 bool a_bMultiLine
= false
452 /** Deallocate all memory stored by this object */
455 /*-----------------------------------------------------------------------*/
456 /** @{ @name Settings */
458 /** Set the storage format of the INI data. This affects both the loading
459 and saving of the INI data using all of the Load/Save API functions.
460 This value cannot be changed after any INI data has been loaded.
462 If the file is not set to Unicode (UTF-8), then the data encoding is
463 assumed to be the OS native encoding. This encoding is the system
464 locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP.
465 If the storage format is set to Unicode then the file will be loaded
466 as UTF-8 encoded data regardless of the native file encoding. If
467 SI_CHAR == char then all of the char* parameters take and return UTF-8
468 encoded data regardless of the system locale.
470 \param a_bIsUtf8 Assume UTF-8 encoding for the source?
472 void SetUnicode(bool a_bIsUtf8
= true) {
473 if (!m_pData
) m_bStoreIsUtf8
= a_bIsUtf8
;
476 /** Get the storage format of the INI data. */
477 bool IsUnicode() const { return m_bStoreIsUtf8
; }
479 /** Should multiple identical keys be permitted in the file. If set to false
480 then the last value encountered will be used as the value of the key.
481 If set to true, then all values will be available to be queried. For
482 example, with the following input:
490 Then with SetMultiKey(true), both of the values "value1" and "value2"
491 will be returned for the key test. If SetMultiKey(false) is used, then
492 the value for "test" will only be "value2". This value may be changed
495 \param a_bAllowMultiKey Allow multi-keys in the source?
497 void SetMultiKey(bool a_bAllowMultiKey
= true) {
498 m_bAllowMultiKey
= a_bAllowMultiKey
;
501 /** Get the storage format of the INI data. */
502 bool IsMultiKey() const { return m_bAllowMultiKey
; }
504 /** Should data values be permitted to span multiple lines in the file. If
505 set to false then the multi-line construct <<<TAG as a value will be
506 returned as is instead of loading the data. This value may be changed
509 \param a_bAllowMultiLine Allow multi-line values in the source?
511 void SetMultiLine(bool a_bAllowMultiLine
= true) {
512 m_bAllowMultiLine
= a_bAllowMultiLine
;
515 /** Query the status of multi-line data */
516 bool IsMultiLine() const { return m_bAllowMultiLine
; }
518 /*-----------------------------------------------------------------------*/
520 @{ @name Loading INI Data */
522 /** Load an INI file from disk into memory
524 @param a_pszFile Path of the file to be loaded. This will be passed
525 to fopen() and so must be a valid path for the
528 @return SI_Error See error definitions
531 const char * a_pszFile
534 #ifdef SI_HAS_WIDE_FILE
535 /** Load an INI file from disk into memory
537 @param a_pwszFile Path of the file to be loaded in UTF-16.
539 @return SI_Error See error definitions
542 const SI_WCHAR_T
* a_pwszFile
544 #endif // SI_HAS_WIDE_FILE
546 /** Load the file from a file pointer.
548 @param a_fpFile Valid file pointer to read the file data from. The
549 file will be read until end of file.
551 @return SI_Error See error definitions
557 #ifdef SI_SUPPORT_IOSTREAMS
558 /** Load INI file data from an istream.
560 @param a_istream Stream to read from
562 @return SI_Error See error definitions
565 std::istream
& a_istream
567 #endif // SI_SUPPORT_IOSTREAMS
569 /** Load INI file data direct from a std::string
571 @param a_strData Data to be loaded
573 @return SI_Error See error definitions
575 SI_Error
Load(const std::string
& a_strData
) {
576 return Load(a_strData
.c_str(), a_strData
.size());
579 /** Load INI file data direct from memory
581 @param a_pData Data to be loaded
582 @param a_uDataLen Length of the data in bytes
584 @return SI_Error See error definitions
587 const char * a_pData
,
591 /*-----------------------------------------------------------------------*/
593 @{ @name Saving INI Data */
595 /** Save an INI file from memory to disk
597 @param a_pszFile Path of the file to be saved. This will be passed
598 to fopen() and so must be a valid path for the
601 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is
602 in UTF-8 format. If it is not UTF-8 then
603 this parameter is ignored.
605 @return SI_Error See error definitions
608 const char * a_pszFile
,
609 bool a_bAddSignature
= true
612 #ifdef SI_HAS_WIDE_FILE
613 /** Save an INI file from memory to disk
615 @param a_pwszFile Path of the file to be saved in UTF-16.
617 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is
618 in UTF-8 format. If it is not UTF-8 then
619 this parameter is ignored.
621 @return SI_Error See error definitions
624 const SI_WCHAR_T
* a_pwszFile
,
625 bool a_bAddSignature
= true
629 /** Save the INI data to a file. See Save() for details.
631 @param a_pFile Handle to a file. File should be opened for
634 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
635 UTF-8 format. If it is not UTF-8 then this value is
636 ignored. Do not set this to true if anything has
637 already been written to the file.
639 @return SI_Error See error definitions
643 bool a_bAddSignature
= false
646 /** Save the INI data. The data will be written to the output device
647 in a format appropriate to the current data, selected by:
650 <tr><th>SI_CHAR <th>FORMAT
651 <tr><td>char <td>same format as when loaded (MBCS or UTF-8)
652 <tr><td>wchar_t <td>UTF-8
653 <tr><td>other <td>UTF-8
656 Note that comments from the original data is preserved as per the
657 documentation on comments. The order of the sections and values
658 from the original file will be preserved.
660 Any data prepended or appended to the output device must use the the
661 same format (MBCS or UTF-8). You may use the GetConverter() method to
662 convert text to the correct format regardless of the output format
663 being used by SimpleIni.
665 To add a BOM to UTF-8 data, write it out manually at the very beginning
666 like is done in SaveFile when a_bUseBOM is true.
668 @param a_oOutput Output writer to write the data to.
670 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
671 UTF-8 format. If it is not UTF-8 then this value is
672 ignored. Do not set this to true if anything has
673 already been written to the OutputWriter.
675 @return SI_Error See error definitions
678 OutputWriter
& a_oOutput
,
679 bool a_bAddSignature
= false
682 #ifdef SI_SUPPORT_IOSTREAMS
683 /** Save the INI data to an ostream. See Save() for details.
685 @param a_ostream String to have the INI data appended to.
687 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
688 UTF-8 format. If it is not UTF-8 then this value is
689 ignored. Do not set this to true if anything has
690 already been written to the stream.
692 @return SI_Error See error definitions
695 std::ostream
& a_ostream
,
696 bool a_bAddSignature
= false
699 StreamWriter
writer(a_ostream
);
700 return Save(writer
, a_bAddSignature
);
702 #endif // SI_SUPPORT_IOSTREAMS
704 /** Append the INI data to a string. See Save() for details.
706 @param a_sBuffer String to have the INI data appended to.
708 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
709 UTF-8 format. If it is not UTF-8 then this value is
710 ignored. Do not set this to true if anything has
711 already been written to the string.
713 @return SI_Error See error definitions
716 std::string
& a_sBuffer
,
717 bool a_bAddSignature
= false
720 StringWriter
writer(a_sBuffer
);
721 return Save(writer
, a_bAddSignature
);
724 /*-----------------------------------------------------------------------*/
726 @{ @name Accessing INI Data */
728 /** Retrieve all section names. The list is returned as an STL vector of
729 names and can be iterated or searched as necessary. Note that the
730 collation order of the returned strings is NOT DEFINED.
732 NOTE! This structure contains only pointers to strings. The actual
733 string data is stored in memory owned by CSimpleIni. Ensure that the
734 CSimpleIni object is not destroyed or Reset() while these pointers
737 @param a_names Vector that will receive all of the section
738 names. See note above!
741 TNamesDepend
& a_names
744 /** Retrieve all unique key names in a section. The collation order of the
745 returned strings is NOT DEFINED. Only unique key names are returned.
747 NOTE! This structure contains only pointers to strings. The actual
748 string data is stored in memory owned by CSimpleIni. Ensure that the
749 CSimpleIni object is not destroyed or Reset() while these strings
752 @param a_pSection Section to request data for
753 @param a_names List that will receive all of the key
754 names. See note above!
756 @return true Section was found.
757 @return false Matching section was not found.
760 const SI_CHAR
* a_pSection
,
761 TNamesDepend
& a_names
764 /** Retrieve all values for a specific key. This method can be used when
765 multiple keys are both enabled and disabled.
767 NOTE! The returned values are pointers to string data stored in memory
768 owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed
769 or Reset while you are using this pointer!
771 @param a_pSection Section to search
772 @param a_pKey Key to search for
773 @param a_values List to return if the key is not found
775 @return true Key was found.
776 @return false Matching section/key was not found.
779 const SI_CHAR
* a_pSection
,
780 const SI_CHAR
* a_pKey
,
781 TNamesDepend
& a_values
784 /** Query the number of keys in a specific section. Note that if multiple
785 keys are enabled, then this value may be different to the number of
786 keys returned by GetAllKeys.
788 @param a_pSection Section to request data for
790 @return -1 Section does not exist in the file
791 @return >=0 Number of keys in the section
794 const SI_CHAR
* a_pSection
797 /** Retrieve all key and value pairs for a section. The data is returned
798 as a pointer to an STL map and can be iterated or searched as
799 desired. Note that multiple entries for the same key may exist when
800 multiple keys have been enabled.
802 NOTE! This structure contains only pointers to strings. The actual
803 string data is stored in memory owned by CSimpleIni. Ensure that the
804 CSimpleIni object is not destroyed or Reset() while these strings
807 @param a_pSection Name of the section to return
808 @return boolean Was a section matching the supplied
811 const TKeyVal
* GetSection(
812 const SI_CHAR
* a_pSection
815 /** Retrieve the value for a specific key. If multiple keys are enabled
816 (see SetMultiKey) then only the first value associated with that key
817 will be returned, see GetAllValues for getting all values with multikey.
819 NOTE! The returned value is a pointer to string data stored in memory
820 owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed
821 or Reset while you are using this pointer!
823 @param a_pSection Section to search
824 @param a_pKey Key to search for
825 @param a_pDefault Value to return if the key is not found
826 @param a_pHasMultiple Optionally receive notification of if there are
827 multiple entries for this key.
829 @return a_pDefault Key was not found in the section
830 @return other Value of the key
832 const SI_CHAR
* GetValue(
833 const SI_CHAR
* a_pSection
,
834 const SI_CHAR
* a_pKey
,
835 const SI_CHAR
* a_pDefault
= NULL
,
836 bool * a_pHasMultiple
= NULL
839 /** Add or update a section or value. This will always insert
840 when multiple keys are enabled.
842 @param a_pSection Section to add or update
843 @param a_pKey Key to add or update. Set to NULL to
844 create an empty section.
845 @param a_pValue Value to set. Set to NULL to create an
847 @param a_pComment Comment to be associated with the section or the
848 key. If a_pKey is NULL then it will be associated
849 with the section, otherwise the key. Note that a
850 comment may be set ONLY when the section or key is
851 first created (i.e. when this function returns the
852 value SI_INSERTED). If you wish to create a section
853 with a comment then you need to create the section
854 separately to the key. The comment string must be
855 in full comment form already (have a comment
856 character starting every line).
858 @return SI_Error See error definitions
859 @return SI_UPDATED Value was updated
860 @return SI_INSERTED Value was inserted
863 const SI_CHAR
* a_pSection
,
864 const SI_CHAR
* a_pKey
,
865 const SI_CHAR
* a_pValue
,
866 const SI_CHAR
* a_pComment
= NULL
869 return AddEntry(a_pSection
, a_pKey
, a_pValue
, a_pComment
, true);
872 /** Delete an entire section, or a key from a section. Note that the
873 data returned by GetSection is invalid and must not be used after
874 anything has been deleted from that section using this method.
875 Note when multiple keys is enabled, this will delete all keys with
876 that name; there is no way to selectively delete individual key/values
879 @param a_pSection Section to delete key from, or if
880 a_pKey is NULL, the section to remove.
881 @param a_pKey Key to remove from the section. Set to
882 NULL to remove the entire section.
883 @param a_bRemoveEmpty If the section is empty after this key has
884 been deleted, should the empty section be
887 @return true Key or section was deleted.
888 @return false Key or section was not found.
891 const SI_CHAR
* a_pSection
,
892 const SI_CHAR
* a_pKey
,
893 bool a_bRemoveEmpty
= false
896 /*-----------------------------------------------------------------------*/
898 @{ @name Converter */
900 /** Return a conversion object to convert text to the same encoding
901 as is used by the Save(), SaveFile() and SaveString() functions.
902 Use this to prepare the strings that you wish to append or prepend
903 to the output INI data.
905 Converter
GetConverter() const {
906 return Converter(m_bStoreIsUtf8
);
909 /*-----------------------------------------------------------------------*/
913 /** Parse the data looking for a file comment and store it if found.
915 SI_Error
FindFileComment(
920 /** Parse the data looking for the next valid entry. The memory pointed to
921 by a_pData is modified by inserting NULL characters. The pointer is
922 updated to the current location in the block of text.
926 const SI_CHAR
*& a_pSection
,
927 const SI_CHAR
*& a_pKey
,
928 const SI_CHAR
*& a_pVal
,
929 const SI_CHAR
*& a_pComment
932 /** Add the section/key/value to our data.
934 @param a_pSection Section name. Sections will be created if they
936 @param a_pKey Key name. May be NULL to create an empty section.
937 Existing entries will be updated. New entries will
939 @param a_pValue Value for the key.
940 @param a_pComment Comment to be associated with the section or the
941 key. If a_pKey is NULL then it will be associated
942 with the section, otherwise the key. This must be
943 a string in full comment form already (have a
944 comment character starting every line).
945 @param a_bCopyStrings Should copies of the strings be made or not.
946 If false then the pointers will be used as is.
949 const SI_CHAR
* a_pSection
,
950 const SI_CHAR
* a_pKey
,
951 const SI_CHAR
* a_pValue
,
952 const SI_CHAR
* a_pComment
,
956 /** Is the supplied character a whitespace character? */
957 inline bool IsSpace(SI_CHAR ch
) const {
958 return (ch
== ' ' || ch
== '\t' || ch
== '\r' || ch
== '\n');
961 /** Does the supplied character start a comment line? */
962 inline bool IsComment(SI_CHAR ch
) const {
963 return (ch
== ';' || ch
== '#');
967 /** Skip over a newline character (or characters) for either DOS or UNIX */
968 inline void SkipNewLine(SI_CHAR
*& a_pData
) const {
969 a_pData
+= (*a_pData
== '\r' && *(a_pData
+1) == '\n') ? 2 : 1;
972 /** Make a copy of the supplied string, replacing the original pointer */
973 SI_Error
CopyString(const SI_CHAR
*& a_pString
);
975 /** Delete a string from the copied strings buffer if necessary */
976 void DeleteString(const SI_CHAR
* a_pString
);
978 /** Internal use of our string comparison function */
979 bool IsLess(const SI_CHAR
* a_pLeft
, const SI_CHAR
* a_pRight
) const {
980 const static SI_STRLESS isLess
= SI_STRLESS();
981 return isLess(a_pLeft
, a_pRight
);
984 bool IsMultiLineTag(const SI_CHAR
* a_pData
) const;
985 bool IsMultiLineData(const SI_CHAR
* a_pData
) const;
986 bool LoadMultiLineText(
988 const SI_CHAR
*& a_pVal
,
989 const SI_CHAR
* a_pTagName
,
990 bool a_bAllowBlankLinesInComment
= false
992 bool IsNewLineChar(SI_CHAR a_c
) const;
994 bool OutputMultiLineText(
995 OutputWriter
& a_oOutput
,
996 Converter
& a_oConverter
,
997 const SI_CHAR
* a_pText
1001 /** Copy of the INI file data in our character format. This will be
1002 modified when parsed to have NULL characters added after all
1003 interesting string entries. All of the string pointers to sections,
1004 keys and values point into this block of memory.
1008 /** Length of the data that we have stored. Used when deleting strings
1009 to determine if the string is stored here or in the allocated string
1014 /** File comment for this data, if one exists. */
1015 const SI_CHAR
* m_pFileComment
;
1017 /** Parsed INI data. Section -> (Key -> Value). */
1020 /** This vector stores allocated memory for copies of strings that have
1021 been supplied after the file load. It will be empty unless SetValue()
1024 TNamesDepend m_strings
;
1026 /** Is the format of our datafile UTF-8 or MBCS? */
1027 bool m_bStoreIsUtf8
;
1029 /** Are multiple values permitted for the same key? */
1030 bool m_bAllowMultiKey
;
1032 /** Are data values permitted to span multiple lines? */
1033 bool m_bAllowMultiLine
;
1035 /** Next order value, used to ensure sections and keys are output in the
1036 same order that they are loaded/added.
1041 // ---------------------------------------------------------------------------
1043 // ---------------------------------------------------------------------------
1045 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1046 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::CSimpleIniTempl(
1048 bool a_bAllowMultiKey
,
1049 bool a_bAllowMultiLine
1053 , m_pFileComment(NULL
)
1054 , m_bStoreIsUtf8(a_bIsUtf8
)
1055 , m_bAllowMultiKey(a_bAllowMultiKey
)
1056 , m_bAllowMultiLine(a_bAllowMultiLine
)
1060 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1061 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::~CSimpleIniTempl()
1066 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1068 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::Reset()
1074 m_pFileComment
= NULL
;
1075 if (!m_data
.empty()) {
1076 m_data
.erase(m_data
.begin(), m_data
.end());
1079 // remove all strings
1080 if (!m_strings
.empty()) {
1081 typename
TNamesDepend::iterator i
= m_strings
.begin();
1082 for (; i
!= m_strings
.end(); ++i
) {
1083 delete[] const_cast<SI_CHAR
*>(i
->pItem
);
1085 m_strings
.erase(m_strings
.begin(), m_strings
.end());
1089 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1091 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::LoadFile(
1092 const char * a_pszFile
1096 #if __STDC_WANT_SECURE_LIB__
1097 fopen_s(&fp
, a_pszFile
, "rb");
1099 fp
= fopen(a_pszFile
, "rb");
1104 SI_Error rc
= LoadFile(fp
);
1109 #ifdef SI_HAS_WIDE_FILE
1110 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1112 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::LoadFile(
1113 const SI_WCHAR_T
* a_pwszFile
1118 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
1119 _wfopen_s(&fp
, a_pwszFile
, L
"rb");
1121 fp
= _wfopen(a_pwszFile
, L
"rb");
1123 if (!fp
) return SI_FILE
;
1124 SI_Error rc
= LoadFile(fp
);
1127 #else // SI_CONVERT_ICU
1129 u_austrncpy(szFile
, a_pwszFile
, sizeof(szFile
));
1130 return LoadFile(szFile
);
1133 #endif // SI_HAS_WIDE_FILE
1135 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1137 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::LoadFile(
1141 // load the raw file data
1142 int retval
= fseek(a_fpFile
, 0, SEEK_END
);
1146 long lSize
= ftell(a_fpFile
);
1153 char * pData
= new char[lSize
];
1157 fseek(a_fpFile
, 0, SEEK_SET
);
1158 size_t uRead
= fread(pData
, sizeof(char), lSize
, a_fpFile
);
1159 if (uRead
!= (size_t) lSize
) {
1164 // convert the raw data to unicode
1165 SI_Error rc
= Load(pData
, uRead
);
1170 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1172 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::Load(
1173 const char * a_pData
,
1177 SI_CONVERTER
converter(m_bStoreIsUtf8
);
1179 if (a_uDataLen
== 0) {
1183 // consume the UTF-8 BOM if it exists
1184 if (m_bStoreIsUtf8
&& a_uDataLen
>= 3) {
1185 if (memcmp(a_pData
, SI_UTF8_SIGNATURE
, 3) == 0) {
1191 // determine the length of the converted data
1192 size_t uLen
= converter
.SizeFromStore(a_pData
, a_uDataLen
);
1193 if (uLen
== (size_t)(-1)) {
1197 // allocate memory for the data, ensure that there is a NULL
1198 // terminator wherever the converted data ends
1199 SI_CHAR
* pData
= new SI_CHAR
[uLen
+1];
1203 memset(pData
, 0, sizeof(SI_CHAR
)*(uLen
+1));
1206 if (!converter
.ConvertFromStore(a_pData
, a_uDataLen
, pData
, uLen
)) {
1212 const static SI_CHAR empty
= 0;
1213 SI_CHAR
* pWork
= pData
;
1214 const SI_CHAR
* pSection
= &empty
;
1215 const SI_CHAR
* pItem
= NULL
;
1216 const SI_CHAR
* pVal
= NULL
;
1217 const SI_CHAR
* pComment
= NULL
;
1219 // We copy the strings if we are loading data into this class when we
1220 // already have stored some.
1221 bool bCopyStrings
= (m_pData
!= NULL
);
1223 // find a file comment if it exists, this is a comment that starts at the
1224 // beginning of the file and continues until the first blank line.
1225 SI_Error rc
= FindFileComment(pWork
, bCopyStrings
);
1226 if (rc
< 0) return rc
;
1228 // add every entry in the file to the data table
1229 while (FindEntry(pWork
, pSection
, pItem
, pVal
, pComment
)) {
1230 rc
= AddEntry(pSection
, pItem
, pVal
, pComment
, bCopyStrings
);
1231 if (rc
< 0) return rc
;
1234 // store these strings if we didn't copy them
1240 m_uDataLen
= uLen
+1;
1246 #ifdef SI_SUPPORT_IOSTREAMS
1247 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1249 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::Load(
1250 std::istream
& a_istream
1253 std::string strData
;
1256 a_istream
.get(szBuf
, sizeof(szBuf
), '\0');
1257 strData
.append(szBuf
);
1259 while (a_istream
.good());
1260 return Load(strData
);
1262 #endif // SI_SUPPORT_IOSTREAMS
1264 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1266 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::FindFileComment(
1271 // there can only be a single file comment
1272 if (m_pFileComment
) {
1276 // Load the file comment as multi-line text, this will modify all of
1277 // the newline characters to be single \n chars
1278 if (!LoadMultiLineText(a_pData
, m_pFileComment
, NULL
, false)) {
1282 // copy the string if necessary
1283 if (a_bCopyStrings
) {
1284 SI_Error rc
= CopyString(m_pFileComment
);
1285 if (rc
< 0) return rc
;
1291 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1293 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::FindEntry(
1295 const SI_CHAR
*& a_pSection
,
1296 const SI_CHAR
*& a_pKey
,
1297 const SI_CHAR
*& a_pVal
,
1298 const SI_CHAR
*& a_pComment
1303 SI_CHAR
* pTrail
= NULL
;
1305 // skip spaces and empty lines
1306 while (*a_pData
&& IsSpace(*a_pData
)) {
1313 // skip processing of comment lines but keep a pointer to
1314 // the start of the comment.
1315 if (IsComment(*a_pData
)) {
1316 LoadMultiLineText(a_pData
, a_pComment
, NULL
, true);
1320 // process section names
1321 if (*a_pData
== '[') {
1322 // skip leading spaces
1324 while (*a_pData
&& IsSpace(*a_pData
)) {
1328 // find the end of the section name (it may contain spaces)
1329 // and convert it to lowercase as necessary
1330 a_pSection
= a_pData
;
1331 while (*a_pData
&& *a_pData
!= ']' && !IsNewLineChar(*a_pData
)) {
1335 // if it's an invalid line, just skip it
1336 if (*a_pData
!= ']') {
1340 // remove trailing spaces from the section
1341 pTrail
= a_pData
- 1;
1342 while (pTrail
>= a_pSection
&& IsSpace(*pTrail
)) {
1348 // skip to the end of the line
1349 ++a_pData
; // safe as checked that it == ']' above
1350 while (*a_pData
&& !IsNewLineChar(*a_pData
)) {
1359 // find the end of the key name (it may contain spaces)
1360 // and convert it to lowercase as necessary
1362 while (*a_pData
&& *a_pData
!= '=' && !IsNewLineChar(*a_pData
)) {
1366 // if it's an invalid line, just skip it
1367 if (*a_pData
!= '=') {
1371 // empty keys are invalid
1372 if (a_pKey
== a_pData
) {
1373 while (*a_pData
&& !IsNewLineChar(*a_pData
)) {
1379 // remove trailing spaces from the key
1380 pTrail
= a_pData
- 1;
1381 while (pTrail
>= a_pKey
&& IsSpace(*pTrail
)) {
1387 // skip leading whitespace on the value
1388 ++a_pData
; // safe as checked that it == '=' above
1389 while (*a_pData
&& !IsNewLineChar(*a_pData
) && IsSpace(*a_pData
)) {
1393 // find the end of the value which is the end of this line
1395 while (*a_pData
&& !IsNewLineChar(*a_pData
)) {
1399 // remove trailing spaces from the value
1400 pTrail
= a_pData
- 1;
1401 if (*a_pData
) { // prepare for the next round
1402 SkipNewLine(a_pData
);
1404 while (pTrail
>= a_pVal
&& IsSpace(*pTrail
)) {
1410 // check for multi-line entries
1411 if (m_bAllowMultiLine
&& IsMultiLineTag(a_pVal
)) {
1412 // skip the "<<<" to get the tag that will end the multiline
1413 const SI_CHAR
* pTagName
= a_pVal
+ 3;
1414 return LoadMultiLineText(a_pData
, a_pVal
, pTagName
);
1417 // return the standard entry
1424 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1426 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::IsMultiLineTag(
1427 const SI_CHAR
* a_pVal
1430 // check for the "<<<" prefix for a multi-line entry
1431 if (*a_pVal
++ != '<') return false;
1432 if (*a_pVal
++ != '<') return false;
1433 if (*a_pVal
++ != '<') return false;
1437 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1439 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::IsMultiLineData(
1440 const SI_CHAR
* a_pData
1443 // data is multi-line if it has any of the following features:
1444 // * whitespace prefix
1445 // * embedded newlines
1446 // * whitespace suffix
1454 if (IsSpace(*a_pData
)) {
1458 // embedded newlines
1460 if (IsNewLineChar(*a_pData
)) {
1467 if (IsSpace(*--a_pData
)) {
1474 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1476 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::IsNewLineChar(
1480 return (a_c
== '\n' || a_c
== '\r');
1483 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1485 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::LoadMultiLineText(
1487 const SI_CHAR
*& a_pVal
,
1488 const SI_CHAR
* a_pTagName
,
1489 bool a_bAllowBlankLinesInComment
1492 // we modify this data to strip all newlines down to a single '\n'
1493 // character. This means that on Windows we need to strip out some
1494 // characters which will make the data shorter.
1495 // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
1496 // LINE1-LINE1\nLINE2-LINE2\0
1497 // The pDataLine entry is the pointer to the location in memory that
1498 // the current line needs to start to run following the existing one.
1499 // This may be the same as pCurrLine in which case no move is needed.
1500 SI_CHAR
* pDataLine
= a_pData
;
1501 SI_CHAR
* pCurrLine
;
1503 // value starts at the current line
1506 // find the end tag. This tag must start in column 1 and be
1507 // followed by a newline. No whitespace removal is done while
1508 // searching for this tag.
1509 SI_CHAR cEndOfLineChar
= *a_pData
;
1511 // if we are loading comments then we need a comment character as
1512 // the first character on every line
1513 if (!a_pTagName
&& !IsComment(*a_pData
)) {
1514 // if we aren't allowing blank lines then we're done
1515 if (!a_bAllowBlankLinesInComment
) {
1519 // if we are allowing blank lines then we only include them
1520 // in this comment if another comment follows, so read ahead
1522 SI_CHAR
* pCurr
= a_pData
;
1524 while (IsSpace(*pCurr
)) {
1525 if (IsNewLineChar(*pCurr
)) {
1534 // we have a comment, add the blank lines to the output
1535 // and continue processing from here
1536 if (IsComment(*pCurr
)) {
1537 for (; nNewLines
> 0; --nNewLines
) *pDataLine
++ = '\n';
1542 // the comment ends here
1546 // find the end of this line
1547 pCurrLine
= a_pData
;
1548 while (*a_pData
&& !IsNewLineChar(*a_pData
)) ++a_pData
;
1550 // move this line down to the location that it should be if necessary
1551 if (pDataLine
< pCurrLine
) {
1552 size_t nLen
= (size_t) (a_pData
- pCurrLine
);
1553 memmove(pDataLine
, pCurrLine
, nLen
* sizeof(SI_CHAR
));
1554 pDataLine
[nLen
] = '\0';
1557 // end the line with a NULL
1558 cEndOfLineChar
= *a_pData
;
1561 // if are looking for a tag then do the check now. This is done before
1562 // checking for end of the data, so that if we have the tag at the end
1563 // of the data then the tag is removed correctly.
1565 (!IsLess(pDataLine
, a_pTagName
) && !IsLess(a_pTagName
, pDataLine
)))
1570 // if we are at the end of the data then we just automatically end
1571 // this entry and return the current data.
1572 if (!cEndOfLineChar
) {
1576 // otherwise we need to process this newline to ensure that it consists
1577 // of just a single \n character.
1578 pDataLine
+= (a_pData
- pCurrLine
);
1579 *a_pData
= cEndOfLineChar
;
1580 SkipNewLine(a_pData
);
1581 *pDataLine
++ = '\n';
1584 // if we didn't find a comment at all then return false
1585 if (a_pVal
== a_pData
) {
1590 // the data (which ends at the end of the last line) needs to be
1591 // null-terminated BEFORE before the newline character(s). If the
1592 // user wants a new line in the multi-line data then they need to
1593 // add an empty line before the tag.
1594 *--pDataLine
= '\0';
1596 // if looking for a tag and if we aren't at the end of the data,
1597 // then move a_pData to the start of the next line.
1598 if (a_pTagName
&& cEndOfLineChar
) {
1599 SI_ASSERT(IsNewLineChar(cEndOfLineChar
));
1600 *a_pData
= cEndOfLineChar
;
1601 SkipNewLine(a_pData
);
1607 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1609 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::CopyString(
1610 const SI_CHAR
*& a_pString
1614 if (sizeof(SI_CHAR
) == sizeof(char)) {
1615 uLen
= strlen((const char *)a_pString
);
1617 else if (sizeof(SI_CHAR
) == sizeof(wchar_t)) {
1618 uLen
= wcslen((const wchar_t *)a_pString
);
1621 for ( ; a_pString
[uLen
]; ++uLen
) /*loop*/ ;
1623 ++uLen
; // NULL character
1624 SI_CHAR
* pCopy
= new SI_CHAR
[uLen
];
1628 memcpy(pCopy
, a_pString
, sizeof(SI_CHAR
)*uLen
);
1629 m_strings
.push_back(pCopy
);
1634 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1636 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::AddEntry(
1637 const SI_CHAR
* a_pSection
,
1638 const SI_CHAR
* a_pKey
,
1639 const SI_CHAR
* a_pValue
,
1640 const SI_CHAR
* a_pComment
,
1645 bool bInserted
= false;
1647 SI_ASSERT(!a_pComment
|| IsComment(*a_pComment
));
1649 // if we are copying strings then make a copy of the comment now
1650 // because we will need it when we add the entry.
1651 if (a_bCopyStrings
&& a_pComment
) {
1652 rc
= CopyString(a_pComment
);
1653 if (rc
< 0) return rc
;
1656 // check for existence of the section first if we need string copies
1657 typename
TSection::iterator iSection
= m_data
.end();
1658 if (a_bCopyStrings
) {
1659 iSection
= m_data
.find(a_pSection
);
1660 if (iSection
== m_data
.end()) {
1661 // if the section doesn't exist then we need a copy as the
1662 // string needs to last beyond the end of this function
1663 // because we will be inserting the section next
1664 rc
= CopyString(a_pSection
);
1665 if (rc
< 0) return rc
;
1669 // create the section entry
1670 if (iSection
== m_data
.end()) {
1671 Entry
oKey(a_pSection
, ++m_nOrder
);
1672 if (a_pComment
&& (!a_pKey
|| !a_pValue
)) {
1673 oKey
.pComment
= a_pComment
;
1675 typename
TSection::value_type
oEntry(oKey
, TKeyVal());
1676 typedef typename
TSection::iterator SectionIterator
;
1677 std::pair
<SectionIterator
,bool> i
=
1678 m_data
.insert(oEntry
);
1682 if (!a_pKey
|| !a_pValue
) {
1683 // section only entries are specified with pItem and pVal as NULL
1684 return bInserted
? SI_INSERTED
: SI_UPDATED
;
1687 // check for existence of the key
1688 TKeyVal
& keyval
= iSection
->second
;
1689 typename
TKeyVal::iterator iKey
= keyval
.find(a_pKey
);
1691 // make string copies if necessary
1692 if (a_bCopyStrings
) {
1693 if (m_bAllowMultiKey
|| iKey
== keyval
.end()) {
1694 // if the key doesn't exist then we need a copy as the
1695 // string needs to last beyond the end of this function
1696 // because we will be inserting the key next
1697 rc
= CopyString(a_pKey
);
1698 if (rc
< 0) return rc
;
1701 // we always need a copy of the value
1702 rc
= CopyString(a_pValue
);
1703 if (rc
< 0) return rc
;
1706 // create the key entry
1707 if (iKey
== keyval
.end() || m_bAllowMultiKey
) {
1708 Entry
oKey(a_pKey
, ++m_nOrder
);
1710 oKey
.pComment
= a_pComment
;
1712 typename
TKeyVal::value_type
oEntry(oKey
, NULL
);
1713 iKey
= keyval
.insert(oEntry
);
1716 iKey
->second
= a_pValue
;
1717 return bInserted
? SI_INSERTED
: SI_UPDATED
;
1720 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1722 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::GetValue(
1723 const SI_CHAR
* a_pSection
,
1724 const SI_CHAR
* a_pKey
,
1725 const SI_CHAR
* a_pDefault
,
1726 bool * a_pHasMultiple
1729 if (a_pHasMultiple
) {
1730 *a_pHasMultiple
= false;
1732 if (!a_pSection
|| !a_pKey
) {
1735 typename
TSection::const_iterator iSection
= m_data
.find(a_pSection
);
1736 if (iSection
== m_data
.end()) {
1739 typename
TKeyVal::const_iterator iKeyVal
= iSection
->second
.find(a_pKey
);
1740 if (iKeyVal
== iSection
->second
.end()) {
1744 // check for multiple entries with the same key
1745 if (m_bAllowMultiKey
&& a_pHasMultiple
) {
1746 typename
TKeyVal::const_iterator iTemp
= iKeyVal
;
1747 if (++iTemp
!= iSection
->second
.end()) {
1748 if (!IsLess(a_pKey
, iTemp
->first
.pItem
)) {
1749 *a_pHasMultiple
= true;
1754 return iKeyVal
->second
;
1757 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1759 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::GetAllValues(
1760 const SI_CHAR
* a_pSection
,
1761 const SI_CHAR
* a_pKey
,
1762 TNamesDepend
& a_values
1765 if (!a_pSection
|| !a_pKey
) {
1768 typename
TSection::const_iterator iSection
= m_data
.find(a_pSection
);
1769 if (iSection
== m_data
.end()) {
1772 typename
TKeyVal::const_iterator iKeyVal
= iSection
->second
.find(a_pKey
);
1773 if (iKeyVal
== iSection
->second
.end()) {
1777 // insert all values for this key
1778 a_values
.push_back(iKeyVal
->second
);
1779 if (m_bAllowMultiKey
) {
1781 while (iKeyVal
!= iSection
->second
.end() && !IsLess(a_pKey
, iKeyVal
->first
.pItem
)) {
1782 a_values
.push_back(Entry(iKeyVal
->second
, iKeyVal
->first
.nOrder
));
1790 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1792 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::GetSectionSize(
1793 const SI_CHAR
* a_pSection
1800 typename
TSection::const_iterator iSection
= m_data
.find(a_pSection
);
1801 if (iSection
== m_data
.end()) {
1804 const TKeyVal
& section
= iSection
->second
;
1806 // if multi-key isn't permitted then the section size is
1807 // the number of keys that we have.
1808 if (!m_bAllowMultiKey
|| section
.empty()) {
1809 return (int) section
.size();
1812 // otherwise we need to count them
1814 const SI_CHAR
* pLastKey
= NULL
;
1815 typename
TKeyVal::const_iterator iKeyVal
= section
.begin();
1816 for (int n
= 0; iKeyVal
!= section
.end(); ++iKeyVal
, ++n
) {
1817 if (!pLastKey
|| IsLess(pLastKey
, iKeyVal
->first
.pItem
)) {
1819 pLastKey
= iKeyVal
->first
.pItem
;
1825 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1826 const typename CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::TKeyVal
*
1827 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::GetSection(
1828 const SI_CHAR
* a_pSection
1832 typename
TSection::const_iterator i
= m_data
.find(a_pSection
);
1833 if (i
!= m_data
.end()) {
1834 return &(i
->second
);
1840 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1842 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::GetAllSections(
1843 TNamesDepend
& a_names
1846 typename
TSection::const_iterator i
= m_data
.begin();
1847 for (int n
= 0; i
!= m_data
.end(); ++i
, ++n
) {
1848 a_names
.push_back(i
->first
);
1852 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1854 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::GetAllKeys(
1855 const SI_CHAR
* a_pSection
,
1856 TNamesDepend
& a_names
1863 typename
TSection::const_iterator iSection
= m_data
.find(a_pSection
);
1864 if (iSection
== m_data
.end()) {
1868 const TKeyVal
& section
= iSection
->second
;
1869 const SI_CHAR
* pLastKey
= NULL
;
1870 typename
TKeyVal::const_iterator iKeyVal
= section
.begin();
1871 for (int n
= 0; iKeyVal
!= section
.end(); ++iKeyVal
, ++n
) {
1872 if (!pLastKey
|| IsLess(pLastKey
, iKeyVal
->first
.pItem
)) {
1873 a_names
.push_back(iKeyVal
->first
);
1874 pLastKey
= iKeyVal
->first
.pItem
;
1881 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1883 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::SaveFile(
1884 const char * a_pszFile
,
1885 bool a_bAddSignature
1889 #if __STDC_WANT_SECURE_LIB__
1890 fopen_s(&fp
, a_pszFile
, "wb");
1892 fp
= fopen(a_pszFile
, "wb");
1894 if (!fp
) return SI_FILE
;
1895 SI_Error rc
= SaveFile(fp
, a_bAddSignature
);
1900 #ifdef SI_HAS_WIDE_FILE
1901 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1903 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::SaveFile(
1904 const SI_WCHAR_T
* a_pwszFile
,
1905 bool a_bAddSignature
1909 FILE * fp
= _wfopen(a_pwszFile
, L
"wb");
1910 if (!fp
) return SI_FILE
;
1911 SI_Error rc
= SaveFile(fp
, a_bAddSignature
);
1914 #else // SI_CONVERT_ICU
1916 u_austrncpy(szFile
, a_pwszFile
, sizeof(szFile
));
1917 return SaveFile(szFile
, a_bAddSignature
);
1920 #endif // SI_HAS_WIDE_FILE
1922 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1924 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::SaveFile(
1926 bool a_bAddSignature
1929 FileWriter
writer(a_pFile
);
1930 return Save(writer
, a_bAddSignature
);
1933 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
1935 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::Save(
1936 OutputWriter
& a_oOutput
,
1937 bool a_bAddSignature
1940 Converter
convert(m_bStoreIsUtf8
);
1942 // add the UTF-8 signature if it is desired
1943 if (m_bStoreIsUtf8
&& a_bAddSignature
) {
1944 a_oOutput
.Write(SI_UTF8_SIGNATURE
);
1947 // get all of the sections sorted in load order
1948 TNamesDepend oSections
;
1949 GetAllSections(oSections
);
1950 #if defined(_MSC_VER) && _MSC_VER <= 1200
1953 oSections
.sort(typename
Entry::LoadOrder());
1956 // write the file comment if we have one
1957 bool bNeedNewLine
= false;
1958 if (m_pFileComment
) {
1959 if (!OutputMultiLineText(a_oOutput
, convert
, m_pFileComment
)) {
1962 bNeedNewLine
= true;
1965 // iterate through our sections and output the data
1966 typename
TNamesDepend::const_iterator iSection
= oSections
.begin();
1967 for ( ; iSection
!= oSections
.end(); ++iSection
) {
1968 // write out the comment if there is one
1969 if (iSection
->pComment
) {
1970 if (!convert
.ConvertToStore(iSection
->pComment
)) {
1974 a_oOutput
.Write(SI_NEWLINE_A
);
1975 a_oOutput
.Write(SI_NEWLINE_A
);
1977 a_oOutput
.Write(convert
.Data());
1978 a_oOutput
.Write(SI_NEWLINE_A
);
1979 bNeedNewLine
= false;
1983 a_oOutput
.Write(SI_NEWLINE_A
);
1984 a_oOutput
.Write(SI_NEWLINE_A
);
1985 bNeedNewLine
= false;
1988 // write the section (unless there is no section name)
1989 if (*iSection
->pItem
) {
1990 if (!convert
.ConvertToStore(iSection
->pItem
)) {
1993 a_oOutput
.Write("[");
1994 a_oOutput
.Write(convert
.Data());
1995 a_oOutput
.Write("]");
1996 a_oOutput
.Write(SI_NEWLINE_A
);
1999 // get all of the keys sorted in load order
2001 GetAllKeys(iSection
->pItem
, oKeys
);
2002 #if defined(_MSC_VER) && _MSC_VER <= 1200
2005 oKeys
.sort(typename
Entry::LoadOrder());
2008 // write all keys and values
2009 typename
TNamesDepend::const_iterator iKey
= oKeys
.begin();
2010 for ( ; iKey
!= oKeys
.end(); ++iKey
) {
2011 // get all values for this key
2012 TNamesDepend oValues
;
2013 GetAllValues(iSection
->pItem
, iKey
->pItem
, oValues
);
2015 // write out the comment if there is one
2016 if (iKey
->pComment
) {
2017 a_oOutput
.Write(SI_NEWLINE_A
);
2018 if (!OutputMultiLineText(a_oOutput
, convert
, iKey
->pComment
)) {
2023 typename
TNamesDepend::const_iterator iValue
= oValues
.begin();
2024 for ( ; iValue
!= oValues
.end(); ++iValue
) {
2026 if (!convert
.ConvertToStore(iKey
->pItem
)) {
2029 a_oOutput
.Write(convert
.Data());
2032 if (!convert
.ConvertToStore(iValue
->pItem
)) {
2035 a_oOutput
.Write("=");
2036 if (m_bAllowMultiLine
&& IsMultiLineData(iValue
->pItem
)) {
2037 // multi-line data needs to be processed specially to ensure
2038 // that we use the correct newline format for the current system
2039 a_oOutput
.Write("<<<SI-END-OF-MULTILINE-TEXT" SI_NEWLINE_A
);
2040 if (!OutputMultiLineText(a_oOutput
, convert
, iValue
->pItem
)) {
2043 a_oOutput
.Write("SI-END-OF-MULTILINE-TEXT");
2046 a_oOutput
.Write(convert
.Data());
2048 a_oOutput
.Write(SI_NEWLINE_A
);
2052 bNeedNewLine
= true;
2058 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
2060 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::OutputMultiLineText(
2061 OutputWriter
& a_oOutput
,
2062 Converter
& a_oConverter
,
2063 const SI_CHAR
* a_pText
2066 const SI_CHAR
* pEndOfLine
;
2067 SI_CHAR cEndOfLineChar
= *a_pText
;
2068 while (cEndOfLineChar
) {
2069 // find the end of this line
2070 pEndOfLine
= a_pText
;
2071 for (; *pEndOfLine
&& *pEndOfLine
!= '\n'; ++pEndOfLine
) /*loop*/ ;
2072 cEndOfLineChar
= *pEndOfLine
;
2074 // temporarily null terminate, convert and output the line
2075 *const_cast<SI_CHAR
*>(pEndOfLine
) = 0;
2076 if (!a_oConverter
.ConvertToStore(a_pText
)) {
2079 *const_cast<SI_CHAR
*>(pEndOfLine
) = cEndOfLineChar
;
2080 a_pText
+= (pEndOfLine
- a_pText
) + 1;
2081 a_oOutput
.Write(a_oConverter
.Data());
2082 a_oOutput
.Write(SI_NEWLINE_A
);
2087 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
2089 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::Delete(
2090 const SI_CHAR
* a_pSection
,
2091 const SI_CHAR
* a_pKey
,
2099 typename
TSection::iterator iSection
= m_data
.find(a_pSection
);
2100 if (iSection
== m_data
.end()) {
2104 // remove a single key if we have a keyname
2106 typename
TKeyVal::iterator iKeyVal
= iSection
->second
.find(a_pKey
);
2107 if (iKeyVal
== iSection
->second
.end()) {
2111 // remove any copied strings and then the key
2112 typename
TKeyVal::iterator iDelete
;
2114 iDelete
= iKeyVal
++;
2116 DeleteString(iDelete
->first
.pItem
);
2117 DeleteString(iDelete
->second
);
2118 iSection
->second
.erase(iDelete
);
2120 while (iKeyVal
!= iSection
->second
.end()
2121 && !IsLess(a_pKey
, iKeyVal
->first
.pItem
));
2123 // done now if the section is not empty or we are not pruning away
2124 // the empty sections. Otherwise let it fall through into the section
2126 if (!a_bRemoveEmpty
|| !iSection
->second
.empty()) {
2131 // delete all copied strings from this section. The actual
2132 // entries will be removed when the section is removed.
2133 typename
TKeyVal::iterator iKeyVal
= iSection
->second
.begin();
2134 for ( ; iKeyVal
!= iSection
->second
.end(); ++iKeyVal
) {
2135 DeleteString(iKeyVal
->first
.pItem
);
2136 DeleteString(iKeyVal
->second
);
2140 // delete the section itself
2141 DeleteString(iSection
->first
.pItem
);
2142 m_data
.erase(iSection
);
2147 template<class SI_CHAR
, class SI_STRLESS
, class SI_CONVERTER
>
2149 CSimpleIniTempl
<SI_CHAR
,SI_STRLESS
,SI_CONVERTER
>::DeleteString(
2150 const SI_CHAR
* a_pString
2153 // strings may exist either inside the data block, or they will be
2154 // individually allocated and stored in m_strings. We only physically
2155 // delete those stored in m_strings.
2156 if (a_pString
< m_pData
|| a_pString
>= m_pData
+ m_uDataLen
) {
2157 typename
TNamesDepend::iterator i
= m_strings
.begin();
2158 for (;i
!= m_strings
.end(); ++i
) {
2159 if (a_pString
== i
->pItem
) {
2160 delete[] const_cast<SI_CHAR
*>(i
->pItem
);
2168 // ---------------------------------------------------------------------------
2169 // CONVERSION FUNCTIONS
2170 // ---------------------------------------------------------------------------
2172 // Defines the conversion classes for different libraries. Before including
2173 // SimpleIni.h, set the converter that you wish you use by defining one of the
2174 // following symbols.
2176 // SI_CONVERT_GENERIC Use the Unicode reference conversion library in
2177 // the accompanying files ConvertUTF.h/c
2178 // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
2179 // ICU headers on include path and icuuc.lib
2180 // SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
2182 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
2184 # define SI_CONVERT_WIN32
2186 # define SI_CONVERT_GENERIC
2191 * Generic case-sensitive less than comparison. This class returns numerically
2192 * ordered ASCII case-sensitive text for all possible sizes and types of
2195 template<class SI_CHAR
>
2196 struct SI_GenericCase
{
2197 bool operator()(const SI_CHAR
* pLeft
, const SI_CHAR
* pRight
) const {
2199 for ( ;*pLeft
&& *pRight
; ++pLeft
, ++pRight
) {
2200 cmp
= (long) *pLeft
- (long) *pRight
;
2205 return *pRight
!= 0;
2210 * Generic ASCII case-insensitive less than comparison. This class returns
2211 * numerically ordered ASCII case-insensitive text for all possible sizes
2212 * and types of SI_CHAR. It is not safe for MBCS text comparison where
2213 * ASCII A-Z characters are used in the encoding of multi-byte characters.
2215 template<class SI_CHAR
>
2216 struct SI_GenericNoCase
{
2217 inline SI_CHAR
locase(SI_CHAR ch
) const {
2218 return (ch
< 'A' || ch
> 'Z') ? ch
: (ch
- 'A' + 'a');
2220 bool operator()(const SI_CHAR
* pLeft
, const SI_CHAR
* pRight
) const {
2222 for ( ;*pLeft
&& *pRight
; ++pLeft
, ++pRight
) {
2223 cmp
= (long) locase(*pLeft
) - (long) locase(*pRight
);
2228 return *pRight
!= 0;
2233 * Null conversion class for MBCS/UTF-8 to char (or equivalent).
2235 template<class SI_CHAR
>
2237 bool m_bStoreIsUtf8
;
2241 SI_ConvertA(bool a_bStoreIsUtf8
) : m_bStoreIsUtf8(a_bStoreIsUtf8
) { }
2243 /* copy and assignment */
2244 SI_ConvertA(const SI_ConvertA
& rhs
) { operator=(rhs
); }
2245 SI_ConvertA
& operator=(const SI_ConvertA
& rhs
) {
2246 m_bStoreIsUtf8
= rhs
.m_bStoreIsUtf8
;
2250 /** Calculate the number of SI_CHAR required for converting the input
2251 * from the storage format. The storage format is always UTF-8 or MBCS.
2253 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
2254 * @param a_uInputDataLen Length of storage format data in bytes. This
2255 * must be the actual length of the data, including
2256 * NULL byte if NULL terminated string is required.
2257 * @return Number of SI_CHAR required by the string when
2258 * converted. If there are embedded NULL bytes in the
2259 * input data, only the string up and not including
2260 * the NULL byte will be converted.
2261 * @return -1 cast to size_t on a conversion error.
2263 size_t SizeFromStore(
2264 const char * a_pInputData
,
2265 size_t a_uInputDataLen
)
2268 SI_ASSERT(a_uInputDataLen
!= (size_t) -1);
2270 // ASCII/MBCS/UTF-8 needs no conversion
2271 return a_uInputDataLen
;
2274 /** Convert the input string from the storage format to SI_CHAR.
2275 * The storage format is always UTF-8 or MBCS.
2277 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
2278 * @param a_uInputDataLen Length of storage format data in bytes. This
2279 * must be the actual length of the data, including
2280 * NULL byte if NULL terminated string is required.
2281 * @param a_pOutputData Pointer to the output buffer to received the
2283 * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
2284 * @return true if all of the input data was successfully
2287 bool ConvertFromStore(
2288 const char * a_pInputData
,
2289 size_t a_uInputDataLen
,
2290 SI_CHAR
* a_pOutputData
,
2291 size_t a_uOutputDataSize
)
2293 // ASCII/MBCS/UTF-8 needs no conversion
2294 if (a_uInputDataLen
> a_uOutputDataSize
) {
2297 memcpy(a_pOutputData
, a_pInputData
, a_uInputDataLen
);
2301 /** Calculate the number of char required by the storage format of this
2302 * data. The storage format is always UTF-8 or MBCS.
2304 * @param a_pInputData NULL terminated string to calculate the number of
2305 * bytes required to be converted to storage format.
2306 * @return Number of bytes required by the string when
2307 * converted to storage format. This size always
2308 * includes space for the terminating NULL character.
2309 * @return -1 cast to size_t on a conversion error.
2312 const SI_CHAR
* a_pInputData
)
2314 // ASCII/MBCS/UTF-8 needs no conversion
2315 return strlen((const char *)a_pInputData
) + 1;
2318 /** Convert the input string to the storage format of this data.
2319 * The storage format is always UTF-8 or MBCS.
2321 * @param a_pInputData NULL terminated source string to convert. All of
2322 * the data will be converted including the
2323 * terminating NULL character.
2324 * @param a_pOutputData Pointer to the buffer to receive the converted
2326 * @param a_uOutputDataSize Size of the output buffer in char.
2327 * @return true if all of the input data, including the
2328 * terminating NULL character was successfully
2331 bool ConvertToStore(
2332 const SI_CHAR
* a_pInputData
,
2333 char * a_pOutputData
,
2334 size_t a_uOutputDataSize
)
2336 // calc input string length (SI_CHAR type and size independent)
2337 size_t uInputLen
= strlen((const char *)a_pInputData
) + 1;
2338 if (uInputLen
> a_uOutputDataSize
) {
2342 // ascii/UTF-8 needs no conversion
2343 memcpy(a_pOutputData
, a_pInputData
, uInputLen
);
2349 // ---------------------------------------------------------------------------
2350 // SI_CONVERT_GENERIC
2351 // ---------------------------------------------------------------------------
2352 #ifdef SI_CONVERT_GENERIC
2354 #define SI_Case SI_GenericCase
2355 #define SI_NoCase SI_GenericNoCase
2358 #include "ConvertUTF.h"
2361 * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference
2362 * library functions. This can be used on all platforms.
2364 template<class SI_CHAR
>
2366 bool m_bStoreIsUtf8
;
2370 SI_ConvertW(bool a_bStoreIsUtf8
) : m_bStoreIsUtf8(a_bStoreIsUtf8
) { }
2372 /* copy and assignment */
2373 SI_ConvertW(const SI_ConvertW
& rhs
) { operator=(rhs
); }
2374 SI_ConvertW
& operator=(const SI_ConvertW
& rhs
) {
2375 m_bStoreIsUtf8
= rhs
.m_bStoreIsUtf8
;
2379 /** Calculate the number of SI_CHAR required for converting the input
2380 * from the storage format. The storage format is always UTF-8 or MBCS.
2382 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
2383 * @param a_uInputDataLen Length of storage format data in bytes. This
2384 * must be the actual length of the data, including
2385 * NULL byte if NULL terminated string is required.
2386 * @return Number of SI_CHAR required by the string when
2387 * converted. If there are embedded NULL bytes in the
2388 * input data, only the string up and not including
2389 * the NULL byte will be converted.
2390 * @return -1 cast to size_t on a conversion error.
2392 size_t SizeFromStore(
2393 const char * a_pInputData
,
2394 size_t a_uInputDataLen
)
2396 SI_ASSERT(a_uInputDataLen
!= (size_t) -1);
2398 if (m_bStoreIsUtf8
) {
2399 // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
2400 // so we just return the same number of characters required as for
2402 return a_uInputDataLen
;
2405 return mbstowcs(NULL
, a_pInputData
, a_uInputDataLen
);
2409 /** Convert the input string from the storage format to SI_CHAR.
2410 * The storage format is always UTF-8 or MBCS.
2412 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
2413 * @param a_uInputDataLen Length of storage format data in bytes. This
2414 * must be the actual length of the data, including
2415 * NULL byte if NULL terminated string is required.
2416 * @param a_pOutputData Pointer to the output buffer to received the
2418 * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
2419 * @return true if all of the input data was successfully
2422 bool ConvertFromStore(
2423 const char * a_pInputData
,
2424 size_t a_uInputDataLen
,
2425 SI_CHAR
* a_pOutputData
,
2426 size_t a_uOutputDataSize
)
2428 if (m_bStoreIsUtf8
) {
2429 // This uses the Unicode reference implementation to do the
2430 // conversion from UTF-8 to wchar_t. The required files are
2431 // ConvertUTF.h and ConvertUTF.c which should be included in
2432 // the distribution but are publically available from unicode.org
2433 // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
2434 ConversionResult retval
;
2435 const UTF8
* pUtf8
= (const UTF8
*) a_pInputData
;
2436 if (sizeof(wchar_t) == sizeof(UTF32
)) {
2437 UTF32
* pUtf32
= (UTF32
*) a_pOutputData
;
2438 retval
= ConvertUTF8toUTF32(
2439 &pUtf8
, pUtf8
+ a_uInputDataLen
,
2440 &pUtf32
, pUtf32
+ a_uOutputDataSize
,
2443 else if (sizeof(wchar_t) == sizeof(UTF16
)) {
2444 UTF16
* pUtf16
= (UTF16
*) a_pOutputData
;
2445 retval
= ConvertUTF8toUTF16(
2446 &pUtf8
, pUtf8
+ a_uInputDataLen
,
2447 &pUtf16
, pUtf16
+ a_uOutputDataSize
,
2450 return retval
== conversionOK
;
2453 size_t retval
= mbstowcs(a_pOutputData
,
2454 a_pInputData
, a_uOutputDataSize
);
2455 return retval
!= (size_t)(-1);
2459 /** Calculate the number of char required by the storage format of this
2460 * data. The storage format is always UTF-8 or MBCS.
2462 * @param a_pInputData NULL terminated string to calculate the number of
2463 * bytes required to be converted to storage format.
2464 * @return Number of bytes required by the string when
2465 * converted to storage format. This size always
2466 * includes space for the terminating NULL character.
2467 * @return -1 cast to size_t on a conversion error.
2470 const SI_CHAR
* a_pInputData
)
2472 if (m_bStoreIsUtf8
) {
2473 // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
2475 while (a_pInputData
[uLen
]) {
2478 return (6 * uLen
) + 1;
2481 size_t uLen
= wcstombs(NULL
, a_pInputData
, 0);
2482 if (uLen
== (size_t)(-1)) {
2485 return uLen
+ 1; // include NULL terminator
2489 /** Convert the input string to the storage format of this data.
2490 * The storage format is always UTF-8 or MBCS.
2492 * @param a_pInputData NULL terminated source string to convert. All of
2493 * the data will be converted including the
2494 * terminating NULL character.
2495 * @param a_pOutputData Pointer to the buffer to receive the converted
2497 * @param a_uOutputDataSize Size of the output buffer in char.
2498 * @return true if all of the input data, including the
2499 * terminating NULL character was successfully
2502 bool ConvertToStore(
2503 const SI_CHAR
* a_pInputData
,
2504 char * a_pOutputData
,
2505 size_t a_uOutputDataSize
2508 if (m_bStoreIsUtf8
) {
2509 // calc input string length (SI_CHAR type and size independent)
2510 size_t uInputLen
= 0;
2511 while (a_pInputData
[uInputLen
]) {
2514 ++uInputLen
; // include the NULL char
2516 // This uses the Unicode reference implementation to do the
2517 // conversion from wchar_t to UTF-8. The required files are
2518 // ConvertUTF.h and ConvertUTF.c which should be included in
2519 // the distribution but are publically available from unicode.org
2520 // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
2521 ConversionResult retval
;
2522 UTF8
* pUtf8
= (UTF8
*) a_pOutputData
;
2523 if (sizeof(wchar_t) == sizeof(UTF32
)) {
2524 const UTF32
* pUtf32
= (const UTF32
*) a_pInputData
;
2525 retval
= ConvertUTF32toUTF8(
2526 &pUtf32
, pUtf32
+ uInputLen
+ 1,
2527 &pUtf8
, pUtf8
+ a_uOutputDataSize
,
2530 else if (sizeof(wchar_t) == sizeof(UTF16
)) {
2531 const UTF16
* pUtf16
= (const UTF16
*) a_pInputData
;
2532 retval
= ConvertUTF16toUTF8(
2533 &pUtf16
, pUtf16
+ uInputLen
+ 1,
2534 &pUtf8
, pUtf8
+ a_uOutputDataSize
,
2537 return retval
== conversionOK
;
2540 size_t retval
= wcstombs(a_pOutputData
,
2541 a_pInputData
, a_uOutputDataSize
);
2542 return retval
!= (size_t) -1;
2547 #endif // SI_CONVERT_GENERIC
2550 // ---------------------------------------------------------------------------
2552 // ---------------------------------------------------------------------------
2553 #ifdef SI_CONVERT_ICU
2555 #define SI_Case SI_GenericCase
2556 #define SI_NoCase SI_GenericNoCase
2558 #include <unicode/ucnv.h>
2561 * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms.
2563 template<class SI_CHAR
>
2565 const char * m_pEncoding
;
2566 UConverter
* m_pConverter
;
2568 SI_ConvertW() : m_pEncoding(NULL
), m_pConverter(NULL
) { }
2570 SI_ConvertW(bool a_bStoreIsUtf8
) : m_pConverter(NULL
) {
2571 m_pEncoding
= a_bStoreIsUtf8
? "UTF-8" : NULL
;
2574 /* copy and assignment */
2575 SI_ConvertW(const SI_ConvertW
& rhs
) { operator=(rhs
); }
2576 SI_ConvertW
& operator=(const SI_ConvertW
& rhs
) {
2577 m_pEncoding
= rhs
.m_pEncoding
;
2578 m_pConverter
= NULL
;
2581 ~SI_ConvertW() { if (m_pConverter
) ucnv_close(m_pConverter
); }
2583 /** Calculate the number of UChar required for converting the input
2584 * from the storage format. The storage format is always UTF-8 or MBCS.
2586 * @param a_pInputData Data in storage format to be converted to UChar.
2587 * @param a_uInputDataLen Length of storage format data in bytes. This
2588 * must be the actual length of the data, including
2589 * NULL byte if NULL terminated string is required.
2590 * @return Number of UChar required by the string when
2591 * converted. If there are embedded NULL bytes in the
2592 * input data, only the string up and not including
2593 * the NULL byte will be converted.
2594 * @return -1 cast to size_t on a conversion error.
2596 size_t SizeFromStore(
2597 const char * a_pInputData
,
2598 size_t a_uInputDataLen
)
2600 SI_ASSERT(a_uInputDataLen
!= (size_t) -1);
2604 if (!m_pConverter
) {
2605 nError
= U_ZERO_ERROR
;
2606 m_pConverter
= ucnv_open(m_pEncoding
, &nError
);
2607 if (U_FAILURE(nError
)) {
2612 nError
= U_ZERO_ERROR
;
2613 ucnv_resetToUnicode(m_pConverter
);
2614 int32_t nLen
= ucnv_toUChars(m_pConverter
, NULL
, 0,
2615 a_pInputData
, (int32_t) a_uInputDataLen
, &nError
);
2616 if (nError
!= U_BUFFER_OVERFLOW_ERROR
) {
2620 return (size_t) nLen
;
2623 /** Convert the input string from the storage format to UChar.
2624 * The storage format is always UTF-8 or MBCS.
2626 * @param a_pInputData Data in storage format to be converted to UChar.
2627 * @param a_uInputDataLen Length of storage format data in bytes. This
2628 * must be the actual length of the data, including
2629 * NULL byte if NULL terminated string is required.
2630 * @param a_pOutputData Pointer to the output buffer to received the
2632 * @param a_uOutputDataSize Size of the output buffer in UChar.
2633 * @return true if all of the input data was successfully
2636 bool ConvertFromStore(
2637 const char * a_pInputData
,
2638 size_t a_uInputDataLen
,
2639 UChar
* a_pOutputData
,
2640 size_t a_uOutputDataSize
)
2644 if (!m_pConverter
) {
2645 nError
= U_ZERO_ERROR
;
2646 m_pConverter
= ucnv_open(m_pEncoding
, &nError
);
2647 if (U_FAILURE(nError
)) {
2652 nError
= U_ZERO_ERROR
;
2653 ucnv_resetToUnicode(m_pConverter
);
2654 ucnv_toUChars(m_pConverter
,
2655 a_pOutputData
, (int32_t) a_uOutputDataSize
,
2656 a_pInputData
, (int32_t) a_uInputDataLen
, &nError
);
2657 if (U_FAILURE(nError
)) {
2664 /** Calculate the number of char required by the storage format of this
2665 * data. The storage format is always UTF-8 or MBCS.
2667 * @param a_pInputData NULL terminated string to calculate the number of
2668 * bytes required to be converted to storage format.
2669 * @return Number of bytes required by the string when
2670 * converted to storage format. This size always
2671 * includes space for the terminating NULL character.
2672 * @return -1 cast to size_t on a conversion error.
2675 const UChar
* a_pInputData
)
2679 if (!m_pConverter
) {
2680 nError
= U_ZERO_ERROR
;
2681 m_pConverter
= ucnv_open(m_pEncoding
, &nError
);
2682 if (U_FAILURE(nError
)) {
2687 nError
= U_ZERO_ERROR
;
2688 ucnv_resetFromUnicode(m_pConverter
);
2689 int32_t nLen
= ucnv_fromUChars(m_pConverter
, NULL
, 0,
2690 a_pInputData
, -1, &nError
);
2691 if (nError
!= U_BUFFER_OVERFLOW_ERROR
) {
2695 return (size_t) nLen
+ 1;
2698 /** Convert the input string to the storage format of this data.
2699 * The storage format is always UTF-8 or MBCS.
2701 * @param a_pInputData NULL terminated source string to convert. All of
2702 * the data will be converted including the
2703 * terminating NULL character.
2704 * @param a_pOutputData Pointer to the buffer to receive the converted
2706 * @param a_pOutputDataSize Size of the output buffer in char.
2707 * @return true if all of the input data, including the
2708 * terminating NULL character was successfully
2711 bool ConvertToStore(
2712 const UChar
* a_pInputData
,
2713 char * a_pOutputData
,
2714 size_t a_uOutputDataSize
)
2718 if (!m_pConverter
) {
2719 nError
= U_ZERO_ERROR
;
2720 m_pConverter
= ucnv_open(m_pEncoding
, &nError
);
2721 if (U_FAILURE(nError
)) {
2726 nError
= U_ZERO_ERROR
;
2727 ucnv_resetFromUnicode(m_pConverter
);
2728 ucnv_fromUChars(m_pConverter
,
2729 a_pOutputData
, (int32_t) a_uOutputDataSize
,
2730 a_pInputData
, -1, &nError
);
2731 if (U_FAILURE(nError
)) {
2739 #endif // SI_CONVERT_ICU
2742 // ---------------------------------------------------------------------------
2744 // ---------------------------------------------------------------------------
2745 #ifdef SI_CONVERT_WIN32
2747 #define SI_Case SI_GenericCase
2749 // Windows CE doesn't have errno or MBCS libraries
2756 #include <windows.h>
2758 # define SI_NoCase SI_GenericNoCase
2759 #else // !SI_NO_MBCS
2761 * Case-insensitive comparison class using Win32 MBCS functions. This class
2762 * returns a case-insensitive semi-collation order for MBCS text. It may not
2763 * be safe for UTF-8 text returned in char format as we don't know what
2764 * characters will be folded by the function! Therefore, if you are using
2765 * SI_CHAR == char and SetUnicode(true), then you need to use the generic
2766 * SI_NoCase class instead.
2768 #include <mbstring.h>
2769 template<class SI_CHAR
>
2771 bool operator()(const SI_CHAR
* pLeft
, const SI_CHAR
* pRight
) const {
2772 if (sizeof(SI_CHAR
) == sizeof(char)) {
2773 return _mbsicmp((const unsigned char *)pLeft
,
2774 (const unsigned char *)pRight
) < 0;
2776 if (sizeof(SI_CHAR
) == sizeof(wchar_t)) {
2777 return _wcsicmp((const wchar_t *)pLeft
,
2778 (const wchar_t *)pRight
) < 0;
2780 return SI_GenericNoCase
<SI_CHAR
>()(pLeft
, pRight
);
2783 #endif // SI_NO_MBCS
2786 * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses
2787 * only the Win32 functions and doesn't require the external Unicode UTF-8
2788 * conversion library. It will not work on Windows 95 without using Microsoft
2789 * Layer for Unicode in your application.
2791 template<class SI_CHAR
>
2797 SI_ConvertW(bool a_bStoreIsUtf8
) {
2798 m_uCodePage
= a_bStoreIsUtf8
? CP_UTF8
: CP_ACP
;
2801 /* copy and assignment */
2802 SI_ConvertW(const SI_ConvertW
& rhs
) { operator=(rhs
); }
2803 SI_ConvertW
& operator=(const SI_ConvertW
& rhs
) {
2804 m_uCodePage
= rhs
.m_uCodePage
;
2808 /** Calculate the number of SI_CHAR required for converting the input
2809 * from the storage format. The storage format is always UTF-8 or MBCS.
2811 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
2812 * @param a_uInputDataLen Length of storage format data in bytes. This
2813 * must be the actual length of the data, including
2814 * NULL byte if NULL terminated string is required.
2815 * @return Number of SI_CHAR required by the string when
2816 * converted. If there are embedded NULL bytes in the
2817 * input data, only the string up and not including
2818 * the NULL byte will be converted.
2819 * @return -1 cast to size_t on a conversion error.
2821 size_t SizeFromStore(
2822 const char * a_pInputData
,
2823 size_t a_uInputDataLen
)
2825 SI_ASSERT(a_uInputDataLen
!= (size_t) -1);
2827 int retval
= MultiByteToWideChar(
2829 a_pInputData
, (int) a_uInputDataLen
,
2831 return (size_t)(retval
> 0 ? retval
: -1);
2834 /** Convert the input string from the storage format to SI_CHAR.
2835 * The storage format is always UTF-8 or MBCS.
2837 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
2838 * @param a_uInputDataLen Length of storage format data in bytes. This
2839 * must be the actual length of the data, including
2840 * NULL byte if NULL terminated string is required.
2841 * @param a_pOutputData Pointer to the output buffer to received the
2843 * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
2844 * @return true if all of the input data was successfully
2847 bool ConvertFromStore(
2848 const char * a_pInputData
,
2849 size_t a_uInputDataLen
,
2850 SI_CHAR
* a_pOutputData
,
2851 size_t a_uOutputDataSize
)
2853 int nSize
= MultiByteToWideChar(
2855 a_pInputData
, (int) a_uInputDataLen
,
2856 (wchar_t *) a_pOutputData
, (int) a_uOutputDataSize
);
2860 /** Calculate the number of char required by the storage format of this
2861 * data. The storage format is always UTF-8.
2863 * @param a_pInputData NULL terminated string to calculate the number of
2864 * bytes required to be converted to storage format.
2865 * @return Number of bytes required by the string when
2866 * converted to storage format. This size always
2867 * includes space for the terminating NULL character.
2868 * @return -1 cast to size_t on a conversion error.
2871 const SI_CHAR
* a_pInputData
)
2873 int retval
= WideCharToMultiByte(
2875 (const wchar_t *) a_pInputData
, -1,
2877 return (size_t) (retval
> 0 ? retval
: -1);
2880 /** Convert the input string to the storage format of this data.
2881 * The storage format is always UTF-8 or MBCS.
2883 * @param a_pInputData NULL terminated source string to convert. All of
2884 * the data will be converted including the
2885 * terminating NULL character.
2886 * @param a_pOutputData Pointer to the buffer to receive the converted
2888 * @param a_pOutputDataSize Size of the output buffer in char.
2889 * @return true if all of the input data, including the
2890 * terminating NULL character was successfully
2893 bool ConvertToStore(
2894 const SI_CHAR
* a_pInputData
,
2895 char * a_pOutputData
,
2896 size_t a_uOutputDataSize
)
2898 int retval
= WideCharToMultiByte(
2900 (const wchar_t *) a_pInputData
, -1,
2901 a_pOutputData
, (int) a_uOutputDataSize
, 0, 0);
2906 #endif // SI_CONVERT_WIN32
2909 // ---------------------------------------------------------------------------
2911 // ---------------------------------------------------------------------------
2913 typedef CSimpleIniTempl
<char,
2914 SI_NoCase
<char>,SI_ConvertA
<char> > CSimpleIniA
;
2915 typedef CSimpleIniTempl
<char,
2916 SI_Case
<char>,SI_ConvertA
<char> > CSimpleIniCaseA
;
2918 #if defined(SI_CONVERT_ICU)
2919 typedef CSimpleIniTempl
<UChar
,
2920 SI_NoCase
<UChar
>,SI_ConvertW
<UChar
> > CSimpleIniW
;
2921 typedef CSimpleIniTempl
<UChar
,
2922 SI_Case
<UChar
>,SI_ConvertW
<UChar
> > CSimpleIniCaseW
;
2924 typedef CSimpleIniTempl
<wchar_t,
2925 SI_NoCase
<wchar_t>,SI_ConvertW
<wchar_t> > CSimpleIniW
;
2926 typedef CSimpleIniTempl
<wchar_t,
2927 SI_Case
<wchar_t>,SI_ConvertW
<wchar_t> > CSimpleIniCaseW
;
2931 # define CSimpleIni CSimpleIniW
2932 # define CSimpleIniCase CSimpleIniCaseW
2933 # define SI_NEWLINE SI_NEWLINE_W
2935 # define CSimpleIni CSimpleIniA
2936 # define CSimpleIniCase CSimpleIniCaseA
2937 # define SI_NEWLINE SI_NEWLINE_A
2941 # pragma warning (pop)
2944 #endif // INCLUDED_SimpleIni_h