annotate src/Support/SimpleIni.h @ 16:2a5354042241

-Updated the Slaney IIR gammatone to use a cascase of four second-order filters as per the implementtion in Slaney's auditory toolbox. This is more numerically stable at high sample rates and low centre frequencies.
author tomwalters
date Sat, 20 Feb 2010 17:56:40 +0000
parents 582cbe817f2c
children e914b02b31b0
rev   line source
tomwalters@0 1 /** @mainpage
tomwalters@0 2
tomwalters@0 3 <table>
tomwalters@0 4 <tr><th>Library <td>SimpleIni
tomwalters@0 5 <tr><th>File <td>SimpleIni.h
tomwalters@0 6 <tr><th>Author <td>Brodie Thiesfield [code at jellycan dot com]
tomwalters@0 7 <tr><th>Source <td>http://code.jellycan.com/simpleini/
tomwalters@0 8 <tr><th>Version <td>4.12
tomwalters@0 9 </table>
tomwalters@0 10
tomwalters@0 11 Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation.
tomwalters@0 12
tomwalters@0 13 @section intro INTRODUCTION
tomwalters@0 14
tomwalters@0 15 This component allows an INI-style configuration file to be used on both
tomwalters@0 16 Windows and Linux/Unix. It is fast, simple and source code using this
tomwalters@0 17 component will compile unchanged on either OS.
tomwalters@0 18
tomwalters@0 19
tomwalters@0 20 @section features FEATURES
tomwalters@0 21
tomwalters@0 22 - MIT Licence allows free use in all software (including GPL and commercial)
tomwalters@0 23 - multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix)
tomwalters@0 24 - loading and saving of INI-style configuration files
tomwalters@0 25 - configuration files can have any newline format on all platforms
tomwalters@0 26 - liberal acceptance of file format
tomwalters@0 27 - key/values with no section
tomwalters@0 28 - removal of whitespace around sections, keys and values
tomwalters@0 29 - support for multi-line values (values with embedded newline characters)
tomwalters@0 30 - optional support for multiple keys with the same name
tomwalters@0 31 - optional case-insensitive sections and keys (for ASCII characters only)
tomwalters@0 32 - saves files with sections and keys in the same order as they were loaded
tomwalters@0 33 - preserves comments on the file, section and keys where possible.
tomwalters@0 34 - supports both char or wchar_t programming interfaces
tomwalters@0 35 - supports both MBCS (system locale) and UTF-8 file encodings
tomwalters@0 36 - system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file
tomwalters@0 37 - support for non-ASCII characters in section, keys, values and comments
tomwalters@0 38 - support for non-standard character types or file encodings
tomwalters@0 39 via user-written converter classes
tomwalters@0 40 - support for adding/modifying values programmatically
tomwalters@0 41 - compiles cleanly in the following compilers:
tomwalters@0 42 - Windows/VC6 (warning level 3)
tomwalters@0 43 - Windows/VC.NET 2003 (warning level 4)
tomwalters@0 44 - Windows/VC 2005 (warning level 4)
tomwalters@0 45 - Linux/gcc (-Wall)
tomwalters@0 46
tomwalters@0 47
tomwalters@0 48 @section usage USAGE SUMMARY
tomwalters@0 49
tomwalters@0 50 -# Define the appropriate symbol for the converter you wish to use and
tomwalters@0 51 include the SimpleIni.h header file. If no specific converter is defined
tomwalters@0 52 then the default converter is used. The default conversion mode uses
tomwalters@0 53 SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other
tomwalters@0 54 platforms. If you are using ICU then SI_CONVERT_ICU is supported on all
tomwalters@0 55 platforms.
tomwalters@0 56 -# Declare an instance the appropriate class. Note that the following
tomwalters@0 57 definitions are just shortcuts for commonly used types. Other types
tomwalters@0 58 (PRUnichar, unsigned short, unsigned char) are also possible.
tomwalters@0 59 <table>
tomwalters@0 60 <tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef
tomwalters@0 61 <tr><th>SI_CONVERT_GENERIC
tomwalters@0 62 <tr><td>char <td>No <td>Yes <td>Yes #1 <td>CSimpleIniA
tomwalters@0 63 <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
tomwalters@0 64 <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
tomwalters@0 65 <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
tomwalters@0 66 <tr><th>SI_CONVERT_WIN32
tomwalters@0 67 <tr><td>char <td>No <td>No #2 <td>Yes <td>CSimpleIniA
tomwalters@0 68 <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
tomwalters@0 69 <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
tomwalters@0 70 <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
tomwalters@0 71 <tr><th>SI_CONVERT_ICU
tomwalters@0 72 <tr><td>char <td>No <td>Yes <td>Yes <td>CSimpleIniA
tomwalters@0 73 <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
tomwalters@0 74 <tr><td>UChar <td>No <td>Yes <td>Yes <td>CSimpleIniW
tomwalters@0 75 <tr><td>UChar <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
tomwalters@0 76 </table>
tomwalters@0 77 #1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.<br>
tomwalters@0 78 #2 Only affects Windows. On Windows this uses MBCS functions and
tomwalters@0 79 so may fold case incorrectly leading to uncertain results.
tomwalters@0 80 -# Call Load() or LoadFile() to load and parse the INI configuration file
tomwalters@0 81 -# Access and modify the data of the file using the following functions
tomwalters@0 82 <table>
tomwalters@0 83 <tr><td>GetAllSections <td>Return all section names
tomwalters@0 84 <tr><td>GetAllKeys <td>Return all key names within a section
tomwalters@0 85 <tr><td>GetAllValues <td>Return all values within a section & key
tomwalters@0 86 <tr><td>GetSection <td>Return all key names and values in a section
tomwalters@0 87 <tr><td>GetSectionSize <td>Return the number of keys in a section
tomwalters@0 88 <tr><td>GetValue <td>Return a value for a section & key
tomwalters@0 89 <tr><td>SetValue <td>Add or update a value for a section & key
tomwalters@0 90 <tr><td>Delete <td>Remove a section, or a key from a section
tomwalters@0 91 </table>
tomwalters@0 92 -# Call Save() or SaveFile() to save the INI configuration data
tomwalters@0 93
tomwalters@0 94 @section iostreams IO STREAMS
tomwalters@0 95
tomwalters@0 96 SimpleIni supports reading from and writing to STL IO streams. Enable this
tomwalters@0 97 by defining SI_SUPPORT_IOSTREAMS before including the SimpleIni.h header
tomwalters@0 98 file. Ensure that if the streams are backed by a file (e.g. ifstream or
tomwalters@0 99 ofstream) then the flag ios_base::binary has been used when the file was
tomwalters@0 100 opened.
tomwalters@0 101
tomwalters@0 102 @section multiline MULTI-LINE VALUES
tomwalters@0 103
tomwalters@0 104 Values that span multiple lines are created using the following format.
tomwalters@0 105
tomwalters@0 106 <pre>
tomwalters@0 107 key = <<<ENDTAG
tomwalters@0 108 .... multiline value ....
tomwalters@0 109 ENDTAG
tomwalters@0 110 </pre>
tomwalters@0 111
tomwalters@0 112 Note the following:
tomwalters@0 113 - The text used for ENDTAG can be anything and is used to find
tomwalters@0 114 where the multi-line text ends.
tomwalters@0 115 - The newline after ENDTAG in the start tag, and the newline
tomwalters@0 116 before ENDTAG in the end tag is not included in the data value.
tomwalters@0 117 - The ending tag must be on it's own line with no whitespace before
tomwalters@0 118 or after it.
tomwalters@0 119 - The multi-line value is modified at load so that each line in the value
tomwalters@0 120 is delimited by a single '\\n' character on all platforms. At save time
tomwalters@0 121 it will be converted into the newline format used by the current
tomwalters@0 122 platform.
tomwalters@0 123
tomwalters@0 124 @section comments COMMENTS
tomwalters@0 125
tomwalters@0 126 Comments are preserved in the file within the following restrictions:
tomwalters@0 127 - Every file may have a single "file comment". It must start with the
tomwalters@0 128 first character in the file, and will end with the first non-comment
tomwalters@0 129 line in the file.
tomwalters@0 130 - Every section may have a single "section comment". It will start
tomwalters@0 131 with the first comment line following the file comment, or the last
tomwalters@0 132 data entry. It ends at the beginning of the section.
tomwalters@0 133 - Every key may have a single "key comment". This comment will start
tomwalters@0 134 with the first comment line following the section start, or the file
tomwalters@0 135 comment if there is no section name.
tomwalters@0 136 - Comments are set at the time that the file, section or key is first
tomwalters@0 137 created. The only way to modify a comment on a section or a key is to
tomwalters@0 138 delete that entry and recreate it with the new comment. There is no
tomwalters@0 139 way to change the file comment.
tomwalters@0 140
tomwalters@0 141 @section save SAVE ORDER
tomwalters@0 142
tomwalters@0 143 The sections and keys are written out in the same order as they were
tomwalters@0 144 read in from the file. Sections and keys added to the data after the
tomwalters@0 145 file has been loaded will be added to the end of the file when it is
tomwalters@0 146 written. There is no way to specify the location of a section or key
tomwalters@0 147 other than in first-created, first-saved order.
tomwalters@0 148
tomwalters@0 149 @section notes NOTES
tomwalters@0 150
tomwalters@0 151 - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
tomwalters@0 152 Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU.
tomwalters@0 153 - When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
tomwalters@0 154 - When using SI_CONVERT_ICU, ICU header files must be on the include
tomwalters@0 155 path and icuuc.lib must be linked in.
tomwalters@0 156 - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
tomwalters@0 157 you should use SI_CONVERT_GENERIC.
tomwalters@0 158 - The collation (sorting) order used for sections and keys returned from
tomwalters@0 159 iterators is NOT DEFINED. If collation order of the text is important
tomwalters@0 160 then it should be done yourself by either supplying a replacement
tomwalters@0 161 SI_STRLESS class, or by sorting the strings external to this library.
tomwalters@0 162 - Usage of the <mbstring.h> header on Windows can be disabled by defining
tomwalters@0 163 SI_NO_MBCS. This is defined automatically on Windows CE platforms.
tomwalters@0 164
tomwalters@0 165
tomwalters@0 166 @section licence MIT LICENCE
tomwalters@0 167
tomwalters@0 168 The licence text below is the boilerplate "MIT Licence" used from:
tomwalters@0 169 http://www.opensource.org/licenses/mit-license.php
tomwalters@0 170
tomwalters@0 171 Copyright (c) 2006-2008, Brodie Thiesfield
tomwalters@0 172
tomwalters@0 173 Permission is hereby granted, free of charge, to any person obtaining a copy
tomwalters@0 174 of this software and associated documentation files (the "Software"), to deal
tomwalters@0 175 in the Software without restriction, including without limitation the rights
tomwalters@0 176 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
tomwalters@0 177 copies of the Software, and to permit persons to whom the Software is furnished
tomwalters@0 178 to do so, subject to the following conditions:
tomwalters@0 179
tomwalters@0 180 The above copyright notice and this permission notice shall be included in
tomwalters@0 181 all copies or substantial portions of the Software.
tomwalters@0 182
tomwalters@0 183 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
tomwalters@0 184 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
tomwalters@0 185 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
tomwalters@0 186 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
tomwalters@0 187 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
tomwalters@0 188 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
tomwalters@0 189 */
tomwalters@0 190
tomwalters@0 191 #ifndef INCLUDED_SimpleIni_h
tomwalters@0 192 #define INCLUDED_SimpleIni_h
tomwalters@0 193
tomwalters@0 194 #if defined(_MSC_VER) && (_MSC_VER >= 1020)
tomwalters@0 195 # pragma once
tomwalters@0 196 #endif
tomwalters@0 197
tomwalters@0 198 // Disable these warnings in MSVC:
tomwalters@0 199 // 4127 "conditional expression is constant" as the conversion classes trigger
tomwalters@0 200 // it with the statement if (sizeof(SI_CHAR) == sizeof(char)). This test will
tomwalters@0 201 // be optimized away in a release build.
tomwalters@0 202 // 4503 'insert' : decorated name length exceeded, name was truncated
tomwalters@0 203 // 4702 "unreachable code" as the MS STL header causes it in release mode.
tomwalters@0 204 // Again, the code causing the warning will be cleaned up by the compiler.
tomwalters@0 205 // 4786 "identifier truncated to 256 characters" as this is thrown hundreds
tomwalters@0 206 // of times VC6 as soon as STL is used.
tomwalters@0 207 #ifdef _MSC_VER
tomwalters@0 208 # pragma warning (push)
tomwalters@0 209 # pragma warning (disable: 4127 4503 4702 4786)
tomwalters@0 210 #endif
tomwalters@0 211
tomwalters@0 212 #include <cstring>
tomwalters@0 213 #include <string>
tomwalters@0 214 #include <map>
tomwalters@0 215 #include <list>
tomwalters@0 216 #include <algorithm>
tomwalters@0 217 #include <stdio.h>
tomwalters@0 218
tomwalters@0 219 #ifdef SI_SUPPORT_IOSTREAMS
tomwalters@0 220 # include <iostream>
tomwalters@0 221 #endif // SI_SUPPORT_IOSTREAMS
tomwalters@0 222
tomwalters@0 223 #ifdef _DEBUG
tomwalters@0 224 # ifndef assert
tomwalters@0 225 # include <cassert>
tomwalters@0 226 # endif
tomwalters@0 227 # define SI_ASSERT(x) assert(x)
tomwalters@0 228 #else
tomwalters@0 229 # define SI_ASSERT(x)
tomwalters@0 230 #endif
tomwalters@0 231
tomwalters@0 232 enum SI_Error {
tomwalters@0 233 SI_OK = 0, //!< No error
tomwalters@0 234 SI_UPDATED = 1, //!< An existing value was updated
tomwalters@0 235 SI_INSERTED = 2, //!< A new value was inserted
tomwalters@0 236
tomwalters@0 237 // note: test for any error with (retval < 0)
tomwalters@0 238 SI_FAIL = -1, //!< Generic failure
tomwalters@0 239 SI_NOMEM = -2, //!< Out of memory error
tomwalters@0 240 SI_FILE = -3 //!< File error (see errno for detail error)
tomwalters@0 241 };
tomwalters@0 242
tomwalters@0 243 #define SI_UTF8_SIGNATURE "\xEF\xBB\xBF"
tomwalters@0 244
tomwalters@0 245 #ifdef _WIN32
tomwalters@0 246 # define SI_NEWLINE_A "\r\n"
tomwalters@0 247 # define SI_NEWLINE_W L"\r\n"
tomwalters@0 248 #else // !_WIN32
tomwalters@0 249 # define SI_NEWLINE_A "\n"
tomwalters@0 250 # define SI_NEWLINE_W L"\n"
tomwalters@0 251 #endif // _WIN32
tomwalters@0 252
tomwalters@0 253 #if defined(SI_CONVERT_ICU)
tomwalters@0 254 # include <unicode/ustring.h>
tomwalters@0 255 #endif
tomwalters@0 256
tomwalters@0 257 #if defined(_WIN32)
tomwalters@0 258 # define SI_HAS_WIDE_FILE
tomwalters@0 259 # define SI_WCHAR_T wchar_t
tomwalters@0 260 #elif defined(SI_CONVERT_ICU)
tomwalters@0 261 # define SI_HAS_WIDE_FILE
tomwalters@0 262 # define SI_WCHAR_T UChar
tomwalters@0 263 #endif
tomwalters@0 264
tomwalters@0 265
tomwalters@0 266 // ---------------------------------------------------------------------------
tomwalters@0 267 // MAIN TEMPLATE CLASS
tomwalters@0 268 // ---------------------------------------------------------------------------
tomwalters@0 269
tomwalters@0 270 /** Simple INI file reader.
tomwalters@0 271
tomwalters@0 272 This can be instantiated with the choice of unicode or native characterset,
tomwalters@0 273 and case sensitive or insensitive comparisons of section and key names.
tomwalters@0 274 The supported combinations are pre-defined with the following typedefs:
tomwalters@0 275
tomwalters@0 276 <table>
tomwalters@0 277 <tr><th>Interface <th>Case-sensitive <th>Typedef
tomwalters@0 278 <tr><td>char <td>No <td>CSimpleIniA
tomwalters@0 279 <tr><td>char <td>Yes <td>CSimpleIniCaseA
tomwalters@0 280 <tr><td>wchar_t <td>No <td>CSimpleIniW
tomwalters@0 281 <tr><td>wchar_t <td>Yes <td>CSimpleIniCaseW
tomwalters@0 282 </table>
tomwalters@0 283
tomwalters@0 284 Note that using other types for the SI_CHAR is supported. For instance,
tomwalters@0 285 unsigned char, unsigned short, etc. Note that where the alternative type
tomwalters@0 286 is a different size to char/wchar_t you may need to supply new helper
tomwalters@0 287 classes for SI_STRLESS and SI_CONVERTER.
tomwalters@0 288 */
tomwalters@0 289 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 290 class CSimpleIniTempl
tomwalters@0 291 {
tomwalters@0 292 public:
tomwalters@0 293 /** key entry */
tomwalters@0 294 struct Entry {
tomwalters@0 295 const SI_CHAR * pItem;
tomwalters@0 296 const SI_CHAR * pComment;
tomwalters@0 297 int nOrder;
tomwalters@0 298
tomwalters@0 299 Entry(const SI_CHAR * a_pszItem = NULL, int a_nOrder = 0)
tomwalters@0 300 : pItem(a_pszItem)
tomwalters@0 301 , pComment(NULL)
tomwalters@0 302 , nOrder(a_nOrder)
tomwalters@0 303 { }
tomwalters@0 304 Entry(const SI_CHAR * a_pszItem, const SI_CHAR * a_pszComment, int a_nOrder)
tomwalters@0 305 : pItem(a_pszItem)
tomwalters@0 306 , pComment(a_pszComment)
tomwalters@0 307 , nOrder(a_nOrder)
tomwalters@0 308 { }
tomwalters@0 309 Entry(const Entry & rhs) { operator=(rhs); }
tomwalters@0 310 Entry & operator=(const Entry & rhs) {
tomwalters@0 311 pItem = rhs.pItem;
tomwalters@0 312 pComment = rhs.pComment;
tomwalters@0 313 nOrder = rhs.nOrder;
tomwalters@0 314 return *this;
tomwalters@0 315 }
tomwalters@0 316
tomwalters@0 317 #if defined(_MSC_VER) && _MSC_VER <= 1200
tomwalters@0 318 /** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
tomwalters@0 319 bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
tomwalters@0 320 bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
tomwalters@0 321 #endif
tomwalters@0 322
tomwalters@0 323 /** Strict less ordering by name of key only */
tomwalters@0 324 struct KeyOrder : std::binary_function<Entry, Entry, bool> {
tomwalters@0 325 bool operator()(const Entry & lhs, const Entry & rhs) const {
tomwalters@0 326 const static SI_STRLESS isLess = SI_STRLESS();
tomwalters@0 327 return isLess(lhs.pItem, rhs.pItem);
tomwalters@0 328 }
tomwalters@0 329 };
tomwalters@0 330
tomwalters@0 331 /** Strict less ordering by order, and then name of key */
tomwalters@0 332 struct LoadOrder : std::binary_function<Entry, Entry, bool> {
tomwalters@0 333 bool operator()(const Entry & lhs, const Entry & rhs) const {
tomwalters@0 334 if (lhs.nOrder != rhs.nOrder) {
tomwalters@0 335 return lhs.nOrder < rhs.nOrder;
tomwalters@0 336 }
tomwalters@0 337 return KeyOrder()(lhs.pItem, rhs.pItem);
tomwalters@0 338 }
tomwalters@0 339 };
tomwalters@0 340 };
tomwalters@0 341
tomwalters@0 342 /** map keys to values */
tomwalters@0 343 typedef std::multimap<Entry,const SI_CHAR *,typename Entry::KeyOrder> TKeyVal;
tomwalters@0 344
tomwalters@0 345 /** map sections to key/value map */
tomwalters@0 346 typedef std::map<Entry,TKeyVal,typename Entry::KeyOrder> TSection;
tomwalters@0 347
tomwalters@0 348 /** set of dependent string pointers. Note that these pointers are
tomwalters@0 349 dependent on memory owned by CSimpleIni.
tomwalters@0 350 */
tomwalters@0 351 typedef std::list<Entry> TNamesDepend;
tomwalters@0 352
tomwalters@0 353 /** interface definition for the OutputWriter object to pass to Save()
tomwalters@0 354 in order to output the INI file data.
tomwalters@0 355 */
tomwalters@0 356 class OutputWriter {
tomwalters@0 357 public:
tomwalters@0 358 OutputWriter() { }
tomwalters@0 359 virtual ~OutputWriter() { }
tomwalters@0 360 virtual void Write(const char * a_pBuf) = 0;
tomwalters@0 361 private:
tomwalters@0 362 OutputWriter(const OutputWriter &); // disable
tomwalters@0 363 OutputWriter & operator=(const OutputWriter &); // disable
tomwalters@0 364 };
tomwalters@0 365
tomwalters@0 366 /** OutputWriter class to write the INI data to a file */
tomwalters@0 367 class FileWriter : public OutputWriter {
tomwalters@0 368 FILE * m_file;
tomwalters@0 369 public:
tomwalters@0 370 FileWriter(FILE * a_file) : m_file(a_file) { }
tomwalters@0 371 void Write(const char * a_pBuf) {
tomwalters@0 372 fputs(a_pBuf, m_file);
tomwalters@0 373 }
tomwalters@0 374 private:
tomwalters@0 375 FileWriter(const FileWriter &); // disable
tomwalters@0 376 FileWriter & operator=(const FileWriter &); // disable
tomwalters@0 377 };
tomwalters@0 378
tomwalters@0 379 /** OutputWriter class to write the INI data to a string */
tomwalters@0 380 class StringWriter : public OutputWriter {
tomwalters@0 381 std::string & m_string;
tomwalters@0 382 public:
tomwalters@0 383 StringWriter(std::string & a_string) : m_string(a_string) { }
tomwalters@0 384 void Write(const char * a_pBuf) {
tomwalters@0 385 m_string.append(a_pBuf);
tomwalters@0 386 }
tomwalters@0 387 private:
tomwalters@0 388 StringWriter(const StringWriter &); // disable
tomwalters@0 389 StringWriter & operator=(const StringWriter &); // disable
tomwalters@0 390 };
tomwalters@0 391
tomwalters@0 392 #ifdef SI_SUPPORT_IOSTREAMS
tomwalters@0 393 /** OutputWriter class to write the INI data to an ostream */
tomwalters@0 394 class StreamWriter : public OutputWriter {
tomwalters@0 395 std::ostream & m_ostream;
tomwalters@0 396 public:
tomwalters@0 397 StreamWriter(std::ostream & a_ostream) : m_ostream(a_ostream) { }
tomwalters@0 398 void Write(const char * a_pBuf) {
tomwalters@0 399 m_ostream << a_pBuf;
tomwalters@0 400 }
tomwalters@0 401 private:
tomwalters@0 402 StreamWriter(const StreamWriter &); // disable
tomwalters@0 403 StreamWriter & operator=(const StreamWriter &); // disable
tomwalters@0 404 };
tomwalters@0 405 #endif // SI_SUPPORT_IOSTREAMS
tomwalters@0 406
tomwalters@0 407 /** Characterset conversion utility class to convert strings to the
tomwalters@0 408 same format as is used for the storage.
tomwalters@0 409 */
tomwalters@0 410 class Converter : private SI_CONVERTER {
tomwalters@0 411 public:
tomwalters@0 412 Converter(bool a_bStoreIsUtf8) : SI_CONVERTER(a_bStoreIsUtf8) {
tomwalters@0 413 m_scratch.resize(1024);
tomwalters@0 414 }
tomwalters@0 415 Converter(const Converter & rhs) { operator=(rhs); }
tomwalters@0 416 Converter & operator=(const Converter & rhs) {
tomwalters@0 417 m_scratch = rhs.m_scratch;
tomwalters@0 418 return *this;
tomwalters@0 419 }
tomwalters@0 420 bool ConvertToStore(const SI_CHAR * a_pszString) {
tomwalters@0 421 size_t uLen = SizeToStore(a_pszString);
tomwalters@0 422 if (uLen == (size_t)(-1)) {
tomwalters@0 423 return false;
tomwalters@0 424 }
tomwalters@0 425 while (uLen > m_scratch.size()) {
tomwalters@0 426 m_scratch.resize(m_scratch.size() * 2);
tomwalters@0 427 }
tomwalters@0 428 return SI_CONVERTER::ConvertToStore(
tomwalters@0 429 a_pszString,
tomwalters@0 430 const_cast<char*>(m_scratch.data()),
tomwalters@0 431 m_scratch.size());
tomwalters@0 432 }
tomwalters@0 433 const char * Data() { return m_scratch.data(); }
tomwalters@0 434 private:
tomwalters@0 435 std::string m_scratch;
tomwalters@0 436 };
tomwalters@0 437
tomwalters@0 438 public:
tomwalters@0 439 /*-----------------------------------------------------------------------*/
tomwalters@0 440
tomwalters@0 441 /** Default constructor.
tomwalters@0 442
tomwalters@0 443 @param a_bIsUtf8 See the method SetUnicode() for details.
tomwalters@0 444 @param a_bMultiKey See the method SetMultiKey() for details.
tomwalters@0 445 @param a_bMultiLine See the method SetMultiLine() for details.
tomwalters@0 446 */
tomwalters@0 447 CSimpleIniTempl(
tomwalters@0 448 bool a_bIsUtf8 = false,
tomwalters@0 449 bool a_bMultiKey = false,
tomwalters@0 450 bool a_bMultiLine = false
tomwalters@0 451 );
tomwalters@0 452
tomwalters@0 453 /** Destructor */
tomwalters@0 454 ~CSimpleIniTempl();
tomwalters@0 455
tomwalters@0 456 /** Deallocate all memory stored by this object */
tomwalters@0 457 void Reset();
tomwalters@0 458
tomwalters@0 459 /*-----------------------------------------------------------------------*/
tomwalters@0 460 /** @{ @name Settings */
tomwalters@0 461
tomwalters@0 462 /** Set the storage format of the INI data. This affects both the loading
tomwalters@0 463 and saving of the INI data using all of the Load/Save API functions.
tomwalters@0 464 This value cannot be changed after any INI data has been loaded.
tomwalters@0 465
tomwalters@0 466 If the file is not set to Unicode (UTF-8), then the data encoding is
tomwalters@0 467 assumed to be the OS native encoding. This encoding is the system
tomwalters@0 468 locale on Linux/Unix and the legacy MBCS encoding on Windows NT/2K/XP.
tomwalters@0 469 If the storage format is set to Unicode then the file will be loaded
tomwalters@0 470 as UTF-8 encoded data regardless of the native file encoding. If
tomwalters@0 471 SI_CHAR == char then all of the char* parameters take and return UTF-8
tomwalters@0 472 encoded data regardless of the system locale.
tomwalters@0 473
tomwalters@0 474 \param a_bIsUtf8 Assume UTF-8 encoding for the source?
tomwalters@0 475 */
tomwalters@0 476 void SetUnicode(bool a_bIsUtf8 = true) {
tomwalters@0 477 if (!m_pData) m_bStoreIsUtf8 = a_bIsUtf8;
tomwalters@0 478 }
tomwalters@0 479
tomwalters@0 480 /** Get the storage format of the INI data. */
tomwalters@0 481 bool IsUnicode() const { return m_bStoreIsUtf8; }
tomwalters@0 482
tomwalters@0 483 /** Should multiple identical keys be permitted in the file. If set to false
tomwalters@0 484 then the last value encountered will be used as the value of the key.
tomwalters@0 485 If set to true, then all values will be available to be queried. For
tomwalters@0 486 example, with the following input:
tomwalters@0 487
tomwalters@0 488 <pre>
tomwalters@0 489 [section]
tomwalters@0 490 test=value1
tomwalters@0 491 test=value2
tomwalters@0 492 </pre>
tomwalters@0 493
tomwalters@0 494 Then with SetMultiKey(true), both of the values "value1" and "value2"
tomwalters@0 495 will be returned for the key test. If SetMultiKey(false) is used, then
tomwalters@0 496 the value for "test" will only be "value2". This value may be changed
tomwalters@0 497 at any time.
tomwalters@0 498
tomwalters@0 499 \param a_bAllowMultiKey Allow multi-keys in the source?
tomwalters@0 500 */
tomwalters@0 501 void SetMultiKey(bool a_bAllowMultiKey = true) {
tomwalters@0 502 m_bAllowMultiKey = a_bAllowMultiKey;
tomwalters@0 503 }
tomwalters@0 504
tomwalters@0 505 /** Get the storage format of the INI data. */
tomwalters@0 506 bool IsMultiKey() const { return m_bAllowMultiKey; }
tomwalters@0 507
tomwalters@0 508 /** Should data values be permitted to span multiple lines in the file. If
tomwalters@0 509 set to false then the multi-line construct <<<TAG as a value will be
tomwalters@0 510 returned as is instead of loading the data. This value may be changed
tomwalters@0 511 at any time.
tomwalters@0 512
tomwalters@0 513 \param a_bAllowMultiLine Allow multi-line values in the source?
tomwalters@0 514 */
tomwalters@0 515 void SetMultiLine(bool a_bAllowMultiLine = true) {
tomwalters@0 516 m_bAllowMultiLine = a_bAllowMultiLine;
tomwalters@0 517 }
tomwalters@0 518
tomwalters@0 519 /** Query the status of multi-line data */
tomwalters@0 520 bool IsMultiLine() const { return m_bAllowMultiLine; }
tomwalters@0 521
tomwalters@0 522 /** Should spaces be added around the equals sign when writing key/value
tomwalters@0 523 pairs out. When true, the result will be "key = value". When false,
tomwalters@0 524 the result will be "key=value". This value may be changed at any time.
tomwalters@0 525
tomwalters@0 526 \param a_bSpaces Add spaces around the equals sign?
tomwalters@0 527 */
tomwalters@0 528 void SetSpaces(bool a_bSpaces = true) {
tomwalters@0 529 m_bSpaces = a_bSpaces;
tomwalters@0 530 }
tomwalters@0 531
tomwalters@0 532 /** Query the status of spaces output */
tomwalters@0 533 bool UsingSpaces() const { return m_bSpaces; }
tomwalters@0 534
tomwalters@0 535 /*-----------------------------------------------------------------------*/
tomwalters@0 536 /** @}
tomwalters@0 537 @{ @name Loading INI Data */
tomwalters@0 538
tomwalters@0 539 /** Load an INI file from disk into memory
tomwalters@0 540
tomwalters@0 541 @param a_pszFile Path of the file to be loaded. This will be passed
tomwalters@0 542 to fopen() and so must be a valid path for the
tomwalters@0 543 current platform.
tomwalters@0 544
tomwalters@0 545 @return SI_Error See error definitions
tomwalters@0 546 */
tomwalters@0 547 SI_Error LoadFile(
tomwalters@0 548 const char * a_pszFile
tomwalters@0 549 );
tomwalters@0 550
tomwalters@0 551 #ifdef SI_HAS_WIDE_FILE
tomwalters@0 552 /** Load an INI file from disk into memory
tomwalters@0 553
tomwalters@0 554 @param a_pwszFile Path of the file to be loaded in UTF-16.
tomwalters@0 555
tomwalters@0 556 @return SI_Error See error definitions
tomwalters@0 557 */
tomwalters@0 558 SI_Error LoadFile(
tomwalters@0 559 const SI_WCHAR_T * a_pwszFile
tomwalters@0 560 );
tomwalters@0 561 #endif // SI_HAS_WIDE_FILE
tomwalters@0 562
tomwalters@0 563 /** Load the file from a file pointer.
tomwalters@0 564
tomwalters@0 565 @param a_fpFile Valid file pointer to read the file data from. The
tomwalters@0 566 file will be read until end of file.
tomwalters@0 567
tomwalters@0 568 @return SI_Error See error definitions
tomwalters@0 569 */
tomwalters@0 570 SI_Error LoadFile(
tomwalters@0 571 FILE * a_fpFile
tomwalters@0 572 );
tomwalters@0 573
tomwalters@0 574 #ifdef SI_SUPPORT_IOSTREAMS
tomwalters@0 575 /** Load INI file data from an istream.
tomwalters@0 576
tomwalters@0 577 @param a_istream Stream to read from
tomwalters@0 578
tomwalters@0 579 @return SI_Error See error definitions
tomwalters@0 580 */
tomwalters@0 581 SI_Error Load(
tomwalters@0 582 std::istream & a_istream
tomwalters@0 583 );
tomwalters@0 584 #endif // SI_SUPPORT_IOSTREAMS
tomwalters@0 585
tomwalters@0 586 /** Load INI file data direct from a std::string
tomwalters@0 587
tomwalters@0 588 @param a_strData Data to be loaded
tomwalters@0 589
tomwalters@0 590 @return SI_Error See error definitions
tomwalters@0 591 */
tomwalters@0 592 SI_Error Load(const std::string & a_strData) {
tomwalters@0 593 return Load(a_strData.c_str(), a_strData.size());
tomwalters@0 594 }
tomwalters@0 595
tomwalters@0 596 /** Load INI file data direct from memory
tomwalters@0 597
tomwalters@0 598 @param a_pData Data to be loaded
tomwalters@0 599 @param a_uDataLen Length of the data in bytes
tomwalters@0 600
tomwalters@0 601 @return SI_Error See error definitions
tomwalters@0 602 */
tomwalters@0 603 SI_Error Load(
tomwalters@0 604 const char * a_pData,
tomwalters@0 605 size_t a_uDataLen
tomwalters@0 606 );
tomwalters@0 607
tomwalters@0 608 /*-----------------------------------------------------------------------*/
tomwalters@0 609 /** @}
tomwalters@0 610 @{ @name Saving INI Data */
tomwalters@0 611
tomwalters@0 612 /** Save an INI file from memory to disk
tomwalters@0 613
tomwalters@0 614 @param a_pszFile Path of the file to be saved. This will be passed
tomwalters@0 615 to fopen() and so must be a valid path for the
tomwalters@0 616 current platform.
tomwalters@0 617
tomwalters@0 618 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is
tomwalters@0 619 in UTF-8 format. If it is not UTF-8 then
tomwalters@0 620 this parameter is ignored.
tomwalters@0 621
tomwalters@0 622 @return SI_Error See error definitions
tomwalters@0 623 */
tomwalters@0 624 SI_Error SaveFile(
tomwalters@0 625 const char * a_pszFile,
tomwalters@0 626 bool a_bAddSignature = true
tomwalters@0 627 ) const;
tomwalters@0 628
tomwalters@0 629 #ifdef SI_HAS_WIDE_FILE
tomwalters@0 630 /** Save an INI file from memory to disk
tomwalters@0 631
tomwalters@0 632 @param a_pwszFile Path of the file to be saved in UTF-16.
tomwalters@0 633
tomwalters@0 634 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is
tomwalters@0 635 in UTF-8 format. If it is not UTF-8 then
tomwalters@0 636 this parameter is ignored.
tomwalters@0 637
tomwalters@0 638 @return SI_Error See error definitions
tomwalters@0 639 */
tomwalters@0 640 SI_Error SaveFile(
tomwalters@0 641 const SI_WCHAR_T * a_pwszFile,
tomwalters@0 642 bool a_bAddSignature = true
tomwalters@0 643 ) const;
tomwalters@0 644 #endif // _WIN32
tomwalters@0 645
tomwalters@0 646 /** Save the INI data to a file. See Save() for details.
tomwalters@0 647
tomwalters@0 648 @param a_pFile Handle to a file. File should be opened for
tomwalters@0 649 binary output.
tomwalters@0 650
tomwalters@0 651 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
tomwalters@0 652 UTF-8 format. If it is not UTF-8 then this value is
tomwalters@0 653 ignored. Do not set this to true if anything has
tomwalters@0 654 already been written to the file.
tomwalters@0 655
tomwalters@0 656 @return SI_Error See error definitions
tomwalters@0 657 */
tomwalters@0 658 SI_Error SaveFile(
tomwalters@0 659 FILE * a_pFile,
tomwalters@0 660 bool a_bAddSignature = false
tomwalters@0 661 ) const;
tomwalters@0 662
tomwalters@0 663 /** Save the INI data. The data will be written to the output device
tomwalters@0 664 in a format appropriate to the current data, selected by:
tomwalters@0 665
tomwalters@0 666 <table>
tomwalters@0 667 <tr><th>SI_CHAR <th>FORMAT
tomwalters@0 668 <tr><td>char <td>same format as when loaded (MBCS or UTF-8)
tomwalters@0 669 <tr><td>wchar_t <td>UTF-8
tomwalters@0 670 <tr><td>other <td>UTF-8
tomwalters@0 671 </table>
tomwalters@0 672
tomwalters@0 673 Note that comments from the original data is preserved as per the
tomwalters@0 674 documentation on comments. The order of the sections and values
tomwalters@0 675 from the original file will be preserved.
tomwalters@0 676
tomwalters@0 677 Any data prepended or appended to the output device must use the the
tomwalters@0 678 same format (MBCS or UTF-8). You may use the GetConverter() method to
tomwalters@0 679 convert text to the correct format regardless of the output format
tomwalters@0 680 being used by SimpleIni.
tomwalters@0 681
tomwalters@0 682 To add a BOM to UTF-8 data, write it out manually at the very beginning
tomwalters@0 683 like is done in SaveFile when a_bUseBOM is true.
tomwalters@0 684
tomwalters@0 685 @param a_oOutput Output writer to write the data to.
tomwalters@0 686
tomwalters@0 687 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
tomwalters@0 688 UTF-8 format. If it is not UTF-8 then this value is
tomwalters@0 689 ignored. Do not set this to true if anything has
tomwalters@0 690 already been written to the OutputWriter.
tomwalters@0 691
tomwalters@0 692 @return SI_Error See error definitions
tomwalters@0 693 */
tomwalters@0 694 SI_Error Save(
tomwalters@0 695 OutputWriter & a_oOutput,
tomwalters@0 696 bool a_bAddSignature = false
tomwalters@0 697 ) const;
tomwalters@0 698
tomwalters@0 699 #ifdef SI_SUPPORT_IOSTREAMS
tomwalters@0 700 /** Save the INI data to an ostream. See Save() for details.
tomwalters@0 701
tomwalters@0 702 @param a_ostream String to have the INI data appended to.
tomwalters@0 703
tomwalters@0 704 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
tomwalters@0 705 UTF-8 format. If it is not UTF-8 then this value is
tomwalters@0 706 ignored. Do not set this to true if anything has
tomwalters@0 707 already been written to the stream.
tomwalters@0 708
tomwalters@0 709 @return SI_Error See error definitions
tomwalters@0 710 */
tomwalters@0 711 SI_Error Save(
tomwalters@0 712 std::ostream & a_ostream,
tomwalters@0 713 bool a_bAddSignature = false
tomwalters@0 714 ) const
tomwalters@0 715 {
tomwalters@0 716 StreamWriter writer(a_ostream);
tomwalters@0 717 return Save(writer, a_bAddSignature);
tomwalters@0 718 }
tomwalters@0 719 #endif // SI_SUPPORT_IOSTREAMS
tomwalters@0 720
tomwalters@0 721 /** Append the INI data to a string. See Save() for details.
tomwalters@0 722
tomwalters@0 723 @param a_sBuffer String to have the INI data appended to.
tomwalters@0 724
tomwalters@0 725 @param a_bAddSignature Prepend the UTF-8 BOM if the output data is in
tomwalters@0 726 UTF-8 format. If it is not UTF-8 then this value is
tomwalters@0 727 ignored. Do not set this to true if anything has
tomwalters@0 728 already been written to the string.
tomwalters@0 729
tomwalters@0 730 @return SI_Error See error definitions
tomwalters@0 731 */
tomwalters@0 732 SI_Error Save(
tomwalters@0 733 std::string & a_sBuffer,
tomwalters@0 734 bool a_bAddSignature = false
tomwalters@0 735 ) const
tomwalters@0 736 {
tomwalters@0 737 StringWriter writer(a_sBuffer);
tomwalters@0 738 return Save(writer, a_bAddSignature);
tomwalters@0 739 }
tomwalters@0 740
tomwalters@0 741 /*-----------------------------------------------------------------------*/
tomwalters@0 742 /** @}
tomwalters@0 743 @{ @name Accessing INI Data */
tomwalters@0 744
tomwalters@0 745 /** Retrieve all section names. The list is returned as an STL vector of
tomwalters@0 746 names and can be iterated or searched as necessary. Note that the
tomwalters@0 747 sort order of the returned strings is NOT DEFINED. You can sort
tomwalters@0 748 the names into the load order if desired. Search this file for ".sort"
tomwalters@0 749 for an example.
tomwalters@0 750
tomwalters@0 751 NOTE! This structure contains only pointers to strings. The actual
tomwalters@0 752 string data is stored in memory owned by CSimpleIni. Ensure that the
tomwalters@0 753 CSimpleIni object is not destroyed or Reset() while these pointers
tomwalters@0 754 are in use!
tomwalters@0 755
tomwalters@0 756 @param a_names Vector that will receive all of the section
tomwalters@0 757 names. See note above!
tomwalters@0 758 */
tomwalters@0 759 void GetAllSections(
tomwalters@0 760 TNamesDepend & a_names
tomwalters@0 761 ) const;
tomwalters@0 762
tomwalters@0 763 /** Retrieve all unique key names in a section. The sort order of the
tomwalters@0 764 returned strings is NOT DEFINED. You can sort the names into the load
tomwalters@0 765 order if desired. Search this file for ".sort" for an example. Only
tomwalters@0 766 unique key names are returned.
tomwalters@0 767
tomwalters@0 768 NOTE! This structure contains only pointers to strings. The actual
tomwalters@0 769 string data is stored in memory owned by CSimpleIni. Ensure that the
tomwalters@0 770 CSimpleIni object is not destroyed or Reset() while these strings
tomwalters@0 771 are in use!
tomwalters@0 772
tomwalters@0 773 @param a_pSection Section to request data for
tomwalters@0 774 @param a_names List that will receive all of the key
tomwalters@0 775 names. See note above!
tomwalters@0 776
tomwalters@0 777 @return true Section was found.
tomwalters@0 778 @return false Matching section was not found.
tomwalters@0 779 */
tomwalters@0 780 bool GetAllKeys(
tomwalters@0 781 const SI_CHAR * a_pSection,
tomwalters@0 782 TNamesDepend & a_names
tomwalters@0 783 ) const;
tomwalters@0 784
tomwalters@0 785 /** Retrieve all values for a specific key. This method can be used when
tomwalters@0 786 multiple keys are both enabled and disabled. Note that the sort order
tomwalters@0 787 of the returned strings is NOT DEFINED. You can sort the names into
tomwalters@0 788 the load order if desired. Search this file for ".sort" for an example.
tomwalters@0 789
tomwalters@0 790 NOTE! The returned values are pointers to string data stored in memory
tomwalters@0 791 owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed
tomwalters@0 792 or Reset while you are using this pointer!
tomwalters@0 793
tomwalters@0 794 @param a_pSection Section to search
tomwalters@0 795 @param a_pKey Key to search for
tomwalters@0 796 @param a_values List to return if the key is not found
tomwalters@0 797
tomwalters@0 798 @return true Key was found.
tomwalters@0 799 @return false Matching section/key was not found.
tomwalters@0 800 */
tomwalters@0 801 bool GetAllValues(
tomwalters@0 802 const SI_CHAR * a_pSection,
tomwalters@0 803 const SI_CHAR * a_pKey,
tomwalters@0 804 TNamesDepend & a_values
tomwalters@0 805 ) const;
tomwalters@0 806
tomwalters@0 807 /** Query the number of keys in a specific section. Note that if multiple
tomwalters@0 808 keys are enabled, then this value may be different to the number of
tomwalters@0 809 keys returned by GetAllKeys.
tomwalters@0 810
tomwalters@0 811 @param a_pSection Section to request data for
tomwalters@0 812
tomwalters@0 813 @return -1 Section does not exist in the file
tomwalters@0 814 @return >=0 Number of keys in the section
tomwalters@0 815 */
tomwalters@0 816 int GetSectionSize(
tomwalters@0 817 const SI_CHAR * a_pSection
tomwalters@0 818 ) const;
tomwalters@0 819
tomwalters@0 820 /** Retrieve all key and value pairs for a section. The data is returned
tomwalters@0 821 as a pointer to an STL map and can be iterated or searched as
tomwalters@0 822 desired. Note that multiple entries for the same key may exist when
tomwalters@0 823 multiple keys have been enabled.
tomwalters@0 824
tomwalters@0 825 NOTE! This structure contains only pointers to strings. The actual
tomwalters@0 826 string data is stored in memory owned by CSimpleIni. Ensure that the
tomwalters@0 827 CSimpleIni object is not destroyed or Reset() while these strings
tomwalters@0 828 are in use!
tomwalters@0 829
tomwalters@0 830 @param a_pSection Name of the section to return
tomwalters@0 831 @return boolean Was a section matching the supplied
tomwalters@0 832 name found.
tomwalters@0 833 */
tomwalters@0 834 const TKeyVal * GetSection(
tomwalters@0 835 const SI_CHAR * a_pSection
tomwalters@0 836 ) const;
tomwalters@0 837
tomwalters@0 838 /** Retrieve the value for a specific key. If multiple keys are enabled
tomwalters@0 839 (see SetMultiKey) then only the first value associated with that key
tomwalters@0 840 will be returned, see GetAllValues for getting all values with multikey.
tomwalters@0 841
tomwalters@0 842 NOTE! The returned value is a pointer to string data stored in memory
tomwalters@0 843 owned by CSimpleIni. Ensure that the CSimpleIni object is not destroyed
tomwalters@0 844 or Reset while you are using this pointer!
tomwalters@0 845
tomwalters@0 846 @param a_pSection Section to search
tomwalters@0 847 @param a_pKey Key to search for
tomwalters@0 848 @param a_pDefault Value to return if the key is not found
tomwalters@0 849 @param a_pHasMultiple Optionally receive notification of if there are
tomwalters@0 850 multiple entries for this key.
tomwalters@0 851
tomwalters@0 852 @return a_pDefault Key was not found in the section
tomwalters@0 853 @return other Value of the key
tomwalters@0 854 */
tomwalters@0 855 const SI_CHAR * GetValue(
tomwalters@0 856 const SI_CHAR * a_pSection,
tomwalters@0 857 const SI_CHAR * a_pKey,
tomwalters@0 858 const SI_CHAR * a_pDefault = NULL,
tomwalters@0 859 bool * a_pHasMultiple = NULL
tomwalters@0 860 ) const;
tomwalters@0 861
tomwalters@0 862 /** Retrieve a numeric value for a specific key. If multiple keys are enabled
tomwalters@0 863 (see SetMultiKey) then only the first value associated with that key
tomwalters@0 864 will be returned, see GetAllValues for getting all values with multikey.
tomwalters@0 865
tomwalters@0 866 @param a_pSection Section to search
tomwalters@0 867 @param a_pKey Key to search for
tomwalters@0 868 @param a_nDefault Value to return if the key is not found
tomwalters@0 869 @param a_pHasMultiple Optionally receive notification of if there are
tomwalters@0 870 multiple entries for this key.
tomwalters@0 871
tomwalters@0 872 @return a_nDefault Key was not found in the section
tomwalters@0 873 @return other Value of the key
tomwalters@0 874 */
tomwalters@0 875 long GetLongValue(
tomwalters@0 876 const SI_CHAR * a_pSection,
tomwalters@0 877 const SI_CHAR * a_pKey,
tomwalters@0 878 long a_nDefault = 0,
tomwalters@0 879 bool * a_pHasMultiple = NULL
tomwalters@0 880 ) const;
tomwalters@0 881
tomwalters@0 882 /** Retrieve a boolean value for a specific key. If multiple keys are enabled
tomwalters@0 883 (see SetMultiKey) then only the first value associated with that key
tomwalters@0 884 will be returned, see GetAllValues for getting all values with multikey.
tomwalters@0 885
tomwalters@0 886 Strings starting with "t", "y", "on" or "1" are returned as logically true.
tomwalters@0 887 Strings starting with "f", "n", "of" or "0" are returned as logically false.
tomwalters@0 888 For all other values the default is returned. Character comparisons are
tomwalters@0 889 case-insensitive.
tomwalters@0 890
tomwalters@0 891 @param a_pSection Section to search
tomwalters@0 892 @param a_pKey Key to search for
tomwalters@0 893 @param a_bDefault Value to return if the key is not found
tomwalters@0 894 @param a_pHasMultiple Optionally receive notification of if there are
tomwalters@0 895 multiple entries for this key.
tomwalters@0 896
tomwalters@0 897 @return a_nDefault Key was not found in the section
tomwalters@0 898 @return other Value of the key
tomwalters@0 899 */
tomwalters@0 900 bool GetBoolValue(
tomwalters@0 901 const SI_CHAR * a_pSection,
tomwalters@0 902 const SI_CHAR * a_pKey,
tomwalters@0 903 bool a_bDefault = false,
tomwalters@0 904 bool * a_pHasMultiple = NULL
tomwalters@0 905 ) const;
tomwalters@0 906
tomwalters@0 907 /** Add or update a section or value. This will always insert
tomwalters@0 908 when multiple keys are enabled.
tomwalters@0 909
tomwalters@0 910 @param a_pSection Section to add or update
tomwalters@0 911 @param a_pKey Key to add or update. Set to NULL to
tomwalters@0 912 create an empty section.
tomwalters@0 913 @param a_pValue Value to set. Set to NULL to create an
tomwalters@0 914 empty section.
tomwalters@0 915 @param a_pComment Comment to be associated with the section or the
tomwalters@0 916 key. If a_pKey is NULL then it will be associated
tomwalters@0 917 with the section, otherwise the key. Note that a
tomwalters@0 918 comment may be set ONLY when the section or key is
tomwalters@0 919 first created (i.e. when this function returns the
tomwalters@0 920 value SI_INSERTED). If you wish to create a section
tomwalters@0 921 with a comment then you need to create the section
tomwalters@0 922 separately to the key. The comment string must be
tomwalters@0 923 in full comment form already (have a comment
tomwalters@0 924 character starting every line).
tomwalters@0 925 @param a_bForceReplace Should all existing values in a multi-key INI
tomwalters@0 926 file be replaced with this entry. This option has
tomwalters@0 927 no effect if not using multi-key files. The
tomwalters@0 928 difference between Delete/SetValue and SetValue
tomwalters@0 929 with a_bForceReplace = true, is that the load
tomwalters@0 930 order and comment will be preserved this way.
tomwalters@0 931
tomwalters@0 932 @return SI_Error See error definitions
tomwalters@0 933 @return SI_UPDATED Value was updated
tomwalters@0 934 @return SI_INSERTED Value was inserted
tomwalters@0 935 */
tomwalters@0 936 SI_Error SetValue(
tomwalters@0 937 const SI_CHAR * a_pSection,
tomwalters@0 938 const SI_CHAR * a_pKey,
tomwalters@0 939 const SI_CHAR * a_pValue,
tomwalters@0 940 const SI_CHAR * a_pComment = NULL,
tomwalters@0 941 bool a_bForceReplace = false
tomwalters@0 942 )
tomwalters@0 943 {
tomwalters@0 944 return AddEntry(a_pSection, a_pKey, a_pValue, a_pComment, a_bForceReplace, true);
tomwalters@0 945 }
tomwalters@0 946
tomwalters@0 947 /** Add or update a numeric value. This will always insert
tomwalters@0 948 when multiple keys are enabled.
tomwalters@0 949
tomwalters@0 950 @param a_pSection Section to add or update
tomwalters@0 951 @param a_pKey Key to add or update.
tomwalters@0 952 @param a_nValue Value to set.
tomwalters@0 953 @param a_pComment Comment to be associated with the key. See the
tomwalters@0 954 notes on SetValue() for comments.
tomwalters@0 955 @param a_bUseHex By default the value will be written to the file
tomwalters@0 956 in decimal format. Set this to true to write it
tomwalters@0 957 as hexadecimal.
tomwalters@0 958 @param a_bForceReplace Should all existing values in a multi-key INI
tomwalters@0 959 file be replaced with this entry. This option has
tomwalters@0 960 no effect if not using multi-key files. The
tomwalters@0 961 difference between Delete/SetLongValue and
tomwalters@0 962 SetLongValue with a_bForceReplace = true, is that
tomwalters@0 963 the load order and comment will be preserved this
tomwalters@0 964 way.
tomwalters@0 965
tomwalters@0 966 @return SI_Error See error definitions
tomwalters@0 967 @return SI_UPDATED Value was updated
tomwalters@0 968 @return SI_INSERTED Value was inserted
tomwalters@0 969 */
tomwalters@0 970 SI_Error SetLongValue(
tomwalters@0 971 const SI_CHAR * a_pSection,
tomwalters@0 972 const SI_CHAR * a_pKey,
tomwalters@0 973 long a_nValue,
tomwalters@0 974 const SI_CHAR * a_pComment = NULL,
tomwalters@0 975 bool a_bUseHex = false,
tomwalters@0 976 bool a_bForceReplace = false
tomwalters@0 977 );
tomwalters@0 978
tomwalters@0 979 /** Add or update a boolean value. This will always insert
tomwalters@0 980 when multiple keys are enabled.
tomwalters@0 981
tomwalters@0 982 @param a_pSection Section to add or update
tomwalters@0 983 @param a_pKey Key to add or update.
tomwalters@0 984 @param a_bValue Value to set.
tomwalters@0 985 @param a_pComment Comment to be associated with the key. See the
tomwalters@0 986 notes on SetValue() for comments.
tomwalters@0 987 @param a_bForceReplace Should all existing values in a multi-key INI
tomwalters@0 988 file be replaced with this entry. This option has
tomwalters@0 989 no effect if not using multi-key files. The
tomwalters@0 990 difference between Delete/SetBoolValue and
tomwalters@0 991 SetBoolValue with a_bForceReplace = true, is that
tomwalters@0 992 the load order and comment will be preserved this
tomwalters@0 993 way.
tomwalters@0 994
tomwalters@0 995 @return SI_Error See error definitions
tomwalters@0 996 @return SI_UPDATED Value was updated
tomwalters@0 997 @return SI_INSERTED Value was inserted
tomwalters@0 998 */
tomwalters@0 999 SI_Error SetBoolValue(
tomwalters@0 1000 const SI_CHAR * a_pSection,
tomwalters@0 1001 const SI_CHAR * a_pKey,
tomwalters@0 1002 bool a_bValue,
tomwalters@0 1003 const SI_CHAR * a_pComment = NULL,
tomwalters@0 1004 bool a_bForceReplace = false
tomwalters@0 1005 );
tomwalters@0 1006
tomwalters@0 1007 /** Delete an entire section, or a key from a section. Note that the
tomwalters@0 1008 data returned by GetSection is invalid and must not be used after
tomwalters@0 1009 anything has been deleted from that section using this method.
tomwalters@0 1010 Note when multiple keys is enabled, this will delete all keys with
tomwalters@0 1011 that name; there is no way to selectively delete individual key/values
tomwalters@0 1012 in this situation.
tomwalters@0 1013
tomwalters@0 1014 @param a_pSection Section to delete key from, or if
tomwalters@0 1015 a_pKey is NULL, the section to remove.
tomwalters@0 1016 @param a_pKey Key to remove from the section. Set to
tomwalters@0 1017 NULL to remove the entire section.
tomwalters@0 1018 @param a_bRemoveEmpty If the section is empty after this key has
tomwalters@0 1019 been deleted, should the empty section be
tomwalters@0 1020 removed?
tomwalters@0 1021
tomwalters@0 1022 @return true Key or section was deleted.
tomwalters@0 1023 @return false Key or section was not found.
tomwalters@0 1024 */
tomwalters@0 1025 bool Delete(
tomwalters@0 1026 const SI_CHAR * a_pSection,
tomwalters@0 1027 const SI_CHAR * a_pKey,
tomwalters@0 1028 bool a_bRemoveEmpty = false
tomwalters@0 1029 );
tomwalters@0 1030
tomwalters@0 1031 /*-----------------------------------------------------------------------*/
tomwalters@0 1032 /** @}
tomwalters@0 1033 @{ @name Converter */
tomwalters@0 1034
tomwalters@0 1035 /** Return a conversion object to convert text to the same encoding
tomwalters@0 1036 as is used by the Save(), SaveFile() and SaveString() functions.
tomwalters@0 1037 Use this to prepare the strings that you wish to append or prepend
tomwalters@0 1038 to the output INI data.
tomwalters@0 1039 */
tomwalters@0 1040 Converter GetConverter() const {
tomwalters@0 1041 return Converter(m_bStoreIsUtf8);
tomwalters@0 1042 }
tomwalters@0 1043
tomwalters@0 1044 /*-----------------------------------------------------------------------*/
tomwalters@0 1045 /** @} */
tomwalters@0 1046
tomwalters@0 1047 private:
tomwalters@0 1048 // copying is not permitted
tomwalters@0 1049 CSimpleIniTempl(const CSimpleIniTempl &); // disabled
tomwalters@0 1050 CSimpleIniTempl & operator=(const CSimpleIniTempl &); // disabled
tomwalters@0 1051
tomwalters@0 1052 /** Parse the data looking for a file comment and store it if found.
tomwalters@0 1053 */
tomwalters@0 1054 SI_Error FindFileComment(
tomwalters@0 1055 SI_CHAR *& a_pData,
tomwalters@0 1056 bool a_bCopyStrings
tomwalters@0 1057 );
tomwalters@0 1058
tomwalters@0 1059 /** Parse the data looking for the next valid entry. The memory pointed to
tomwalters@0 1060 by a_pData is modified by inserting NULL characters. The pointer is
tomwalters@0 1061 updated to the current location in the block of text.
tomwalters@0 1062 */
tomwalters@0 1063 bool FindEntry(
tomwalters@0 1064 SI_CHAR *& a_pData,
tomwalters@0 1065 const SI_CHAR *& a_pSection,
tomwalters@0 1066 const SI_CHAR *& a_pKey,
tomwalters@0 1067 const SI_CHAR *& a_pVal,
tomwalters@0 1068 const SI_CHAR *& a_pComment
tomwalters@0 1069 ) const;
tomwalters@0 1070
tomwalters@0 1071 /** Add the section/key/value to our data.
tomwalters@0 1072
tomwalters@0 1073 @param a_pSection Section name. Sections will be created if they
tomwalters@0 1074 don't already exist.
tomwalters@0 1075 @param a_pKey Key name. May be NULL to create an empty section.
tomwalters@0 1076 Existing entries will be updated. New entries will
tomwalters@0 1077 be created.
tomwalters@0 1078 @param a_pValue Value for the key.
tomwalters@0 1079 @param a_pComment Comment to be associated with the section or the
tomwalters@0 1080 key. If a_pKey is NULL then it will be associated
tomwalters@0 1081 with the section, otherwise the key. This must be
tomwalters@0 1082 a string in full comment form already (have a
tomwalters@0 1083 comment character starting every line).
tomwalters@0 1084 @param a_bForceReplace Should all existing values in a multi-key INI
tomwalters@0 1085 file be replaced with this entry. This option has
tomwalters@0 1086 no effect if not using multi-key files. The
tomwalters@0 1087 difference between Delete/AddEntry and AddEntry
tomwalters@0 1088 with a_bForceReplace = true, is that the load
tomwalters@0 1089 order and comment will be preserved this way.
tomwalters@0 1090 @param a_bCopyStrings Should copies of the strings be made or not.
tomwalters@0 1091 If false then the pointers will be used as is.
tomwalters@0 1092 */
tomwalters@0 1093 SI_Error AddEntry(
tomwalters@0 1094 const SI_CHAR * a_pSection,
tomwalters@0 1095 const SI_CHAR * a_pKey,
tomwalters@0 1096 const SI_CHAR * a_pValue,
tomwalters@0 1097 const SI_CHAR * a_pComment,
tomwalters@0 1098 bool a_bForceReplace,
tomwalters@0 1099 bool a_bCopyStrings
tomwalters@0 1100 );
tomwalters@0 1101
tomwalters@0 1102 /** Is the supplied character a whitespace character? */
tomwalters@0 1103 inline bool IsSpace(SI_CHAR ch) const {
tomwalters@0 1104 return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
tomwalters@0 1105 }
tomwalters@0 1106
tomwalters@0 1107 /** Does the supplied character start a comment line? */
tomwalters@0 1108 inline bool IsComment(SI_CHAR ch) const {
tomwalters@0 1109 return (ch == ';' || ch == '#');
tomwalters@0 1110 }
tomwalters@0 1111
tomwalters@0 1112
tomwalters@0 1113 /** Skip over a newline character (or characters) for either DOS or UNIX */
tomwalters@0 1114 inline void SkipNewLine(SI_CHAR *& a_pData) const {
tomwalters@0 1115 a_pData += (*a_pData == '\r' && *(a_pData+1) == '\n') ? 2 : 1;
tomwalters@0 1116 }
tomwalters@0 1117
tomwalters@0 1118 /** Make a copy of the supplied string, replacing the original pointer */
tomwalters@0 1119 SI_Error CopyString(const SI_CHAR *& a_pString);
tomwalters@0 1120
tomwalters@0 1121 /** Delete a string from the copied strings buffer if necessary */
tomwalters@0 1122 void DeleteString(const SI_CHAR * a_pString);
tomwalters@0 1123
tomwalters@0 1124 /** Internal use of our string comparison function */
tomwalters@0 1125 bool IsLess(const SI_CHAR * a_pLeft, const SI_CHAR * a_pRight) const {
tomwalters@0 1126 const static SI_STRLESS isLess = SI_STRLESS();
tomwalters@0 1127 return isLess(a_pLeft, a_pRight);
tomwalters@0 1128 }
tomwalters@0 1129
tomwalters@0 1130 bool IsMultiLineTag(const SI_CHAR * a_pData) const;
tomwalters@0 1131 bool IsMultiLineData(const SI_CHAR * a_pData) const;
tomwalters@0 1132 bool LoadMultiLineText(
tomwalters@0 1133 SI_CHAR *& a_pData,
tomwalters@0 1134 const SI_CHAR *& a_pVal,
tomwalters@0 1135 const SI_CHAR * a_pTagName,
tomwalters@0 1136 bool a_bAllowBlankLinesInComment = false
tomwalters@0 1137 ) const;
tomwalters@0 1138 bool IsNewLineChar(SI_CHAR a_c) const;
tomwalters@0 1139
tomwalters@0 1140 bool OutputMultiLineText(
tomwalters@0 1141 OutputWriter & a_oOutput,
tomwalters@0 1142 Converter & a_oConverter,
tomwalters@0 1143 const SI_CHAR * a_pText
tomwalters@0 1144 ) const;
tomwalters@0 1145
tomwalters@0 1146 private:
tomwalters@0 1147 /** Copy of the INI file data in our character format. This will be
tomwalters@0 1148 modified when parsed to have NULL characters added after all
tomwalters@0 1149 interesting string entries. All of the string pointers to sections,
tomwalters@0 1150 keys and values point into this block of memory.
tomwalters@0 1151 */
tomwalters@0 1152 SI_CHAR * m_pData;
tomwalters@0 1153
tomwalters@0 1154 /** Length of the data that we have stored. Used when deleting strings
tomwalters@0 1155 to determine if the string is stored here or in the allocated string
tomwalters@0 1156 buffer.
tomwalters@0 1157 */
tomwalters@0 1158 size_t m_uDataLen;
tomwalters@0 1159
tomwalters@0 1160 /** File comment for this data, if one exists. */
tomwalters@0 1161 const SI_CHAR * m_pFileComment;
tomwalters@0 1162
tomwalters@0 1163 /** Parsed INI data. Section -> (Key -> Value). */
tomwalters@0 1164 TSection m_data;
tomwalters@0 1165
tomwalters@0 1166 /** This vector stores allocated memory for copies of strings that have
tomwalters@0 1167 been supplied after the file load. It will be empty unless SetValue()
tomwalters@0 1168 has been called.
tomwalters@0 1169 */
tomwalters@0 1170 TNamesDepend m_strings;
tomwalters@0 1171
tomwalters@0 1172 /** Is the format of our datafile UTF-8 or MBCS? */
tomwalters@0 1173 bool m_bStoreIsUtf8;
tomwalters@0 1174
tomwalters@0 1175 /** Are multiple values permitted for the same key? */
tomwalters@0 1176 bool m_bAllowMultiKey;
tomwalters@0 1177
tomwalters@0 1178 /** Are data values permitted to span multiple lines? */
tomwalters@0 1179 bool m_bAllowMultiLine;
tomwalters@0 1180
tomwalters@0 1181 /** Should spaces be written out surrounding the equals sign? */
tomwalters@0 1182 bool m_bSpaces;
tomwalters@0 1183
tomwalters@0 1184 /** Next order value, used to ensure sections and keys are output in the
tomwalters@0 1185 same order that they are loaded/added.
tomwalters@0 1186 */
tomwalters@0 1187 int m_nOrder;
tomwalters@0 1188 };
tomwalters@0 1189
tomwalters@0 1190 // ---------------------------------------------------------------------------
tomwalters@0 1191 // IMPLEMENTATION
tomwalters@0 1192 // ---------------------------------------------------------------------------
tomwalters@0 1193
tomwalters@0 1194 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1195 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CSimpleIniTempl(
tomwalters@0 1196 bool a_bIsUtf8,
tomwalters@0 1197 bool a_bAllowMultiKey,
tomwalters@0 1198 bool a_bAllowMultiLine
tomwalters@0 1199 )
tomwalters@0 1200 : m_pData(0)
tomwalters@0 1201 , m_uDataLen(0)
tomwalters@0 1202 , m_pFileComment(NULL)
tomwalters@0 1203 , m_bStoreIsUtf8(a_bIsUtf8)
tomwalters@0 1204 , m_bAllowMultiKey(a_bAllowMultiKey)
tomwalters@0 1205 , m_bAllowMultiLine(a_bAllowMultiLine)
tomwalters@0 1206 , m_bSpaces(true)
tomwalters@0 1207 , m_nOrder(0)
tomwalters@0 1208 { }
tomwalters@0 1209
tomwalters@0 1210 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1211 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::~CSimpleIniTempl()
tomwalters@0 1212 {
tomwalters@0 1213 Reset();
tomwalters@0 1214 }
tomwalters@0 1215
tomwalters@0 1216 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1217 void
tomwalters@0 1218 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Reset()
tomwalters@0 1219 {
tomwalters@0 1220 // remove all data
tomwalters@0 1221 delete[] m_pData;
tomwalters@0 1222 m_pData = NULL;
tomwalters@0 1223 m_uDataLen = 0;
tomwalters@0 1224 m_pFileComment = NULL;
tomwalters@0 1225 if (!m_data.empty()) {
tomwalters@0 1226 m_data.erase(m_data.begin(), m_data.end());
tomwalters@0 1227 }
tomwalters@0 1228
tomwalters@0 1229 // remove all strings
tomwalters@0 1230 if (!m_strings.empty()) {
tomwalters@0 1231 typename TNamesDepend::iterator i = m_strings.begin();
tomwalters@0 1232 for (; i != m_strings.end(); ++i) {
tomwalters@0 1233 delete[] const_cast<SI_CHAR*>(i->pItem);
tomwalters@0 1234 }
tomwalters@0 1235 m_strings.erase(m_strings.begin(), m_strings.end());
tomwalters@0 1236 }
tomwalters@0 1237 }
tomwalters@0 1238
tomwalters@0 1239 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1240 SI_Error
tomwalters@0 1241 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
tomwalters@0 1242 const char * a_pszFile
tomwalters@0 1243 )
tomwalters@0 1244 {
tomwalters@0 1245 FILE * fp = NULL;
tomwalters@0 1246 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
tomwalters@0 1247 fopen_s(&fp, a_pszFile, "rb");
tomwalters@0 1248 #else // !__STDC_WANT_SECURE_LIB__
tomwalters@0 1249 fp = fopen(a_pszFile, "rb");
tomwalters@0 1250 #endif // __STDC_WANT_SECURE_LIB__
tomwalters@0 1251 if (!fp) {
tomwalters@0 1252 return SI_FILE;
tomwalters@0 1253 }
tomwalters@0 1254 SI_Error rc = LoadFile(fp);
tomwalters@0 1255 fclose(fp);
tomwalters@0 1256 return rc;
tomwalters@0 1257 }
tomwalters@0 1258
tomwalters@0 1259 #ifdef SI_HAS_WIDE_FILE
tomwalters@0 1260 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1261 SI_Error
tomwalters@0 1262 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
tomwalters@0 1263 const SI_WCHAR_T * a_pwszFile
tomwalters@0 1264 )
tomwalters@0 1265 {
tomwalters@0 1266 #ifdef _WIN32
tomwalters@0 1267 FILE * fp = NULL;
tomwalters@0 1268 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
tomwalters@0 1269 _wfopen_s(&fp, a_pwszFile, L"rb");
tomwalters@0 1270 #else // !__STDC_WANT_SECURE_LIB__
tomwalters@0 1271 fp = _wfopen(a_pwszFile, L"rb");
tomwalters@0 1272 #endif // __STDC_WANT_SECURE_LIB__
tomwalters@0 1273 if (!fp) return SI_FILE;
tomwalters@0 1274 SI_Error rc = LoadFile(fp);
tomwalters@0 1275 fclose(fp);
tomwalters@0 1276 return rc;
tomwalters@0 1277 #else // !_WIN32 (therefore SI_CONVERT_ICU)
tomwalters@0 1278 char szFile[256];
tomwalters@0 1279 u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
tomwalters@0 1280 return LoadFile(szFile);
tomwalters@0 1281 #endif // _WIN32
tomwalters@0 1282 }
tomwalters@0 1283 #endif // SI_HAS_WIDE_FILE
tomwalters@0 1284
tomwalters@0 1285 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1286 SI_Error
tomwalters@0 1287 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
tomwalters@0 1288 FILE * a_fpFile
tomwalters@0 1289 )
tomwalters@0 1290 {
tomwalters@0 1291 // load the raw file data
tomwalters@0 1292 int retval = fseek(a_fpFile, 0, SEEK_END);
tomwalters@0 1293 if (retval != 0) {
tomwalters@0 1294 return SI_FILE;
tomwalters@0 1295 }
tomwalters@0 1296 long lSize = ftell(a_fpFile);
tomwalters@0 1297 if (lSize < 0) {
tomwalters@0 1298 return SI_FILE;
tomwalters@0 1299 }
tomwalters@0 1300 if (lSize == 0) {
tomwalters@0 1301 return SI_OK;
tomwalters@0 1302 }
tomwalters@0 1303 char * pData = new char[lSize];
tomwalters@0 1304 if (!pData) {
tomwalters@0 1305 return SI_NOMEM;
tomwalters@0 1306 }
tomwalters@0 1307 fseek(a_fpFile, 0, SEEK_SET);
tomwalters@0 1308 size_t uRead = fread(pData, sizeof(char), lSize, a_fpFile);
tomwalters@0 1309 if (uRead != (size_t) lSize) {
tomwalters@0 1310 delete[] pData;
tomwalters@0 1311 return SI_FILE;
tomwalters@0 1312 }
tomwalters@0 1313
tomwalters@0 1314 // convert the raw data to unicode
tomwalters@0 1315 SI_Error rc = Load(pData, uRead);
tomwalters@0 1316 delete[] pData;
tomwalters@0 1317 return rc;
tomwalters@0 1318 }
tomwalters@0 1319
tomwalters@0 1320 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1321 SI_Error
tomwalters@0 1322 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
tomwalters@0 1323 const char * a_pData,
tomwalters@0 1324 size_t a_uDataLen
tomwalters@0 1325 )
tomwalters@0 1326 {
tomwalters@0 1327 SI_CONVERTER converter(m_bStoreIsUtf8);
tomwalters@0 1328
tomwalters@0 1329 if (a_uDataLen == 0) {
tomwalters@0 1330 return SI_OK;
tomwalters@0 1331 }
tomwalters@0 1332
tomwalters@0 1333 // consume the UTF-8 BOM if it exists
tomwalters@0 1334 if (m_bStoreIsUtf8 && a_uDataLen >= 3) {
tomwalters@0 1335 if (memcmp(a_pData, SI_UTF8_SIGNATURE, 3) == 0) {
tomwalters@0 1336 a_pData += 3;
tomwalters@0 1337 a_uDataLen -= 3;
tomwalters@0 1338 }
tomwalters@0 1339 }
tomwalters@0 1340
tomwalters@0 1341 // determine the length of the converted data
tomwalters@0 1342 size_t uLen = converter.SizeFromStore(a_pData, a_uDataLen);
tomwalters@0 1343 if (uLen == (size_t)(-1)) {
tomwalters@0 1344 return SI_FAIL;
tomwalters@0 1345 }
tomwalters@0 1346
tomwalters@0 1347 // allocate memory for the data, ensure that there is a NULL
tomwalters@0 1348 // terminator wherever the converted data ends
tomwalters@0 1349 SI_CHAR * pData = new SI_CHAR[uLen+1];
tomwalters@0 1350 if (!pData) {
tomwalters@0 1351 return SI_NOMEM;
tomwalters@0 1352 }
tomwalters@0 1353 memset(pData, 0, sizeof(SI_CHAR)*(uLen+1));
tomwalters@0 1354
tomwalters@0 1355 // convert the data
tomwalters@0 1356 if (!converter.ConvertFromStore(a_pData, a_uDataLen, pData, uLen)) {
tomwalters@0 1357 delete[] pData;
tomwalters@0 1358 return SI_FAIL;
tomwalters@0 1359 }
tomwalters@0 1360
tomwalters@0 1361 // parse it
tomwalters@0 1362 const static SI_CHAR empty = 0;
tomwalters@0 1363 SI_CHAR * pWork = pData;
tomwalters@0 1364 const SI_CHAR * pSection = &empty;
tomwalters@0 1365 const SI_CHAR * pItem = NULL;
tomwalters@0 1366 const SI_CHAR * pVal = NULL;
tomwalters@0 1367 const SI_CHAR * pComment = NULL;
tomwalters@0 1368
tomwalters@0 1369 // We copy the strings if we are loading data into this class when we
tomwalters@0 1370 // already have stored some.
tomwalters@0 1371 bool bCopyStrings = (m_pData != NULL);
tomwalters@0 1372
tomwalters@0 1373 // find a file comment if it exists, this is a comment that starts at the
tomwalters@0 1374 // beginning of the file and continues until the first blank line.
tomwalters@0 1375 SI_Error rc = FindFileComment(pWork, bCopyStrings);
tomwalters@0 1376 if (rc < 0) return rc;
tomwalters@0 1377
tomwalters@0 1378 // add every entry in the file to the data table
tomwalters@0 1379 while (FindEntry(pWork, pSection, pItem, pVal, pComment)) {
tomwalters@0 1380 rc = AddEntry(pSection, pItem, pVal, pComment, false, bCopyStrings);
tomwalters@0 1381 if (rc < 0) return rc;
tomwalters@0 1382 }
tomwalters@0 1383
tomwalters@0 1384 // store these strings if we didn't copy them
tomwalters@0 1385 if (bCopyStrings) {
tomwalters@0 1386 delete[] pData;
tomwalters@0 1387 }
tomwalters@0 1388 else {
tomwalters@0 1389 m_pData = pData;
tomwalters@0 1390 m_uDataLen = uLen+1;
tomwalters@0 1391 }
tomwalters@0 1392
tomwalters@0 1393 return SI_OK;
tomwalters@0 1394 }
tomwalters@0 1395
tomwalters@0 1396 #ifdef SI_SUPPORT_IOSTREAMS
tomwalters@0 1397 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1398 SI_Error
tomwalters@0 1399 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
tomwalters@0 1400 std::istream & a_istream
tomwalters@0 1401 )
tomwalters@0 1402 {
tomwalters@0 1403 std::string strData;
tomwalters@0 1404 char szBuf[512];
tomwalters@0 1405 do {
tomwalters@0 1406 a_istream.get(szBuf, sizeof(szBuf), '\0');
tomwalters@0 1407 strData.append(szBuf);
tomwalters@0 1408 }
tomwalters@0 1409 while (a_istream.good());
tomwalters@0 1410 return Load(strData);
tomwalters@0 1411 }
tomwalters@0 1412 #endif // SI_SUPPORT_IOSTREAMS
tomwalters@0 1413
tomwalters@0 1414 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1415 SI_Error
tomwalters@0 1416 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindFileComment(
tomwalters@0 1417 SI_CHAR *& a_pData,
tomwalters@0 1418 bool a_bCopyStrings
tomwalters@0 1419 )
tomwalters@0 1420 {
tomwalters@0 1421 // there can only be a single file comment
tomwalters@0 1422 if (m_pFileComment) {
tomwalters@0 1423 return SI_OK;
tomwalters@0 1424 }
tomwalters@0 1425
tomwalters@0 1426 // Load the file comment as multi-line text, this will modify all of
tomwalters@0 1427 // the newline characters to be single \n chars
tomwalters@0 1428 if (!LoadMultiLineText(a_pData, m_pFileComment, NULL, false)) {
tomwalters@0 1429 return SI_OK;
tomwalters@0 1430 }
tomwalters@0 1431
tomwalters@0 1432 // copy the string if necessary
tomwalters@0 1433 if (a_bCopyStrings) {
tomwalters@0 1434 SI_Error rc = CopyString(m_pFileComment);
tomwalters@0 1435 if (rc < 0) return rc;
tomwalters@0 1436 }
tomwalters@0 1437
tomwalters@0 1438 return SI_OK;
tomwalters@0 1439 }
tomwalters@0 1440
tomwalters@0 1441 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1442 bool
tomwalters@0 1443 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::FindEntry(
tomwalters@0 1444 SI_CHAR *& a_pData,
tomwalters@0 1445 const SI_CHAR *& a_pSection,
tomwalters@0 1446 const SI_CHAR *& a_pKey,
tomwalters@0 1447 const SI_CHAR *& a_pVal,
tomwalters@0 1448 const SI_CHAR *& a_pComment
tomwalters@0 1449 ) const
tomwalters@0 1450 {
tomwalters@0 1451 a_pComment = NULL;
tomwalters@0 1452
tomwalters@0 1453 SI_CHAR * pTrail = NULL;
tomwalters@0 1454 while (*a_pData) {
tomwalters@0 1455 // skip spaces and empty lines
tomwalters@0 1456 while (*a_pData && IsSpace(*a_pData)) {
tomwalters@0 1457 ++a_pData;
tomwalters@0 1458 }
tomwalters@0 1459 if (!*a_pData) {
tomwalters@0 1460 break;
tomwalters@0 1461 }
tomwalters@0 1462
tomwalters@0 1463 // skip processing of comment lines but keep a pointer to
tomwalters@0 1464 // the start of the comment.
tomwalters@0 1465 if (IsComment(*a_pData)) {
tomwalters@0 1466 LoadMultiLineText(a_pData, a_pComment, NULL, true);
tomwalters@0 1467 continue;
tomwalters@0 1468 }
tomwalters@0 1469
tomwalters@0 1470 // process section names
tomwalters@0 1471 if (*a_pData == '[') {
tomwalters@0 1472 // skip leading spaces
tomwalters@0 1473 ++a_pData;
tomwalters@0 1474 while (*a_pData && IsSpace(*a_pData)) {
tomwalters@0 1475 ++a_pData;
tomwalters@0 1476 }
tomwalters@0 1477
tomwalters@0 1478 // find the end of the section name (it may contain spaces)
tomwalters@0 1479 // and convert it to lowercase as necessary
tomwalters@0 1480 a_pSection = a_pData;
tomwalters@0 1481 while (*a_pData && *a_pData != ']' && !IsNewLineChar(*a_pData)) {
tomwalters@0 1482 ++a_pData;
tomwalters@0 1483 }
tomwalters@0 1484
tomwalters@0 1485 // if it's an invalid line, just skip it
tomwalters@0 1486 if (*a_pData != ']') {
tomwalters@0 1487 continue;
tomwalters@0 1488 }
tomwalters@0 1489
tomwalters@0 1490 // remove trailing spaces from the section
tomwalters@0 1491 pTrail = a_pData - 1;
tomwalters@0 1492 while (pTrail >= a_pSection && IsSpace(*pTrail)) {
tomwalters@0 1493 --pTrail;
tomwalters@0 1494 }
tomwalters@0 1495 ++pTrail;
tomwalters@0 1496 *pTrail = 0;
tomwalters@0 1497
tomwalters@0 1498 // skip to the end of the line
tomwalters@0 1499 ++a_pData; // safe as checked that it == ']' above
tomwalters@0 1500 while (*a_pData && !IsNewLineChar(*a_pData)) {
tomwalters@0 1501 ++a_pData;
tomwalters@0 1502 }
tomwalters@0 1503
tomwalters@0 1504 a_pKey = NULL;
tomwalters@0 1505 a_pVal = NULL;
tomwalters@0 1506 return true;
tomwalters@0 1507 }
tomwalters@0 1508
tomwalters@0 1509 // find the end of the key name (it may contain spaces)
tomwalters@0 1510 // and convert it to lowercase as necessary
tomwalters@0 1511 a_pKey = a_pData;
tomwalters@0 1512 while (*a_pData && *a_pData != '=' && !IsNewLineChar(*a_pData)) {
tomwalters@0 1513 ++a_pData;
tomwalters@0 1514 }
tomwalters@0 1515
tomwalters@0 1516 // if it's an invalid line, just skip it
tomwalters@0 1517 if (*a_pData != '=') {
tomwalters@0 1518 continue;
tomwalters@0 1519 }
tomwalters@0 1520
tomwalters@0 1521 // empty keys are invalid
tomwalters@0 1522 if (a_pKey == a_pData) {
tomwalters@0 1523 while (*a_pData && !IsNewLineChar(*a_pData)) {
tomwalters@0 1524 ++a_pData;
tomwalters@0 1525 }
tomwalters@0 1526 continue;
tomwalters@0 1527 }
tomwalters@0 1528
tomwalters@0 1529 // remove trailing spaces from the key
tomwalters@0 1530 pTrail = a_pData - 1;
tomwalters@0 1531 while (pTrail >= a_pKey && IsSpace(*pTrail)) {
tomwalters@0 1532 --pTrail;
tomwalters@0 1533 }
tomwalters@0 1534 ++pTrail;
tomwalters@0 1535 *pTrail = 0;
tomwalters@0 1536
tomwalters@0 1537 // skip leading whitespace on the value
tomwalters@0 1538 ++a_pData; // safe as checked that it == '=' above
tomwalters@0 1539 while (*a_pData && !IsNewLineChar(*a_pData) && IsSpace(*a_pData)) {
tomwalters@0 1540 ++a_pData;
tomwalters@0 1541 }
tomwalters@0 1542
tomwalters@0 1543 // find the end of the value which is the end of this line
tomwalters@0 1544 a_pVal = a_pData;
tomwalters@0 1545 while (*a_pData && !IsNewLineChar(*a_pData)) {
tomwalters@0 1546 ++a_pData;
tomwalters@0 1547 }
tomwalters@0 1548
tomwalters@0 1549 // remove trailing spaces from the value
tomwalters@0 1550 pTrail = a_pData - 1;
tomwalters@0 1551 if (*a_pData) { // prepare for the next round
tomwalters@0 1552 SkipNewLine(a_pData);
tomwalters@0 1553 }
tomwalters@0 1554 while (pTrail >= a_pVal && IsSpace(*pTrail)) {
tomwalters@0 1555 --pTrail;
tomwalters@0 1556 }
tomwalters@0 1557 ++pTrail;
tomwalters@0 1558 *pTrail = 0;
tomwalters@0 1559
tomwalters@0 1560 // check for multi-line entries
tomwalters@0 1561 if (m_bAllowMultiLine && IsMultiLineTag(a_pVal)) {
tomwalters@0 1562 // skip the "<<<" to get the tag that will end the multiline
tomwalters@0 1563 const SI_CHAR * pTagName = a_pVal + 3;
tomwalters@0 1564 return LoadMultiLineText(a_pData, a_pVal, pTagName);
tomwalters@0 1565 }
tomwalters@0 1566
tomwalters@0 1567 // return the standard entry
tomwalters@0 1568 return true;
tomwalters@0 1569 }
tomwalters@0 1570
tomwalters@0 1571 return false;
tomwalters@0 1572 }
tomwalters@0 1573
tomwalters@0 1574 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1575 bool
tomwalters@0 1576 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineTag(
tomwalters@0 1577 const SI_CHAR * a_pVal
tomwalters@0 1578 ) const
tomwalters@0 1579 {
tomwalters@0 1580 // check for the "<<<" prefix for a multi-line entry
tomwalters@0 1581 if (*a_pVal++ != '<') return false;
tomwalters@0 1582 if (*a_pVal++ != '<') return false;
tomwalters@0 1583 if (*a_pVal++ != '<') return false;
tomwalters@0 1584 return true;
tomwalters@0 1585 }
tomwalters@0 1586
tomwalters@0 1587 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1588 bool
tomwalters@0 1589 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsMultiLineData(
tomwalters@0 1590 const SI_CHAR * a_pData
tomwalters@0 1591 ) const
tomwalters@0 1592 {
tomwalters@0 1593 // data is multi-line if it has any of the following features:
tomwalters@0 1594 // * whitespace prefix
tomwalters@0 1595 // * embedded newlines
tomwalters@0 1596 // * whitespace suffix
tomwalters@0 1597
tomwalters@0 1598 // empty string
tomwalters@0 1599 if (!*a_pData) {
tomwalters@0 1600 return false;
tomwalters@0 1601 }
tomwalters@0 1602
tomwalters@0 1603 // check for prefix
tomwalters@0 1604 if (IsSpace(*a_pData)) {
tomwalters@0 1605 return true;
tomwalters@0 1606 }
tomwalters@0 1607
tomwalters@0 1608 // embedded newlines
tomwalters@0 1609 while (*a_pData) {
tomwalters@0 1610 if (IsNewLineChar(*a_pData)) {
tomwalters@0 1611 return true;
tomwalters@0 1612 }
tomwalters@0 1613 ++a_pData;
tomwalters@0 1614 }
tomwalters@0 1615
tomwalters@0 1616 // check for suffix
tomwalters@0 1617 if (IsSpace(*--a_pData)) {
tomwalters@0 1618 return true;
tomwalters@0 1619 }
tomwalters@0 1620
tomwalters@0 1621 return false;
tomwalters@0 1622 }
tomwalters@0 1623
tomwalters@0 1624 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1625 bool
tomwalters@0 1626 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::IsNewLineChar(
tomwalters@0 1627 SI_CHAR a_c
tomwalters@0 1628 ) const
tomwalters@0 1629 {
tomwalters@0 1630 return (a_c == '\n' || a_c == '\r');
tomwalters@0 1631 }
tomwalters@0 1632
tomwalters@0 1633 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1634 bool
tomwalters@0 1635 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadMultiLineText(
tomwalters@0 1636 SI_CHAR *& a_pData,
tomwalters@0 1637 const SI_CHAR *& a_pVal,
tomwalters@0 1638 const SI_CHAR * a_pTagName,
tomwalters@0 1639 bool a_bAllowBlankLinesInComment
tomwalters@0 1640 ) const
tomwalters@0 1641 {
tomwalters@0 1642 // we modify this data to strip all newlines down to a single '\n'
tomwalters@0 1643 // character. This means that on Windows we need to strip out some
tomwalters@0 1644 // characters which will make the data shorter.
tomwalters@0 1645 // i.e. LINE1-LINE1\r\nLINE2-LINE2\0 will become
tomwalters@0 1646 // LINE1-LINE1\nLINE2-LINE2\0
tomwalters@0 1647 // The pDataLine entry is the pointer to the location in memory that
tomwalters@0 1648 // the current line needs to start to run following the existing one.
tomwalters@0 1649 // This may be the same as pCurrLine in which case no move is needed.
tomwalters@0 1650 SI_CHAR * pDataLine = a_pData;
tomwalters@0 1651 SI_CHAR * pCurrLine;
tomwalters@0 1652
tomwalters@0 1653 // value starts at the current line
tomwalters@0 1654 a_pVal = a_pData;
tomwalters@0 1655
tomwalters@0 1656 // find the end tag. This tag must start in column 1 and be
tomwalters@0 1657 // followed by a newline. No whitespace removal is done while
tomwalters@0 1658 // searching for this tag.
tomwalters@0 1659 SI_CHAR cEndOfLineChar = *a_pData;
tomwalters@0 1660 for(;;) {
tomwalters@0 1661 // if we are loading comments then we need a comment character as
tomwalters@0 1662 // the first character on every line
tomwalters@0 1663 if (!a_pTagName && !IsComment(*a_pData)) {
tomwalters@0 1664 // if we aren't allowing blank lines then we're done
tomwalters@0 1665 if (!a_bAllowBlankLinesInComment) {
tomwalters@0 1666 break;
tomwalters@0 1667 }
tomwalters@0 1668
tomwalters@0 1669 // if we are allowing blank lines then we only include them
tomwalters@0 1670 // in this comment if another comment follows, so read ahead
tomwalters@0 1671 // to find out.
tomwalters@0 1672 SI_CHAR * pCurr = a_pData;
tomwalters@0 1673 int nNewLines = 0;
tomwalters@0 1674 while (IsSpace(*pCurr)) {
tomwalters@0 1675 if (IsNewLineChar(*pCurr)) {
tomwalters@0 1676 ++nNewLines;
tomwalters@0 1677 SkipNewLine(pCurr);
tomwalters@0 1678 }
tomwalters@0 1679 else {
tomwalters@0 1680 ++pCurr;
tomwalters@0 1681 }
tomwalters@0 1682 }
tomwalters@0 1683
tomwalters@0 1684 // we have a comment, add the blank lines to the output
tomwalters@0 1685 // and continue processing from here
tomwalters@0 1686 if (IsComment(*pCurr)) {
tomwalters@0 1687 for (; nNewLines > 0; --nNewLines) *pDataLine++ = '\n';
tomwalters@0 1688 a_pData = pCurr;
tomwalters@0 1689 continue;
tomwalters@0 1690 }
tomwalters@0 1691
tomwalters@0 1692 // the comment ends here
tomwalters@0 1693 break;
tomwalters@0 1694 }
tomwalters@0 1695
tomwalters@0 1696 // find the end of this line
tomwalters@0 1697 pCurrLine = a_pData;
tomwalters@0 1698 while (*a_pData && !IsNewLineChar(*a_pData)) ++a_pData;
tomwalters@0 1699
tomwalters@0 1700 // move this line down to the location that it should be if necessary
tomwalters@0 1701 if (pDataLine < pCurrLine) {
tomwalters@0 1702 size_t nLen = (size_t) (a_pData - pCurrLine);
tomwalters@0 1703 memmove(pDataLine, pCurrLine, nLen * sizeof(SI_CHAR));
tomwalters@0 1704 pDataLine[nLen] = '\0';
tomwalters@0 1705 }
tomwalters@0 1706
tomwalters@0 1707 // end the line with a NULL
tomwalters@0 1708 cEndOfLineChar = *a_pData;
tomwalters@0 1709 *a_pData = 0;
tomwalters@0 1710
tomwalters@0 1711 // if are looking for a tag then do the check now. This is done before
tomwalters@0 1712 // checking for end of the data, so that if we have the tag at the end
tomwalters@0 1713 // of the data then the tag is removed correctly.
tomwalters@0 1714 if (a_pTagName &&
tomwalters@0 1715 (!IsLess(pDataLine, a_pTagName) && !IsLess(a_pTagName, pDataLine)))
tomwalters@0 1716 {
tomwalters@0 1717 break;
tomwalters@0 1718 }
tomwalters@0 1719
tomwalters@0 1720 // if we are at the end of the data then we just automatically end
tomwalters@0 1721 // this entry and return the current data.
tomwalters@0 1722 if (!cEndOfLineChar) {
tomwalters@0 1723 return true;
tomwalters@0 1724 }
tomwalters@0 1725
tomwalters@0 1726 // otherwise we need to process this newline to ensure that it consists
tomwalters@0 1727 // of just a single \n character.
tomwalters@0 1728 pDataLine += (a_pData - pCurrLine);
tomwalters@0 1729 *a_pData = cEndOfLineChar;
tomwalters@0 1730 SkipNewLine(a_pData);
tomwalters@0 1731 *pDataLine++ = '\n';
tomwalters@0 1732 }
tomwalters@0 1733
tomwalters@0 1734 // if we didn't find a comment at all then return false
tomwalters@0 1735 if (a_pVal == a_pData) {
tomwalters@0 1736 a_pVal = NULL;
tomwalters@0 1737 return false;
tomwalters@0 1738 }
tomwalters@0 1739
tomwalters@0 1740 // the data (which ends at the end of the last line) needs to be
tomwalters@0 1741 // null-terminated BEFORE before the newline character(s). If the
tomwalters@0 1742 // user wants a new line in the multi-line data then they need to
tomwalters@0 1743 // add an empty line before the tag.
tomwalters@0 1744 *--pDataLine = '\0';
tomwalters@0 1745
tomwalters@0 1746 // if looking for a tag and if we aren't at the end of the data,
tomwalters@0 1747 // then move a_pData to the start of the next line.
tomwalters@0 1748 if (a_pTagName && cEndOfLineChar) {
tomwalters@0 1749 SI_ASSERT(IsNewLineChar(cEndOfLineChar));
tomwalters@0 1750 *a_pData = cEndOfLineChar;
tomwalters@0 1751 SkipNewLine(a_pData);
tomwalters@0 1752 }
tomwalters@0 1753
tomwalters@0 1754 return true;
tomwalters@0 1755 }
tomwalters@0 1756
tomwalters@0 1757 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1758 SI_Error
tomwalters@0 1759 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::CopyString(
tomwalters@0 1760 const SI_CHAR *& a_pString
tomwalters@0 1761 )
tomwalters@0 1762 {
tomwalters@0 1763 size_t uLen = 0;
tomwalters@0 1764 if (sizeof(SI_CHAR) == sizeof(char)) {
tomwalters@0 1765 uLen = strlen((const char *)a_pString);
tomwalters@0 1766 }
tomwalters@0 1767 else if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
tomwalters@0 1768 uLen = wcslen((const wchar_t *)a_pString);
tomwalters@0 1769 }
tomwalters@0 1770 else {
tomwalters@0 1771 for ( ; a_pString[uLen]; ++uLen) /*loop*/ ;
tomwalters@0 1772 }
tomwalters@0 1773 ++uLen; // NULL character
tomwalters@0 1774 SI_CHAR * pCopy = new SI_CHAR[uLen];
tomwalters@0 1775 if (!pCopy) {
tomwalters@0 1776 return SI_NOMEM;
tomwalters@0 1777 }
tomwalters@0 1778 memcpy(pCopy, a_pString, sizeof(SI_CHAR)*uLen);
tomwalters@0 1779 m_strings.push_back(pCopy);
tomwalters@0 1780 a_pString = pCopy;
tomwalters@0 1781 return SI_OK;
tomwalters@0 1782 }
tomwalters@0 1783
tomwalters@0 1784 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1785 SI_Error
tomwalters@0 1786 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
tomwalters@0 1787 const SI_CHAR * a_pSection,
tomwalters@0 1788 const SI_CHAR * a_pKey,
tomwalters@0 1789 const SI_CHAR * a_pValue,
tomwalters@0 1790 const SI_CHAR * a_pComment,
tomwalters@0 1791 bool a_bForceReplace,
tomwalters@0 1792 bool a_bCopyStrings
tomwalters@0 1793 )
tomwalters@0 1794 {
tomwalters@0 1795 SI_Error rc;
tomwalters@0 1796 bool bInserted = false;
tomwalters@0 1797
tomwalters@0 1798 SI_ASSERT(!a_pComment || IsComment(*a_pComment));
tomwalters@0 1799
tomwalters@0 1800 // if we are copying strings then make a copy of the comment now
tomwalters@0 1801 // because we will need it when we add the entry.
tomwalters@0 1802 if (a_bCopyStrings && a_pComment) {
tomwalters@0 1803 rc = CopyString(a_pComment);
tomwalters@0 1804 if (rc < 0) return rc;
tomwalters@0 1805 }
tomwalters@0 1806
tomwalters@0 1807 // create the section entry if necessary
tomwalters@0 1808 typename TSection::iterator iSection = m_data.find(a_pSection);
tomwalters@0 1809 if (iSection == m_data.end()) {
tomwalters@0 1810 // if the section doesn't exist then we need a copy as the
tomwalters@0 1811 // string needs to last beyond the end of this function
tomwalters@0 1812 if (a_bCopyStrings) {
tomwalters@0 1813 rc = CopyString(a_pSection);
tomwalters@0 1814 if (rc < 0) return rc;
tomwalters@0 1815 }
tomwalters@0 1816
tomwalters@0 1817 // only set the comment if this is a section only entry
tomwalters@0 1818 Entry oSection(a_pSection, ++m_nOrder);
tomwalters@0 1819 if (a_pComment && (!a_pKey || !a_pValue)) {
tomwalters@0 1820 oSection.pComment = a_pComment;
tomwalters@0 1821 }
tomwalters@0 1822
tomwalters@0 1823 typename TSection::value_type oEntry(oSection, TKeyVal());
tomwalters@0 1824 typedef typename TSection::iterator SectionIterator;
tomwalters@0 1825 std::pair<SectionIterator,bool> i = m_data.insert(oEntry);
tomwalters@0 1826 iSection = i.first;
tomwalters@0 1827 bInserted = true;
tomwalters@0 1828 }
tomwalters@0 1829 if (!a_pKey || !a_pValue) {
tomwalters@0 1830 // section only entries are specified with pItem and pVal as NULL
tomwalters@0 1831 return bInserted ? SI_INSERTED : SI_UPDATED;
tomwalters@0 1832 }
tomwalters@0 1833
tomwalters@0 1834 // check for existence of the key
tomwalters@0 1835 TKeyVal & keyval = iSection->second;
tomwalters@0 1836 typename TKeyVal::iterator iKey = keyval.find(a_pKey);
tomwalters@0 1837
tomwalters@0 1838 // remove all existing entries but save the load order and
tomwalters@0 1839 // comment of the first entry
tomwalters@0 1840 int nLoadOrder = ++m_nOrder;
tomwalters@0 1841 if (iKey != keyval.end() && m_bAllowMultiKey && a_bForceReplace) {
tomwalters@0 1842 const SI_CHAR * pComment = NULL;
tomwalters@0 1843 while (iKey != keyval.end() && !IsLess(a_pKey, iKey->first.pItem)) {
tomwalters@0 1844 if (iKey->first.nOrder < nLoadOrder) {
tomwalters@0 1845 nLoadOrder = iKey->first.nOrder;
tomwalters@0 1846 pComment = iKey->first.pComment;
tomwalters@0 1847 }
tomwalters@0 1848 ++iKey;
tomwalters@0 1849 }
tomwalters@0 1850 if (pComment) {
tomwalters@0 1851 DeleteString(a_pComment);
tomwalters@0 1852 a_pComment = pComment;
tomwalters@0 1853 CopyString(a_pComment);
tomwalters@0 1854 }
tomwalters@0 1855 Delete(a_pSection, a_pKey);
tomwalters@0 1856 iKey = keyval.end();
tomwalters@0 1857 }
tomwalters@0 1858
tomwalters@0 1859 // make string copies if necessary
tomwalters@0 1860 bool bForceCreateNewKey = m_bAllowMultiKey && !a_bForceReplace;
tomwalters@0 1861 if (a_bCopyStrings) {
tomwalters@0 1862 if (bForceCreateNewKey || iKey == keyval.end()) {
tomwalters@0 1863 // if the key doesn't exist then we need a copy as the
tomwalters@0 1864 // string needs to last beyond the end of this function
tomwalters@0 1865 // because we will be inserting the key next
tomwalters@0 1866 rc = CopyString(a_pKey);
tomwalters@0 1867 if (rc < 0) return rc;
tomwalters@0 1868 }
tomwalters@0 1869
tomwalters@0 1870 // we always need a copy of the value
tomwalters@0 1871 rc = CopyString(a_pValue);
tomwalters@0 1872 if (rc < 0) return rc;
tomwalters@0 1873 }
tomwalters@0 1874
tomwalters@0 1875 // create the key entry
tomwalters@0 1876 if (iKey == keyval.end() || bForceCreateNewKey) {
tomwalters@0 1877 Entry oKey(a_pKey, nLoadOrder);
tomwalters@0 1878 if (a_pComment) {
tomwalters@0 1879 oKey.pComment = a_pComment;
tomwalters@0 1880 }
tomwalters@0 1881 typename TKeyVal::value_type oEntry(oKey, NULL);
tomwalters@0 1882 iKey = keyval.insert(oEntry);
tomwalters@0 1883 bInserted = true;
tomwalters@0 1884 }
tomwalters@0 1885 iKey->second = a_pValue;
tomwalters@0 1886 return bInserted ? SI_INSERTED : SI_UPDATED;
tomwalters@0 1887 }
tomwalters@0 1888
tomwalters@0 1889 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1890 const SI_CHAR *
tomwalters@0 1891 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetValue(
tomwalters@0 1892 const SI_CHAR * a_pSection,
tomwalters@0 1893 const SI_CHAR * a_pKey,
tomwalters@0 1894 const SI_CHAR * a_pDefault,
tomwalters@0 1895 bool * a_pHasMultiple
tomwalters@0 1896 ) const
tomwalters@0 1897 {
tomwalters@0 1898 if (a_pHasMultiple) {
tomwalters@0 1899 *a_pHasMultiple = false;
tomwalters@0 1900 }
tomwalters@0 1901 if (!a_pSection || !a_pKey) {
tomwalters@0 1902 return a_pDefault;
tomwalters@0 1903 }
tomwalters@0 1904 typename TSection::const_iterator iSection = m_data.find(a_pSection);
tomwalters@0 1905 if (iSection == m_data.end()) {
tomwalters@0 1906 return a_pDefault;
tomwalters@0 1907 }
tomwalters@0 1908 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
tomwalters@0 1909 if (iKeyVal == iSection->second.end()) {
tomwalters@0 1910 return a_pDefault;
tomwalters@0 1911 }
tomwalters@0 1912
tomwalters@0 1913 // check for multiple entries with the same key
tomwalters@0 1914 if (m_bAllowMultiKey && a_pHasMultiple) {
tomwalters@0 1915 typename TKeyVal::const_iterator iTemp = iKeyVal;
tomwalters@0 1916 if (++iTemp != iSection->second.end()) {
tomwalters@0 1917 if (!IsLess(a_pKey, iTemp->first.pItem)) {
tomwalters@0 1918 *a_pHasMultiple = true;
tomwalters@0 1919 }
tomwalters@0 1920 }
tomwalters@0 1921 }
tomwalters@0 1922
tomwalters@0 1923 return iKeyVal->second;
tomwalters@0 1924 }
tomwalters@0 1925
tomwalters@0 1926 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1927 long
tomwalters@0 1928 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetLongValue(
tomwalters@0 1929 const SI_CHAR * a_pSection,
tomwalters@0 1930 const SI_CHAR * a_pKey,
tomwalters@0 1931 long a_nDefault,
tomwalters@0 1932 bool * a_pHasMultiple
tomwalters@0 1933 ) const
tomwalters@0 1934 {
tomwalters@0 1935 // return the default if we don't have a value
tomwalters@0 1936 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
tomwalters@0 1937 if (!pszValue || !*pszValue) return a_nDefault;
tomwalters@0 1938
tomwalters@0 1939 // convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
tomwalters@0 1940 char szValue[64] = { 0 };
tomwalters@0 1941 SI_CONVERTER c(m_bStoreIsUtf8);
tomwalters@0 1942 if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
tomwalters@0 1943 return a_nDefault;
tomwalters@0 1944 }
tomwalters@0 1945
tomwalters@0 1946 // handle the value as hex if prefaced with "0x"
tomwalters@0 1947 long nValue = a_nDefault;
tomwalters@0 1948 char * pszSuffix = szValue;
tomwalters@0 1949 if (szValue[0] == '0' && (szValue[1] == 'x' || szValue[1] == 'X')) {
tomwalters@0 1950 if (!szValue[2]) return a_nDefault;
tomwalters@0 1951 nValue = strtol(&szValue[2], &pszSuffix, 16);
tomwalters@0 1952 }
tomwalters@0 1953 else {
tomwalters@0 1954 nValue = strtol(szValue, &pszSuffix, 10);
tomwalters@0 1955 }
tomwalters@0 1956
tomwalters@0 1957 // any invalid strings will return the default value
tomwalters@0 1958 if (*pszSuffix) {
tomwalters@0 1959 return a_nDefault;
tomwalters@0 1960 }
tomwalters@0 1961
tomwalters@0 1962 return nValue;
tomwalters@0 1963 }
tomwalters@0 1964
tomwalters@0 1965 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1966 SI_Error
tomwalters@0 1967 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
tomwalters@0 1968 const SI_CHAR * a_pSection,
tomwalters@0 1969 const SI_CHAR * a_pKey,
tomwalters@0 1970 long a_nValue,
tomwalters@0 1971 const SI_CHAR * a_pComment,
tomwalters@0 1972 bool a_bUseHex,
tomwalters@0 1973 bool a_bForceReplace
tomwalters@0 1974 )
tomwalters@0 1975 {
tomwalters@0 1976 // use SetValue to create sections
tomwalters@0 1977 if (!a_pSection || !a_pKey) return SI_FAIL;
tomwalters@0 1978
tomwalters@0 1979 // convert to an ASCII string
tomwalters@0 1980 char szInput[64];
tomwalters@0 1981 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
tomwalters@0 1982 sprintf_s(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
tomwalters@0 1983 #else // !__STDC_WANT_SECURE_LIB__
tomwalters@0 1984 sprintf(szInput, a_bUseHex ? "0x%lx" : "%ld", a_nValue);
tomwalters@0 1985 #endif // __STDC_WANT_SECURE_LIB__
tomwalters@0 1986
tomwalters@0 1987 // convert to output text
tomwalters@0 1988 SI_CHAR szOutput[64];
tomwalters@0 1989 SI_CONVERTER c(m_bStoreIsUtf8);
tomwalters@0 1990 c.ConvertFromStore(szInput, strlen(szInput) + 1,
tomwalters@0 1991 szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
tomwalters@0 1992
tomwalters@0 1993 // actually add it
tomwalters@0 1994 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
tomwalters@0 1995 }
tomwalters@0 1996
tomwalters@0 1997 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 1998 bool
tomwalters@0 1999 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetBoolValue(
tomwalters@0 2000 const SI_CHAR * a_pSection,
tomwalters@0 2001 const SI_CHAR * a_pKey,
tomwalters@0 2002 bool a_bDefault,
tomwalters@0 2003 bool * a_pHasMultiple
tomwalters@0 2004 ) const
tomwalters@0 2005 {
tomwalters@0 2006 // return the default if we don't have a value
tomwalters@0 2007 const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
tomwalters@0 2008 if (!pszValue || !*pszValue) return a_bDefault;
tomwalters@0 2009
tomwalters@0 2010 // we only look at the minimum number of characters
tomwalters@0 2011 switch (pszValue[0]) {
tomwalters@0 2012 case 't': case 'T': // true
tomwalters@0 2013 case 'y': case 'Y': // yes
tomwalters@0 2014 case '1': // 1 (one)
tomwalters@0 2015 return true;
tomwalters@0 2016
tomwalters@0 2017 case 'f': case 'F': // false
tomwalters@0 2018 case 'n': case 'N': // no
tomwalters@0 2019 case '0': // 0 (zero)
tomwalters@0 2020 return false;
tomwalters@0 2021
tomwalters@0 2022 case 'o': case 'O':
tomwalters@0 2023 if (pszValue[1] == 'n' || pszValue[1] == 'N') return true; // on
tomwalters@0 2024 if (pszValue[1] == 'f' || pszValue[1] == 'F') return false; // off
tomwalters@0 2025 break;
tomwalters@0 2026 }
tomwalters@0 2027
tomwalters@0 2028 // no recognized value, return the default
tomwalters@0 2029 return a_bDefault;
tomwalters@0 2030 }
tomwalters@0 2031
tomwalters@0 2032 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2033 SI_Error
tomwalters@0 2034 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetBoolValue(
tomwalters@0 2035 const SI_CHAR * a_pSection,
tomwalters@0 2036 const SI_CHAR * a_pKey,
tomwalters@0 2037 bool a_bValue,
tomwalters@0 2038 const SI_CHAR * a_pComment,
tomwalters@0 2039 bool a_bForceReplace
tomwalters@0 2040 )
tomwalters@0 2041 {
tomwalters@0 2042 // use SetValue to create sections
tomwalters@0 2043 if (!a_pSection || !a_pKey) return SI_FAIL;
tomwalters@0 2044
tomwalters@0 2045 // convert to an ASCII string
tomwalters@0 2046 const char * pszInput = a_bValue ? "true" : "false";
tomwalters@0 2047
tomwalters@0 2048 // convert to output text
tomwalters@0 2049 SI_CHAR szOutput[64];
tomwalters@0 2050 SI_CONVERTER c(m_bStoreIsUtf8);
tomwalters@0 2051 c.ConvertFromStore(pszInput, strlen(pszInput) + 1,
tomwalters@0 2052 szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
tomwalters@0 2053
tomwalters@0 2054 // actually add it
tomwalters@0 2055 return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
tomwalters@0 2056 }
tomwalters@0 2057
tomwalters@0 2058 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2059 bool
tomwalters@0 2060 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllValues(
tomwalters@0 2061 const SI_CHAR * a_pSection,
tomwalters@0 2062 const SI_CHAR * a_pKey,
tomwalters@0 2063 TNamesDepend & a_values
tomwalters@0 2064 ) const
tomwalters@0 2065 {
tomwalters@0 2066 a_values.clear();
tomwalters@0 2067
tomwalters@0 2068 if (!a_pSection || !a_pKey) {
tomwalters@0 2069 return false;
tomwalters@0 2070 }
tomwalters@0 2071 typename TSection::const_iterator iSection = m_data.find(a_pSection);
tomwalters@0 2072 if (iSection == m_data.end()) {
tomwalters@0 2073 return false;
tomwalters@0 2074 }
tomwalters@0 2075 typename TKeyVal::const_iterator iKeyVal = iSection->second.find(a_pKey);
tomwalters@0 2076 if (iKeyVal == iSection->second.end()) {
tomwalters@0 2077 return false;
tomwalters@0 2078 }
tomwalters@0 2079
tomwalters@0 2080 // insert all values for this key
tomwalters@0 2081 a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
tomwalters@0 2082 if (m_bAllowMultiKey) {
tomwalters@0 2083 ++iKeyVal;
tomwalters@0 2084 while (iKeyVal != iSection->second.end() && !IsLess(a_pKey, iKeyVal->first.pItem)) {
tomwalters@0 2085 a_values.push_back(Entry(iKeyVal->second, iKeyVal->first.pComment, iKeyVal->first.nOrder));
tomwalters@0 2086 ++iKeyVal;
tomwalters@0 2087 }
tomwalters@0 2088 }
tomwalters@0 2089
tomwalters@0 2090 return true;
tomwalters@0 2091 }
tomwalters@0 2092
tomwalters@0 2093 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2094 int
tomwalters@0 2095 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSectionSize(
tomwalters@0 2096 const SI_CHAR * a_pSection
tomwalters@0 2097 ) const
tomwalters@0 2098 {
tomwalters@0 2099 if (!a_pSection) {
tomwalters@0 2100 return -1;
tomwalters@0 2101 }
tomwalters@0 2102
tomwalters@0 2103 typename TSection::const_iterator iSection = m_data.find(a_pSection);
tomwalters@0 2104 if (iSection == m_data.end()) {
tomwalters@0 2105 return -1;
tomwalters@0 2106 }
tomwalters@0 2107 const TKeyVal & section = iSection->second;
tomwalters@0 2108
tomwalters@0 2109 // if multi-key isn't permitted then the section size is
tomwalters@0 2110 // the number of keys that we have.
tomwalters@0 2111 if (!m_bAllowMultiKey || section.empty()) {
tomwalters@0 2112 return (int) section.size();
tomwalters@0 2113 }
tomwalters@0 2114
tomwalters@0 2115 // otherwise we need to count them
tomwalters@0 2116 int nCount = 0;
tomwalters@0 2117 const SI_CHAR * pLastKey = NULL;
tomwalters@0 2118 typename TKeyVal::const_iterator iKeyVal = section.begin();
tomwalters@0 2119 for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n) {
tomwalters@0 2120 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
tomwalters@0 2121 ++nCount;
tomwalters@0 2122 pLastKey = iKeyVal->first.pItem;
tomwalters@0 2123 }
tomwalters@0 2124 }
tomwalters@0 2125 return nCount;
tomwalters@0 2126 }
tomwalters@0 2127
tomwalters@0 2128 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2129 const typename CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::TKeyVal *
tomwalters@0 2130 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetSection(
tomwalters@0 2131 const SI_CHAR * a_pSection
tomwalters@0 2132 ) const
tomwalters@0 2133 {
tomwalters@0 2134 if (a_pSection) {
tomwalters@0 2135 typename TSection::const_iterator i = m_data.find(a_pSection);
tomwalters@0 2136 if (i != m_data.end()) {
tomwalters@0 2137 return &(i->second);
tomwalters@0 2138 }
tomwalters@0 2139 }
tomwalters@0 2140 return 0;
tomwalters@0 2141 }
tomwalters@0 2142
tomwalters@0 2143 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2144 void
tomwalters@0 2145 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllSections(
tomwalters@0 2146 TNamesDepend & a_names
tomwalters@0 2147 ) const
tomwalters@0 2148 {
tomwalters@0 2149 a_names.clear();
tomwalters@0 2150 typename TSection::const_iterator i = m_data.begin();
tomwalters@0 2151 for (int n = 0; i != m_data.end(); ++i, ++n ) {
tomwalters@0 2152 a_names.push_back(i->first);
tomwalters@0 2153 }
tomwalters@0 2154 }
tomwalters@0 2155
tomwalters@0 2156 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2157 bool
tomwalters@0 2158 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetAllKeys(
tomwalters@0 2159 const SI_CHAR * a_pSection,
tomwalters@0 2160 TNamesDepend & a_names
tomwalters@0 2161 ) const
tomwalters@0 2162 {
tomwalters@0 2163 a_names.clear();
tomwalters@0 2164
tomwalters@0 2165 if (!a_pSection) {
tomwalters@0 2166 return false;
tomwalters@0 2167 }
tomwalters@0 2168
tomwalters@0 2169 typename TSection::const_iterator iSection = m_data.find(a_pSection);
tomwalters@0 2170 if (iSection == m_data.end()) {
tomwalters@0 2171 return false;
tomwalters@0 2172 }
tomwalters@0 2173
tomwalters@0 2174 const TKeyVal & section = iSection->second;
tomwalters@0 2175 const SI_CHAR * pLastKey = NULL;
tomwalters@0 2176 typename TKeyVal::const_iterator iKeyVal = section.begin();
tomwalters@0 2177 for (int n = 0; iKeyVal != section.end(); ++iKeyVal, ++n ) {
tomwalters@0 2178 if (!pLastKey || IsLess(pLastKey, iKeyVal->first.pItem)) {
tomwalters@0 2179 a_names.push_back(iKeyVal->first);
tomwalters@0 2180 pLastKey = iKeyVal->first.pItem;
tomwalters@0 2181 }
tomwalters@0 2182 }
tomwalters@0 2183
tomwalters@0 2184 return true;
tomwalters@0 2185 }
tomwalters@0 2186
tomwalters@0 2187 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2188 SI_Error
tomwalters@0 2189 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
tomwalters@0 2190 const char * a_pszFile,
tomwalters@0 2191 bool a_bAddSignature
tomwalters@0 2192 ) const
tomwalters@0 2193 {
tomwalters@0 2194 FILE * fp = NULL;
tomwalters@0 2195 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
tomwalters@0 2196 fopen_s(&fp, a_pszFile, "wb");
tomwalters@0 2197 #else // !__STDC_WANT_SECURE_LIB__
tomwalters@0 2198 fp = fopen(a_pszFile, "wb");
tomwalters@0 2199 #endif // __STDC_WANT_SECURE_LIB__
tomwalters@0 2200 if (!fp) return SI_FILE;
tomwalters@0 2201 SI_Error rc = SaveFile(fp, a_bAddSignature);
tomwalters@0 2202 fclose(fp);
tomwalters@0 2203 return rc;
tomwalters@0 2204 }
tomwalters@0 2205
tomwalters@0 2206 #ifdef SI_HAS_WIDE_FILE
tomwalters@0 2207 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2208 SI_Error
tomwalters@0 2209 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
tomwalters@0 2210 const SI_WCHAR_T * a_pwszFile,
tomwalters@0 2211 bool a_bAddSignature
tomwalters@0 2212 ) const
tomwalters@0 2213 {
tomwalters@0 2214 #ifdef _WIN32
tomwalters@0 2215 FILE * fp = NULL;
tomwalters@0 2216 #if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
tomwalters@0 2217 _wfopen_s(&fp, a_pwszFile, L"wb");
tomwalters@0 2218 #else // !__STDC_WANT_SECURE_LIB__
tomwalters@0 2219 fp = _wfopen(a_pwszFile, L"wb");
tomwalters@0 2220 #endif // __STDC_WANT_SECURE_LIB__
tomwalters@0 2221 if (!fp) return SI_FILE;
tomwalters@0 2222 SI_Error rc = SaveFile(fp, a_bAddSignature);
tomwalters@0 2223 fclose(fp);
tomwalters@0 2224 return rc;
tomwalters@0 2225 #else // !_WIN32 (therefore SI_CONVERT_ICU)
tomwalters@0 2226 char szFile[256];
tomwalters@0 2227 u_austrncpy(szFile, a_pwszFile, sizeof(szFile));
tomwalters@0 2228 return SaveFile(szFile, a_bAddSignature);
tomwalters@0 2229 #endif // _WIN32
tomwalters@0 2230 }
tomwalters@0 2231 #endif // SI_HAS_WIDE_FILE
tomwalters@0 2232
tomwalters@0 2233 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2234 SI_Error
tomwalters@0 2235 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SaveFile(
tomwalters@0 2236 FILE * a_pFile,
tomwalters@0 2237 bool a_bAddSignature
tomwalters@0 2238 ) const
tomwalters@0 2239 {
tomwalters@0 2240 FileWriter writer(a_pFile);
tomwalters@0 2241 return Save(writer, a_bAddSignature);
tomwalters@0 2242 }
tomwalters@0 2243
tomwalters@0 2244 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2245 SI_Error
tomwalters@0 2246 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
tomwalters@0 2247 OutputWriter & a_oOutput,
tomwalters@0 2248 bool a_bAddSignature
tomwalters@0 2249 ) const
tomwalters@0 2250 {
tomwalters@0 2251 Converter convert(m_bStoreIsUtf8);
tomwalters@0 2252
tomwalters@0 2253 // add the UTF-8 signature if it is desired
tomwalters@0 2254 if (m_bStoreIsUtf8 && a_bAddSignature) {
tomwalters@0 2255 a_oOutput.Write(SI_UTF8_SIGNATURE);
tomwalters@0 2256 }
tomwalters@0 2257
tomwalters@0 2258 // get all of the sections sorted in load order
tomwalters@0 2259 TNamesDepend oSections;
tomwalters@0 2260 GetAllSections(oSections);
tomwalters@0 2261 #if defined(_MSC_VER) && _MSC_VER <= 1200
tomwalters@0 2262 oSections.sort();
tomwalters@0 2263 #elif defined(__BORLANDC__)
tomwalters@0 2264 oSections.sort(Entry::LoadOrder());
tomwalters@0 2265 #else
tomwalters@0 2266 oSections.sort(typename Entry::LoadOrder());
tomwalters@0 2267 #endif
tomwalters@0 2268
tomwalters@0 2269 // write the file comment if we have one
tomwalters@0 2270 bool bNeedNewLine = false;
tomwalters@0 2271 if (m_pFileComment) {
tomwalters@0 2272 if (!OutputMultiLineText(a_oOutput, convert, m_pFileComment)) {
tomwalters@0 2273 return SI_FAIL;
tomwalters@0 2274 }
tomwalters@0 2275 bNeedNewLine = true;
tomwalters@0 2276 }
tomwalters@0 2277
tomwalters@0 2278 // iterate through our sections and output the data
tomwalters@0 2279 typename TNamesDepend::const_iterator iSection = oSections.begin();
tomwalters@0 2280 for ( ; iSection != oSections.end(); ++iSection ) {
tomwalters@0 2281 // write out the comment if there is one
tomwalters@0 2282 if (iSection->pComment) {
tomwalters@0 2283 if (bNeedNewLine) {
tomwalters@0 2284 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2285 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2286 }
tomwalters@0 2287 if (!OutputMultiLineText(a_oOutput, convert, iSection->pComment)) {
tomwalters@0 2288 return SI_FAIL;
tomwalters@0 2289 }
tomwalters@0 2290 bNeedNewLine = false;
tomwalters@0 2291 }
tomwalters@0 2292
tomwalters@0 2293 if (bNeedNewLine) {
tomwalters@0 2294 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2295 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2296 bNeedNewLine = false;
tomwalters@0 2297 }
tomwalters@0 2298
tomwalters@0 2299 // write the section (unless there is no section name)
tomwalters@0 2300 if (*iSection->pItem) {
tomwalters@0 2301 if (!convert.ConvertToStore(iSection->pItem)) {
tomwalters@0 2302 return SI_FAIL;
tomwalters@0 2303 }
tomwalters@0 2304 a_oOutput.Write("[");
tomwalters@0 2305 a_oOutput.Write(convert.Data());
tomwalters@0 2306 a_oOutput.Write("]");
tomwalters@0 2307 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2308 }
tomwalters@0 2309
tomwalters@0 2310 // get all of the keys sorted in load order
tomwalters@0 2311 TNamesDepend oKeys;
tomwalters@0 2312 GetAllKeys(iSection->pItem, oKeys);
tomwalters@0 2313 #if defined(_MSC_VER) && _MSC_VER <= 1200
tomwalters@0 2314 oKeys.sort();
tomwalters@0 2315 #elif defined(__BORLANDC__)
tomwalters@0 2316 oKeys.sort(Entry::LoadOrder());
tomwalters@0 2317 #else
tomwalters@0 2318 oKeys.sort(typename Entry::LoadOrder());
tomwalters@0 2319 #endif
tomwalters@0 2320
tomwalters@0 2321 // write all keys and values
tomwalters@0 2322 typename TNamesDepend::const_iterator iKey = oKeys.begin();
tomwalters@0 2323 for ( ; iKey != oKeys.end(); ++iKey) {
tomwalters@0 2324 // get all values for this key
tomwalters@0 2325 TNamesDepend oValues;
tomwalters@0 2326 GetAllValues(iSection->pItem, iKey->pItem, oValues);
tomwalters@0 2327
tomwalters@0 2328 typename TNamesDepend::const_iterator iValue = oValues.begin();
tomwalters@0 2329 for ( ; iValue != oValues.end(); ++iValue) {
tomwalters@0 2330 // write out the comment if there is one
tomwalters@0 2331 if (iValue->pComment) {
tomwalters@0 2332 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2333 if (!OutputMultiLineText(a_oOutput, convert, iValue->pComment)) {
tomwalters@0 2334 return SI_FAIL;
tomwalters@0 2335 }
tomwalters@0 2336 }
tomwalters@0 2337
tomwalters@0 2338 // write the key
tomwalters@0 2339 if (!convert.ConvertToStore(iKey->pItem)) {
tomwalters@0 2340 return SI_FAIL;
tomwalters@0 2341 }
tomwalters@0 2342 a_oOutput.Write(convert.Data());
tomwalters@0 2343
tomwalters@0 2344 // write the value
tomwalters@0 2345 if (!convert.ConvertToStore(iValue->pItem)) {
tomwalters@0 2346 return SI_FAIL;
tomwalters@0 2347 }
tomwalters@0 2348 a_oOutput.Write(m_bSpaces ? " = " : "=");
tomwalters@0 2349 if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
tomwalters@0 2350 // multi-line data needs to be processed specially to ensure
tomwalters@0 2351 // that we use the correct newline format for the current system
tomwalters@0 2352 a_oOutput.Write("<<<SI-END-OF-MULTILINE-TEXT" SI_NEWLINE_A);
tomwalters@0 2353 if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
tomwalters@0 2354 return SI_FAIL;
tomwalters@0 2355 }
tomwalters@0 2356 a_oOutput.Write("SI-END-OF-MULTILINE-TEXT");
tomwalters@0 2357 }
tomwalters@0 2358 else {
tomwalters@0 2359 a_oOutput.Write(convert.Data());
tomwalters@0 2360 }
tomwalters@0 2361 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2362 }
tomwalters@0 2363 }
tomwalters@0 2364
tomwalters@0 2365 bNeedNewLine = true;
tomwalters@0 2366 }
tomwalters@0 2367
tomwalters@0 2368 return SI_OK;
tomwalters@0 2369 }
tomwalters@0 2370
tomwalters@0 2371 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2372 bool
tomwalters@0 2373 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::OutputMultiLineText(
tomwalters@0 2374 OutputWriter & a_oOutput,
tomwalters@0 2375 Converter & a_oConverter,
tomwalters@0 2376 const SI_CHAR * a_pText
tomwalters@0 2377 ) const
tomwalters@0 2378 {
tomwalters@0 2379 const SI_CHAR * pEndOfLine;
tomwalters@0 2380 SI_CHAR cEndOfLineChar = *a_pText;
tomwalters@0 2381 while (cEndOfLineChar) {
tomwalters@0 2382 // find the end of this line
tomwalters@0 2383 pEndOfLine = a_pText;
tomwalters@0 2384 for (; *pEndOfLine && *pEndOfLine != '\n'; ++pEndOfLine) /*loop*/ ;
tomwalters@0 2385 cEndOfLineChar = *pEndOfLine;
tomwalters@0 2386
tomwalters@0 2387 // temporarily null terminate, convert and output the line
tomwalters@0 2388 *const_cast<SI_CHAR*>(pEndOfLine) = 0;
tomwalters@0 2389 if (!a_oConverter.ConvertToStore(a_pText)) {
tomwalters@0 2390 return false;
tomwalters@0 2391 }
tomwalters@0 2392 *const_cast<SI_CHAR*>(pEndOfLine) = cEndOfLineChar;
tomwalters@0 2393 a_pText += (pEndOfLine - a_pText) + 1;
tomwalters@0 2394 a_oOutput.Write(a_oConverter.Data());
tomwalters@0 2395 a_oOutput.Write(SI_NEWLINE_A);
tomwalters@0 2396 }
tomwalters@0 2397 return true;
tomwalters@0 2398 }
tomwalters@0 2399
tomwalters@0 2400 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2401 bool
tomwalters@0 2402 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Delete(
tomwalters@0 2403 const SI_CHAR * a_pSection,
tomwalters@0 2404 const SI_CHAR * a_pKey,
tomwalters@0 2405 bool a_bRemoveEmpty
tomwalters@0 2406 )
tomwalters@0 2407 {
tomwalters@0 2408 if (!a_pSection) {
tomwalters@0 2409 return false;
tomwalters@0 2410 }
tomwalters@0 2411
tomwalters@0 2412 typename TSection::iterator iSection = m_data.find(a_pSection);
tomwalters@0 2413 if (iSection == m_data.end()) {
tomwalters@0 2414 return false;
tomwalters@0 2415 }
tomwalters@0 2416
tomwalters@0 2417 // remove a single key if we have a keyname
tomwalters@0 2418 if (a_pKey) {
tomwalters@0 2419 typename TKeyVal::iterator iKeyVal = iSection->second.find(a_pKey);
tomwalters@0 2420 if (iKeyVal == iSection->second.end()) {
tomwalters@0 2421 return false;
tomwalters@0 2422 }
tomwalters@0 2423
tomwalters@0 2424 // remove any copied strings and then the key
tomwalters@0 2425 typename TKeyVal::iterator iDelete;
tomwalters@0 2426 do {
tomwalters@0 2427 iDelete = iKeyVal++;
tomwalters@0 2428
tomwalters@0 2429 DeleteString(iDelete->first.pItem);
tomwalters@0 2430 DeleteString(iDelete->second);
tomwalters@0 2431 iSection->second.erase(iDelete);
tomwalters@0 2432 }
tomwalters@0 2433 while (iKeyVal != iSection->second.end()
tomwalters@0 2434 && !IsLess(a_pKey, iKeyVal->first.pItem));
tomwalters@0 2435
tomwalters@0 2436 // done now if the section is not empty or we are not pruning away
tomwalters@0 2437 // the empty sections. Otherwise let it fall through into the section
tomwalters@0 2438 // deletion code
tomwalters@0 2439 if (!a_bRemoveEmpty || !iSection->second.empty()) {
tomwalters@0 2440 return true;
tomwalters@0 2441 }
tomwalters@0 2442 }
tomwalters@0 2443 else {
tomwalters@0 2444 // delete all copied strings from this section. The actual
tomwalters@0 2445 // entries will be removed when the section is removed.
tomwalters@0 2446 typename TKeyVal::iterator iKeyVal = iSection->second.begin();
tomwalters@0 2447 for ( ; iKeyVal != iSection->second.end(); ++iKeyVal) {
tomwalters@0 2448 DeleteString(iKeyVal->first.pItem);
tomwalters@0 2449 DeleteString(iKeyVal->second);
tomwalters@0 2450 }
tomwalters@0 2451 }
tomwalters@0 2452
tomwalters@0 2453 // delete the section itself
tomwalters@0 2454 DeleteString(iSection->first.pItem);
tomwalters@0 2455 m_data.erase(iSection);
tomwalters@0 2456
tomwalters@0 2457 return true;
tomwalters@0 2458 }
tomwalters@0 2459
tomwalters@0 2460 template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
tomwalters@0 2461 void
tomwalters@0 2462 CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteString(
tomwalters@0 2463 const SI_CHAR * a_pString
tomwalters@0 2464 )
tomwalters@0 2465 {
tomwalters@0 2466 // strings may exist either inside the data block, or they will be
tomwalters@0 2467 // individually allocated and stored in m_strings. We only physically
tomwalters@0 2468 // delete those stored in m_strings.
tomwalters@0 2469 if (a_pString < m_pData || a_pString >= m_pData + m_uDataLen) {
tomwalters@0 2470 typename TNamesDepend::iterator i = m_strings.begin();
tomwalters@0 2471 for (;i != m_strings.end(); ++i) {
tomwalters@0 2472 if (a_pString == i->pItem) {
tomwalters@0 2473 delete[] const_cast<SI_CHAR*>(i->pItem);
tomwalters@0 2474 m_strings.erase(i);
tomwalters@0 2475 break;
tomwalters@0 2476 }
tomwalters@0 2477 }
tomwalters@0 2478 }
tomwalters@0 2479 }
tomwalters@0 2480
tomwalters@0 2481 // ---------------------------------------------------------------------------
tomwalters@0 2482 // CONVERSION FUNCTIONS
tomwalters@0 2483 // ---------------------------------------------------------------------------
tomwalters@0 2484
tomwalters@0 2485 // Defines the conversion classes for different libraries. Before including
tomwalters@0 2486 // SimpleIni.h, set the converter that you wish you use by defining one of the
tomwalters@0 2487 // following symbols.
tomwalters@0 2488 //
tomwalters@0 2489 // SI_CONVERT_GENERIC Use the Unicode reference conversion library in
tomwalters@0 2490 // the accompanying files ConvertUTF.h/c
tomwalters@0 2491 // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
tomwalters@0 2492 // ICU headers on include path and icuuc.lib
tomwalters@0 2493 // SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
tomwalters@0 2494
tomwalters@0 2495 #if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
tomwalters@0 2496 # ifdef _WIN32
tomwalters@0 2497 # define SI_CONVERT_WIN32
tomwalters@0 2498 # else
tomwalters@0 2499 # define SI_CONVERT_GENERIC
tomwalters@0 2500 # endif
tomwalters@0 2501 #endif
tomwalters@0 2502
tomwalters@0 2503 /**
tomwalters@0 2504 * Generic case-sensitive less than comparison. This class returns numerically
tomwalters@0 2505 * ordered ASCII case-sensitive text for all possible sizes and types of
tomwalters@0 2506 * SI_CHAR.
tomwalters@0 2507 */
tomwalters@0 2508 template<class SI_CHAR>
tomwalters@0 2509 struct SI_GenericCase {
tomwalters@0 2510 bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
tomwalters@0 2511 long cmp;
tomwalters@0 2512 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
tomwalters@0 2513 cmp = (long) *pLeft - (long) *pRight;
tomwalters@0 2514 if (cmp != 0) {
tomwalters@0 2515 return cmp < 0;
tomwalters@0 2516 }
tomwalters@0 2517 }
tomwalters@0 2518 return *pRight != 0;
tomwalters@0 2519 }
tomwalters@0 2520 };
tomwalters@0 2521
tomwalters@0 2522 /**
tomwalters@0 2523 * Generic ASCII case-insensitive less than comparison. This class returns
tomwalters@0 2524 * numerically ordered ASCII case-insensitive text for all possible sizes
tomwalters@0 2525 * and types of SI_CHAR. It is not safe for MBCS text comparison where
tomwalters@0 2526 * ASCII A-Z characters are used in the encoding of multi-byte characters.
tomwalters@0 2527 */
tomwalters@0 2528 template<class SI_CHAR>
tomwalters@0 2529 struct SI_GenericNoCase {
tomwalters@0 2530 inline SI_CHAR locase(SI_CHAR ch) const {
tomwalters@0 2531 return (ch < 'A' || ch > 'Z') ? ch : (ch - 'A' + 'a');
tomwalters@0 2532 }
tomwalters@0 2533 bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
tomwalters@0 2534 long cmp;
tomwalters@0 2535 for ( ;*pLeft && *pRight; ++pLeft, ++pRight) {
tomwalters@0 2536 cmp = (long) locase(*pLeft) - (long) locase(*pRight);
tomwalters@0 2537 if (cmp != 0) {
tomwalters@0 2538 return cmp < 0;
tomwalters@0 2539 }
tomwalters@0 2540 }
tomwalters@0 2541 return *pRight != 0;
tomwalters@0 2542 }
tomwalters@0 2543 };
tomwalters@0 2544
tomwalters@0 2545 /**
tomwalters@0 2546 * Null conversion class for MBCS/UTF-8 to char (or equivalent).
tomwalters@0 2547 */
tomwalters@0 2548 template<class SI_CHAR>
tomwalters@0 2549 class SI_ConvertA {
tomwalters@0 2550 bool m_bStoreIsUtf8;
tomwalters@0 2551 protected:
tomwalters@0 2552 SI_ConvertA() { }
tomwalters@0 2553 public:
tomwalters@0 2554 SI_ConvertA(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
tomwalters@0 2555
tomwalters@0 2556 /* copy and assignment */
tomwalters@0 2557 SI_ConvertA(const SI_ConvertA & rhs) { operator=(rhs); }
tomwalters@0 2558 SI_ConvertA & operator=(const SI_ConvertA & rhs) {
tomwalters@0 2559 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
tomwalters@0 2560 return *this;
tomwalters@0 2561 }
tomwalters@0 2562
tomwalters@0 2563 /** Calculate the number of SI_CHAR required for converting the input
tomwalters@0 2564 * from the storage format. The storage format is always UTF-8 or MBCS.
tomwalters@0 2565 *
tomwalters@0 2566 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
tomwalters@0 2567 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 2568 * must be the actual length of the data, including
tomwalters@0 2569 * NULL byte if NULL terminated string is required.
tomwalters@0 2570 * @return Number of SI_CHAR required by the string when
tomwalters@0 2571 * converted. If there are embedded NULL bytes in the
tomwalters@0 2572 * input data, only the string up and not including
tomwalters@0 2573 * the NULL byte will be converted.
tomwalters@0 2574 * @return -1 cast to size_t on a conversion error.
tomwalters@0 2575 */
tomwalters@0 2576 size_t SizeFromStore(
tomwalters@0 2577 const char * a_pInputData,
tomwalters@0 2578 size_t a_uInputDataLen)
tomwalters@0 2579 {
tomwalters@0 2580 (void)a_pInputData;
tomwalters@0 2581 SI_ASSERT(a_uInputDataLen != (size_t) -1);
tomwalters@0 2582
tomwalters@0 2583 // ASCII/MBCS/UTF-8 needs no conversion
tomwalters@0 2584 return a_uInputDataLen;
tomwalters@0 2585 }
tomwalters@0 2586
tomwalters@0 2587 /** Convert the input string from the storage format to SI_CHAR.
tomwalters@0 2588 * The storage format is always UTF-8 or MBCS.
tomwalters@0 2589 *
tomwalters@0 2590 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
tomwalters@0 2591 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 2592 * must be the actual length of the data, including
tomwalters@0 2593 * NULL byte if NULL terminated string is required.
tomwalters@0 2594 * @param a_pOutputData Pointer to the output buffer to received the
tomwalters@0 2595 * converted data.
tomwalters@0 2596 * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
tomwalters@0 2597 * @return true if all of the input data was successfully
tomwalters@0 2598 * converted.
tomwalters@0 2599 */
tomwalters@0 2600 bool ConvertFromStore(
tomwalters@0 2601 const char * a_pInputData,
tomwalters@0 2602 size_t a_uInputDataLen,
tomwalters@0 2603 SI_CHAR * a_pOutputData,
tomwalters@0 2604 size_t a_uOutputDataSize)
tomwalters@0 2605 {
tomwalters@0 2606 // ASCII/MBCS/UTF-8 needs no conversion
tomwalters@0 2607 if (a_uInputDataLen > a_uOutputDataSize) {
tomwalters@0 2608 return false;
tomwalters@0 2609 }
tomwalters@0 2610 memcpy(a_pOutputData, a_pInputData, a_uInputDataLen);
tomwalters@0 2611 return true;
tomwalters@0 2612 }
tomwalters@0 2613
tomwalters@0 2614 /** Calculate the number of char required by the storage format of this
tomwalters@0 2615 * data. The storage format is always UTF-8 or MBCS.
tomwalters@0 2616 *
tomwalters@0 2617 * @param a_pInputData NULL terminated string to calculate the number of
tomwalters@0 2618 * bytes required to be converted to storage format.
tomwalters@0 2619 * @return Number of bytes required by the string when
tomwalters@0 2620 * converted to storage format. This size always
tomwalters@0 2621 * includes space for the terminating NULL character.
tomwalters@0 2622 * @return -1 cast to size_t on a conversion error.
tomwalters@0 2623 */
tomwalters@0 2624 size_t SizeToStore(
tomwalters@0 2625 const SI_CHAR * a_pInputData)
tomwalters@0 2626 {
tomwalters@0 2627 // ASCII/MBCS/UTF-8 needs no conversion
tomwalters@0 2628 return strlen((const char *)a_pInputData) + 1;
tomwalters@0 2629 }
tomwalters@0 2630
tomwalters@0 2631 /** Convert the input string to the storage format of this data.
tomwalters@0 2632 * The storage format is always UTF-8 or MBCS.
tomwalters@0 2633 *
tomwalters@0 2634 * @param a_pInputData NULL terminated source string to convert. All of
tomwalters@0 2635 * the data will be converted including the
tomwalters@0 2636 * terminating NULL character.
tomwalters@0 2637 * @param a_pOutputData Pointer to the buffer to receive the converted
tomwalters@0 2638 * string.
tomwalters@0 2639 * @param a_uOutputDataSize Size of the output buffer in char.
tomwalters@0 2640 * @return true if all of the input data, including the
tomwalters@0 2641 * terminating NULL character was successfully
tomwalters@0 2642 * converted.
tomwalters@0 2643 */
tomwalters@0 2644 bool ConvertToStore(
tomwalters@0 2645 const SI_CHAR * a_pInputData,
tomwalters@0 2646 char * a_pOutputData,
tomwalters@0 2647 size_t a_uOutputDataSize)
tomwalters@0 2648 {
tomwalters@0 2649 // calc input string length (SI_CHAR type and size independent)
tomwalters@0 2650 size_t uInputLen = strlen((const char *)a_pInputData) + 1;
tomwalters@0 2651 if (uInputLen > a_uOutputDataSize) {
tomwalters@0 2652 return false;
tomwalters@0 2653 }
tomwalters@0 2654
tomwalters@0 2655 // ascii/UTF-8 needs no conversion
tomwalters@0 2656 memcpy(a_pOutputData, a_pInputData, uInputLen);
tomwalters@0 2657 return true;
tomwalters@0 2658 }
tomwalters@0 2659 };
tomwalters@0 2660
tomwalters@0 2661
tomwalters@0 2662 // ---------------------------------------------------------------------------
tomwalters@0 2663 // SI_CONVERT_GENERIC
tomwalters@0 2664 // ---------------------------------------------------------------------------
tomwalters@0 2665 #ifdef SI_CONVERT_GENERIC
tomwalters@0 2666
tomwalters@0 2667 #define SI_Case SI_GenericCase
tomwalters@0 2668 #define SI_NoCase SI_GenericNoCase
tomwalters@0 2669
tomwalters@0 2670 #include <wchar.h>
tomwalters@0 2671 #include "ConvertUTF.h"
tomwalters@0 2672
tomwalters@0 2673 /**
tomwalters@0 2674 * Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference
tomwalters@0 2675 * library functions. This can be used on all platforms.
tomwalters@0 2676 */
tomwalters@0 2677 template<class SI_CHAR>
tomwalters@0 2678 class SI_ConvertW {
tomwalters@0 2679 bool m_bStoreIsUtf8;
tomwalters@0 2680 protected:
tomwalters@0 2681 SI_ConvertW() { }
tomwalters@0 2682 public:
tomwalters@0 2683 SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
tomwalters@0 2684
tomwalters@0 2685 /* copy and assignment */
tomwalters@0 2686 SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
tomwalters@0 2687 SI_ConvertW & operator=(const SI_ConvertW & rhs) {
tomwalters@0 2688 m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
tomwalters@0 2689 return *this;
tomwalters@0 2690 }
tomwalters@0 2691
tomwalters@0 2692 /** Calculate the number of SI_CHAR required for converting the input
tomwalters@0 2693 * from the storage format. The storage format is always UTF-8 or MBCS.
tomwalters@0 2694 *
tomwalters@0 2695 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
tomwalters@0 2696 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 2697 * must be the actual length of the data, including
tomwalters@0 2698 * NULL byte if NULL terminated string is required.
tomwalters@0 2699 * @return Number of SI_CHAR required by the string when
tomwalters@0 2700 * converted. If there are embedded NULL bytes in the
tomwalters@0 2701 * input data, only the string up and not including
tomwalters@0 2702 * the NULL byte will be converted.
tomwalters@0 2703 * @return -1 cast to size_t on a conversion error.
tomwalters@0 2704 */
tomwalters@0 2705 size_t SizeFromStore(
tomwalters@0 2706 const char * a_pInputData,
tomwalters@0 2707 size_t a_uInputDataLen)
tomwalters@0 2708 {
tomwalters@0 2709 SI_ASSERT(a_uInputDataLen != (size_t) -1);
tomwalters@0 2710
tomwalters@0 2711 if (m_bStoreIsUtf8) {
tomwalters@0 2712 // worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
tomwalters@0 2713 // so we just return the same number of characters required as for
tomwalters@0 2714 // the source text.
tomwalters@0 2715 return a_uInputDataLen;
tomwalters@0 2716 }
tomwalters@0 2717 else {
tomwalters@0 2718 return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
tomwalters@0 2719 }
tomwalters@0 2720 }
tomwalters@0 2721
tomwalters@0 2722 /** Convert the input string from the storage format to SI_CHAR.
tomwalters@0 2723 * The storage format is always UTF-8 or MBCS.
tomwalters@0 2724 *
tomwalters@0 2725 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
tomwalters@0 2726 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 2727 * must be the actual length of the data, including
tomwalters@0 2728 * NULL byte if NULL terminated string is required.
tomwalters@0 2729 * @param a_pOutputData Pointer to the output buffer to received the
tomwalters@0 2730 * converted data.
tomwalters@0 2731 * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
tomwalters@0 2732 * @return true if all of the input data was successfully
tomwalters@0 2733 * converted.
tomwalters@0 2734 */
tomwalters@0 2735 bool ConvertFromStore(
tomwalters@0 2736 const char * a_pInputData,
tomwalters@0 2737 size_t a_uInputDataLen,
tomwalters@0 2738 SI_CHAR * a_pOutputData,
tomwalters@0 2739 size_t a_uOutputDataSize)
tomwalters@0 2740 {
tomwalters@0 2741 if (m_bStoreIsUtf8) {
tomwalters@0 2742 // This uses the Unicode reference implementation to do the
tomwalters@0 2743 // conversion from UTF-8 to wchar_t. The required files are
tomwalters@0 2744 // ConvertUTF.h and ConvertUTF.c which should be included in
tomwalters@0 2745 // the distribution but are publically available from unicode.org
tomwalters@0 2746 // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
tomwalters@0 2747 ConversionResult retval;
tomwalters@0 2748 const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
tomwalters@0 2749 if (sizeof(wchar_t) == sizeof(UTF32)) {
tomwalters@0 2750 UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
tomwalters@0 2751 retval = ConvertUTF8toUTF32(
tomwalters@0 2752 &pUtf8, pUtf8 + a_uInputDataLen,
tomwalters@0 2753 &pUtf32, pUtf32 + a_uOutputDataSize,
tomwalters@0 2754 lenientConversion);
tomwalters@0 2755 }
tomwalters@0 2756 else if (sizeof(wchar_t) == sizeof(UTF16)) {
tomwalters@0 2757 UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
tomwalters@0 2758 retval = ConvertUTF8toUTF16(
tomwalters@0 2759 &pUtf8, pUtf8 + a_uInputDataLen,
tomwalters@0 2760 &pUtf16, pUtf16 + a_uOutputDataSize,
tomwalters@0 2761 lenientConversion);
tomwalters@0 2762 }
tomwalters@0 2763 return retval == conversionOK;
tomwalters@0 2764 }
tomwalters@0 2765 else {
tomwalters@0 2766 size_t retval = mbstowcs(a_pOutputData,
tomwalters@0 2767 a_pInputData, a_uOutputDataSize);
tomwalters@0 2768 return retval != (size_t)(-1);
tomwalters@0 2769 }
tomwalters@0 2770 }
tomwalters@0 2771
tomwalters@0 2772 /** Calculate the number of char required by the storage format of this
tomwalters@0 2773 * data. The storage format is always UTF-8 or MBCS.
tomwalters@0 2774 *
tomwalters@0 2775 * @param a_pInputData NULL terminated string to calculate the number of
tomwalters@0 2776 * bytes required to be converted to storage format.
tomwalters@0 2777 * @return Number of bytes required by the string when
tomwalters@0 2778 * converted to storage format. This size always
tomwalters@0 2779 * includes space for the terminating NULL character.
tomwalters@0 2780 * @return -1 cast to size_t on a conversion error.
tomwalters@0 2781 */
tomwalters@0 2782 size_t SizeToStore(
tomwalters@0 2783 const SI_CHAR * a_pInputData)
tomwalters@0 2784 {
tomwalters@0 2785 if (m_bStoreIsUtf8) {
tomwalters@0 2786 // worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
tomwalters@0 2787 size_t uLen = 0;
tomwalters@0 2788 while (a_pInputData[uLen]) {
tomwalters@0 2789 ++uLen;
tomwalters@0 2790 }
tomwalters@0 2791 return (6 * uLen) + 1;
tomwalters@0 2792 }
tomwalters@0 2793 else {
tomwalters@0 2794 size_t uLen = wcstombs(NULL, a_pInputData, 0);
tomwalters@0 2795 if (uLen == (size_t)(-1)) {
tomwalters@0 2796 return uLen;
tomwalters@0 2797 }
tomwalters@0 2798 return uLen + 1; // include NULL terminator
tomwalters@0 2799 }
tomwalters@0 2800 }
tomwalters@0 2801
tomwalters@0 2802 /** Convert the input string to the storage format of this data.
tomwalters@0 2803 * The storage format is always UTF-8 or MBCS.
tomwalters@0 2804 *
tomwalters@0 2805 * @param a_pInputData NULL terminated source string to convert. All of
tomwalters@0 2806 * the data will be converted including the
tomwalters@0 2807 * terminating NULL character.
tomwalters@0 2808 * @param a_pOutputData Pointer to the buffer to receive the converted
tomwalters@0 2809 * string.
tomwalters@0 2810 * @param a_uOutputDataSize Size of the output buffer in char.
tomwalters@0 2811 * @return true if all of the input data, including the
tomwalters@0 2812 * terminating NULL character was successfully
tomwalters@0 2813 * converted.
tomwalters@0 2814 */
tomwalters@0 2815 bool ConvertToStore(
tomwalters@0 2816 const SI_CHAR * a_pInputData,
tomwalters@0 2817 char * a_pOutputData,
tomwalters@0 2818 size_t a_uOutputDataSize
tomwalters@0 2819 )
tomwalters@0 2820 {
tomwalters@0 2821 if (m_bStoreIsUtf8) {
tomwalters@0 2822 // calc input string length (SI_CHAR type and size independent)
tomwalters@0 2823 size_t uInputLen = 0;
tomwalters@0 2824 while (a_pInputData[uInputLen]) {
tomwalters@0 2825 ++uInputLen;
tomwalters@0 2826 }
tomwalters@0 2827 ++uInputLen; // include the NULL char
tomwalters@0 2828
tomwalters@0 2829 // This uses the Unicode reference implementation to do the
tomwalters@0 2830 // conversion from wchar_t to UTF-8. The required files are
tomwalters@0 2831 // ConvertUTF.h and ConvertUTF.c which should be included in
tomwalters@0 2832 // the distribution but are publically available from unicode.org
tomwalters@0 2833 // at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
tomwalters@0 2834 ConversionResult retval;
tomwalters@0 2835 UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
tomwalters@0 2836 if (sizeof(wchar_t) == sizeof(UTF32)) {
tomwalters@0 2837 const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
tomwalters@0 2838 retval = ConvertUTF32toUTF8(
tomwalters@0 2839 &pUtf32, pUtf32 + uInputLen,
tomwalters@0 2840 &pUtf8, pUtf8 + a_uOutputDataSize,
tomwalters@0 2841 lenientConversion);
tomwalters@0 2842 }
tomwalters@0 2843 else if (sizeof(wchar_t) == sizeof(UTF16)) {
tomwalters@0 2844 const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
tomwalters@0 2845 retval = ConvertUTF16toUTF8(
tomwalters@0 2846 &pUtf16, pUtf16 + uInputLen,
tomwalters@0 2847 &pUtf8, pUtf8 + a_uOutputDataSize,
tomwalters@0 2848 lenientConversion);
tomwalters@0 2849 }
tomwalters@0 2850 return retval == conversionOK;
tomwalters@0 2851 }
tomwalters@0 2852 else {
tomwalters@0 2853 size_t retval = wcstombs(a_pOutputData,
tomwalters@0 2854 a_pInputData, a_uOutputDataSize);
tomwalters@0 2855 return retval != (size_t) -1;
tomwalters@0 2856 }
tomwalters@0 2857 }
tomwalters@0 2858 };
tomwalters@0 2859
tomwalters@0 2860 #endif // SI_CONVERT_GENERIC
tomwalters@0 2861
tomwalters@0 2862
tomwalters@0 2863 // ---------------------------------------------------------------------------
tomwalters@0 2864 // SI_CONVERT_ICU
tomwalters@0 2865 // ---------------------------------------------------------------------------
tomwalters@0 2866 #ifdef SI_CONVERT_ICU
tomwalters@0 2867
tomwalters@0 2868 #define SI_Case SI_GenericCase
tomwalters@0 2869 #define SI_NoCase SI_GenericNoCase
tomwalters@0 2870
tomwalters@0 2871 #include <unicode/ucnv.h>
tomwalters@0 2872
tomwalters@0 2873 /**
tomwalters@0 2874 * Converts MBCS/UTF-8 to UChar using ICU. This can be used on all platforms.
tomwalters@0 2875 */
tomwalters@0 2876 template<class SI_CHAR>
tomwalters@0 2877 class SI_ConvertW {
tomwalters@0 2878 const char * m_pEncoding;
tomwalters@0 2879 UConverter * m_pConverter;
tomwalters@0 2880 protected:
tomwalters@0 2881 SI_ConvertW() : m_pEncoding(NULL), m_pConverter(NULL) { }
tomwalters@0 2882 public:
tomwalters@0 2883 SI_ConvertW(bool a_bStoreIsUtf8) : m_pConverter(NULL) {
tomwalters@0 2884 m_pEncoding = a_bStoreIsUtf8 ? "UTF-8" : NULL;
tomwalters@0 2885 }
tomwalters@0 2886
tomwalters@0 2887 /* copy and assignment */
tomwalters@0 2888 SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
tomwalters@0 2889 SI_ConvertW & operator=(const SI_ConvertW & rhs) {
tomwalters@0 2890 m_pEncoding = rhs.m_pEncoding;
tomwalters@0 2891 m_pConverter = NULL;
tomwalters@0 2892 return *this;
tomwalters@0 2893 }
tomwalters@0 2894 ~SI_ConvertW() { if (m_pConverter) ucnv_close(m_pConverter); }
tomwalters@0 2895
tomwalters@0 2896 /** Calculate the number of UChar required for converting the input
tomwalters@0 2897 * from the storage format. The storage format is always UTF-8 or MBCS.
tomwalters@0 2898 *
tomwalters@0 2899 * @param a_pInputData Data in storage format to be converted to UChar.
tomwalters@0 2900 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 2901 * must be the actual length of the data, including
tomwalters@0 2902 * NULL byte if NULL terminated string is required.
tomwalters@0 2903 * @return Number of UChar required by the string when
tomwalters@0 2904 * converted. If there are embedded NULL bytes in the
tomwalters@0 2905 * input data, only the string up and not including
tomwalters@0 2906 * the NULL byte will be converted.
tomwalters@0 2907 * @return -1 cast to size_t on a conversion error.
tomwalters@0 2908 */
tomwalters@0 2909 size_t SizeFromStore(
tomwalters@0 2910 const char * a_pInputData,
tomwalters@0 2911 size_t a_uInputDataLen)
tomwalters@0 2912 {
tomwalters@0 2913 SI_ASSERT(a_uInputDataLen != (size_t) -1);
tomwalters@0 2914
tomwalters@0 2915 UErrorCode nError;
tomwalters@0 2916
tomwalters@0 2917 if (!m_pConverter) {
tomwalters@0 2918 nError = U_ZERO_ERROR;
tomwalters@0 2919 m_pConverter = ucnv_open(m_pEncoding, &nError);
tomwalters@0 2920 if (U_FAILURE(nError)) {
tomwalters@0 2921 return (size_t) -1;
tomwalters@0 2922 }
tomwalters@0 2923 }
tomwalters@0 2924
tomwalters@0 2925 nError = U_ZERO_ERROR;
tomwalters@0 2926 ucnv_resetToUnicode(m_pConverter);
tomwalters@0 2927 int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
tomwalters@0 2928 a_pInputData, (int32_t) a_uInputDataLen, &nError);
tomwalters@0 2929 if (nError != U_BUFFER_OVERFLOW_ERROR) {
tomwalters@0 2930 return (size_t) -1;
tomwalters@0 2931 }
tomwalters@0 2932
tomwalters@0 2933 return (size_t) nLen;
tomwalters@0 2934 }
tomwalters@0 2935
tomwalters@0 2936 /** Convert the input string from the storage format to UChar.
tomwalters@0 2937 * The storage format is always UTF-8 or MBCS.
tomwalters@0 2938 *
tomwalters@0 2939 * @param a_pInputData Data in storage format to be converted to UChar.
tomwalters@0 2940 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 2941 * must be the actual length of the data, including
tomwalters@0 2942 * NULL byte if NULL terminated string is required.
tomwalters@0 2943 * @param a_pOutputData Pointer to the output buffer to received the
tomwalters@0 2944 * converted data.
tomwalters@0 2945 * @param a_uOutputDataSize Size of the output buffer in UChar.
tomwalters@0 2946 * @return true if all of the input data was successfully
tomwalters@0 2947 * converted.
tomwalters@0 2948 */
tomwalters@0 2949 bool ConvertFromStore(
tomwalters@0 2950 const char * a_pInputData,
tomwalters@0 2951 size_t a_uInputDataLen,
tomwalters@0 2952 UChar * a_pOutputData,
tomwalters@0 2953 size_t a_uOutputDataSize)
tomwalters@0 2954 {
tomwalters@0 2955 UErrorCode nError;
tomwalters@0 2956
tomwalters@0 2957 if (!m_pConverter) {
tomwalters@0 2958 nError = U_ZERO_ERROR;
tomwalters@0 2959 m_pConverter = ucnv_open(m_pEncoding, &nError);
tomwalters@0 2960 if (U_FAILURE(nError)) {
tomwalters@0 2961 return false;
tomwalters@0 2962 }
tomwalters@0 2963 }
tomwalters@0 2964
tomwalters@0 2965 nError = U_ZERO_ERROR;
tomwalters@0 2966 ucnv_resetToUnicode(m_pConverter);
tomwalters@0 2967 ucnv_toUChars(m_pConverter,
tomwalters@0 2968 a_pOutputData, (int32_t) a_uOutputDataSize,
tomwalters@0 2969 a_pInputData, (int32_t) a_uInputDataLen, &nError);
tomwalters@0 2970 if (U_FAILURE(nError)) {
tomwalters@0 2971 return false;
tomwalters@0 2972 }
tomwalters@0 2973
tomwalters@0 2974 return true;
tomwalters@0 2975 }
tomwalters@0 2976
tomwalters@0 2977 /** Calculate the number of char required by the storage format of this
tomwalters@0 2978 * data. The storage format is always UTF-8 or MBCS.
tomwalters@0 2979 *
tomwalters@0 2980 * @param a_pInputData NULL terminated string to calculate the number of
tomwalters@0 2981 * bytes required to be converted to storage format.
tomwalters@0 2982 * @return Number of bytes required by the string when
tomwalters@0 2983 * converted to storage format. This size always
tomwalters@0 2984 * includes space for the terminating NULL character.
tomwalters@0 2985 * @return -1 cast to size_t on a conversion error.
tomwalters@0 2986 */
tomwalters@0 2987 size_t SizeToStore(
tomwalters@0 2988 const UChar * a_pInputData)
tomwalters@0 2989 {
tomwalters@0 2990 UErrorCode nError;
tomwalters@0 2991
tomwalters@0 2992 if (!m_pConverter) {
tomwalters@0 2993 nError = U_ZERO_ERROR;
tomwalters@0 2994 m_pConverter = ucnv_open(m_pEncoding, &nError);
tomwalters@0 2995 if (U_FAILURE(nError)) {
tomwalters@0 2996 return (size_t) -1;
tomwalters@0 2997 }
tomwalters@0 2998 }
tomwalters@0 2999
tomwalters@0 3000 nError = U_ZERO_ERROR;
tomwalters@0 3001 ucnv_resetFromUnicode(m_pConverter);
tomwalters@0 3002 int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
tomwalters@0 3003 a_pInputData, -1, &nError);
tomwalters@0 3004 if (nError != U_BUFFER_OVERFLOW_ERROR) {
tomwalters@0 3005 return (size_t) -1;
tomwalters@0 3006 }
tomwalters@0 3007
tomwalters@0 3008 return (size_t) nLen + 1;
tomwalters@0 3009 }
tomwalters@0 3010
tomwalters@0 3011 /** Convert the input string to the storage format of this data.
tomwalters@0 3012 * The storage format is always UTF-8 or MBCS.
tomwalters@0 3013 *
tomwalters@0 3014 * @param a_pInputData NULL terminated source string to convert. All of
tomwalters@0 3015 * the data will be converted including the
tomwalters@0 3016 * terminating NULL character.
tomwalters@0 3017 * @param a_pOutputData Pointer to the buffer to receive the converted
tomwalters@0 3018 * string.
tomwalters@0 3019 * @param a_pOutputDataSize Size of the output buffer in char.
tomwalters@0 3020 * @return true if all of the input data, including the
tomwalters@0 3021 * terminating NULL character was successfully
tomwalters@0 3022 * converted.
tomwalters@0 3023 */
tomwalters@0 3024 bool ConvertToStore(
tomwalters@0 3025 const UChar * a_pInputData,
tomwalters@0 3026 char * a_pOutputData,
tomwalters@0 3027 size_t a_uOutputDataSize)
tomwalters@0 3028 {
tomwalters@0 3029 UErrorCode nError;
tomwalters@0 3030
tomwalters@0 3031 if (!m_pConverter) {
tomwalters@0 3032 nError = U_ZERO_ERROR;
tomwalters@0 3033 m_pConverter = ucnv_open(m_pEncoding, &nError);
tomwalters@0 3034 if (U_FAILURE(nError)) {
tomwalters@0 3035 return false;
tomwalters@0 3036 }
tomwalters@0 3037 }
tomwalters@0 3038
tomwalters@0 3039 nError = U_ZERO_ERROR;
tomwalters@0 3040 ucnv_resetFromUnicode(m_pConverter);
tomwalters@0 3041 ucnv_fromUChars(m_pConverter,
tomwalters@0 3042 a_pOutputData, (int32_t) a_uOutputDataSize,
tomwalters@0 3043 a_pInputData, -1, &nError);
tomwalters@0 3044 if (U_FAILURE(nError)) {
tomwalters@0 3045 return false;
tomwalters@0 3046 }
tomwalters@0 3047
tomwalters@0 3048 return true;
tomwalters@0 3049 }
tomwalters@0 3050 };
tomwalters@0 3051
tomwalters@0 3052 #endif // SI_CONVERT_ICU
tomwalters@0 3053
tomwalters@0 3054
tomwalters@0 3055 // ---------------------------------------------------------------------------
tomwalters@0 3056 // SI_CONVERT_WIN32
tomwalters@0 3057 // ---------------------------------------------------------------------------
tomwalters@0 3058 #ifdef SI_CONVERT_WIN32
tomwalters@0 3059
tomwalters@0 3060 #define SI_Case SI_GenericCase
tomwalters@0 3061
tomwalters@0 3062 // Windows CE doesn't have errno or MBCS libraries
tomwalters@0 3063 #ifdef _WIN32_WCE
tomwalters@0 3064 # ifndef SI_NO_MBCS
tomwalters@0 3065 # define SI_NO_MBCS
tomwalters@0 3066 # endif
tomwalters@0 3067 #endif
tomwalters@0 3068
tomwalters@0 3069 #include <windows.h>
tomwalters@0 3070 #ifdef SI_NO_MBCS
tomwalters@0 3071 # define SI_NoCase SI_GenericNoCase
tomwalters@0 3072 #else // !SI_NO_MBCS
tomwalters@0 3073 /**
tomwalters@0 3074 * Case-insensitive comparison class using Win32 MBCS functions. This class
tomwalters@0 3075 * returns a case-insensitive semi-collation order for MBCS text. It may not
tomwalters@0 3076 * be safe for UTF-8 text returned in char format as we don't know what
tomwalters@0 3077 * characters will be folded by the function! Therefore, if you are using
tomwalters@0 3078 * SI_CHAR == char and SetUnicode(true), then you need to use the generic
tomwalters@0 3079 * SI_NoCase class instead.
tomwalters@0 3080 */
tomwalters@0 3081 #include <mbstring.h>
tomwalters@0 3082 template<class SI_CHAR>
tomwalters@0 3083 struct SI_NoCase {
tomwalters@0 3084 bool operator()(const SI_CHAR * pLeft, const SI_CHAR * pRight) const {
tomwalters@0 3085 if (sizeof(SI_CHAR) == sizeof(char)) {
tomwalters@0 3086 return _mbsicmp((const unsigned char *)pLeft,
tomwalters@0 3087 (const unsigned char *)pRight) < 0;
tomwalters@0 3088 }
tomwalters@0 3089 if (sizeof(SI_CHAR) == sizeof(wchar_t)) {
tomwalters@0 3090 return _wcsicmp((const wchar_t *)pLeft,
tomwalters@0 3091 (const wchar_t *)pRight) < 0;
tomwalters@0 3092 }
tomwalters@0 3093 return SI_GenericNoCase<SI_CHAR>()(pLeft, pRight);
tomwalters@0 3094 }
tomwalters@0 3095 };
tomwalters@0 3096 #endif // SI_NO_MBCS
tomwalters@0 3097
tomwalters@0 3098 /**
tomwalters@0 3099 * Converts MBCS and UTF-8 to a wchar_t (or equivalent) on Windows. This uses
tomwalters@0 3100 * only the Win32 functions and doesn't require the external Unicode UTF-8
tomwalters@0 3101 * conversion library. It will not work on Windows 95 without using Microsoft
tomwalters@0 3102 * Layer for Unicode in your application.
tomwalters@0 3103 */
tomwalters@0 3104 template<class SI_CHAR>
tomwalters@0 3105 class SI_ConvertW {
tomwalters@0 3106 UINT m_uCodePage;
tomwalters@0 3107 protected:
tomwalters@0 3108 SI_ConvertW() { }
tomwalters@0 3109 public:
tomwalters@0 3110 SI_ConvertW(bool a_bStoreIsUtf8) {
tomwalters@0 3111 m_uCodePage = a_bStoreIsUtf8 ? CP_UTF8 : CP_ACP;
tomwalters@0 3112 }
tomwalters@0 3113
tomwalters@0 3114 /* copy and assignment */
tomwalters@0 3115 SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
tomwalters@0 3116 SI_ConvertW & operator=(const SI_ConvertW & rhs) {
tomwalters@0 3117 m_uCodePage = rhs.m_uCodePage;
tomwalters@0 3118 return *this;
tomwalters@0 3119 }
tomwalters@0 3120
tomwalters@0 3121 /** Calculate the number of SI_CHAR required for converting the input
tomwalters@0 3122 * from the storage format. The storage format is always UTF-8 or MBCS.
tomwalters@0 3123 *
tomwalters@0 3124 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
tomwalters@0 3125 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 3126 * must be the actual length of the data, including
tomwalters@0 3127 * NULL byte if NULL terminated string is required.
tomwalters@0 3128 * @return Number of SI_CHAR required by the string when
tomwalters@0 3129 * converted. If there are embedded NULL bytes in the
tomwalters@0 3130 * input data, only the string up and not including
tomwalters@0 3131 * the NULL byte will be converted.
tomwalters@0 3132 * @return -1 cast to size_t on a conversion error.
tomwalters@0 3133 */
tomwalters@0 3134 size_t SizeFromStore(
tomwalters@0 3135 const char * a_pInputData,
tomwalters@0 3136 size_t a_uInputDataLen)
tomwalters@0 3137 {
tomwalters@0 3138 SI_ASSERT(a_uInputDataLen != (size_t) -1);
tomwalters@0 3139
tomwalters@0 3140 int retval = MultiByteToWideChar(
tomwalters@0 3141 m_uCodePage, 0,
tomwalters@0 3142 a_pInputData, (int) a_uInputDataLen,
tomwalters@0 3143 0, 0);
tomwalters@0 3144 return (size_t)(retval > 0 ? retval : -1);
tomwalters@0 3145 }
tomwalters@0 3146
tomwalters@0 3147 /** Convert the input string from the storage format to SI_CHAR.
tomwalters@0 3148 * The storage format is always UTF-8 or MBCS.
tomwalters@0 3149 *
tomwalters@0 3150 * @param a_pInputData Data in storage format to be converted to SI_CHAR.
tomwalters@0 3151 * @param a_uInputDataLen Length of storage format data in bytes. This
tomwalters@0 3152 * must be the actual length of the data, including
tomwalters@0 3153 * NULL byte if NULL terminated string is required.
tomwalters@0 3154 * @param a_pOutputData Pointer to the output buffer to received the
tomwalters@0 3155 * converted data.
tomwalters@0 3156 * @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
tomwalters@0 3157 * @return true if all of the input data was successfully
tomwalters@0 3158 * converted.
tomwalters@0 3159 */
tomwalters@0 3160 bool ConvertFromStore(
tomwalters@0 3161 const char * a_pInputData,
tomwalters@0 3162 size_t a_uInputDataLen,
tomwalters@0 3163 SI_CHAR * a_pOutputData,
tomwalters@0 3164 size_t a_uOutputDataSize)
tomwalters@0 3165 {
tomwalters@0 3166 int nSize = MultiByteToWideChar(
tomwalters@0 3167 m_uCodePage, 0,
tomwalters@0 3168 a_pInputData, (int) a_uInputDataLen,
tomwalters@0 3169 (wchar_t *) a_pOutputData, (int) a_uOutputDataSize);
tomwalters@0 3170 return (nSize > 0);
tomwalters@0 3171 }
tomwalters@0 3172
tomwalters@0 3173 /** Calculate the number of char required by the storage format of this
tomwalters@0 3174 * data. The storage format is always UTF-8.
tomwalters@0 3175 *
tomwalters@0 3176 * @param a_pInputData NULL terminated string to calculate the number of
tomwalters@0 3177 * bytes required to be converted to storage format.
tomwalters@0 3178 * @return Number of bytes required by the string when
tomwalters@0 3179 * converted to storage format. This size always
tomwalters@0 3180 * includes space for the terminating NULL character.
tomwalters@0 3181 * @return -1 cast to size_t on a conversion error.
tomwalters@0 3182 */
tomwalters@0 3183 size_t SizeToStore(
tomwalters@0 3184 const SI_CHAR * a_pInputData)
tomwalters@0 3185 {
tomwalters@0 3186 int retval = WideCharToMultiByte(
tomwalters@0 3187 m_uCodePage, 0,
tomwalters@0 3188 (const wchar_t *) a_pInputData, -1,
tomwalters@0 3189 0, 0, 0, 0);
tomwalters@0 3190 return (size_t) (retval > 0 ? retval : -1);
tomwalters@0 3191 }
tomwalters@0 3192
tomwalters@0 3193 /** Convert the input string to the storage format of this data.
tomwalters@0 3194 * The storage format is always UTF-8 or MBCS.
tomwalters@0 3195 *
tomwalters@0 3196 * @param a_pInputData NULL terminated source string to convert. All of
tomwalters@0 3197 * the data will be converted including the
tomwalters@0 3198 * terminating NULL character.
tomwalters@0 3199 * @param a_pOutputData Pointer to the buffer to receive the converted
tomwalters@0 3200 * string.
tomwalters@0 3201 * @param a_pOutputDataSize Size of the output buffer in char.
tomwalters@0 3202 * @return true if all of the input data, including the
tomwalters@0 3203 * terminating NULL character was successfully
tomwalters@0 3204 * converted.
tomwalters@0 3205 */
tomwalters@0 3206 bool ConvertToStore(
tomwalters@0 3207 const SI_CHAR * a_pInputData,
tomwalters@0 3208 char * a_pOutputData,
tomwalters@0 3209 size_t a_uOutputDataSize)
tomwalters@0 3210 {
tomwalters@0 3211 int retval = WideCharToMultiByte(
tomwalters@0 3212 m_uCodePage, 0,
tomwalters@0 3213 (const wchar_t *) a_pInputData, -1,
tomwalters@0 3214 a_pOutputData, (int) a_uOutputDataSize, 0, 0);
tomwalters@0 3215 return retval > 0;
tomwalters@0 3216 }
tomwalters@0 3217 };
tomwalters@0 3218
tomwalters@0 3219 #endif // SI_CONVERT_WIN32
tomwalters@0 3220
tomwalters@0 3221
tomwalters@0 3222 // ---------------------------------------------------------------------------
tomwalters@0 3223 // TYPE DEFINITIONS
tomwalters@0 3224 // ---------------------------------------------------------------------------
tomwalters@0 3225
tomwalters@0 3226 typedef CSimpleIniTempl<char,
tomwalters@0 3227 SI_NoCase<char>,SI_ConvertA<char> > CSimpleIniA;
tomwalters@0 3228 typedef CSimpleIniTempl<char,
tomwalters@0 3229 SI_Case<char>,SI_ConvertA<char> > CSimpleIniCaseA;
tomwalters@0 3230
tomwalters@0 3231 #if defined(SI_CONVERT_ICU)
tomwalters@0 3232 typedef CSimpleIniTempl<UChar,
tomwalters@0 3233 SI_NoCase<UChar>,SI_ConvertW<UChar> > CSimpleIniW;
tomwalters@0 3234 typedef CSimpleIniTempl<UChar,
tomwalters@0 3235 SI_Case<UChar>,SI_ConvertW<UChar> > CSimpleIniCaseW;
tomwalters@0 3236 #else
tomwalters@0 3237 typedef CSimpleIniTempl<wchar_t,
tomwalters@0 3238 SI_NoCase<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniW;
tomwalters@0 3239 typedef CSimpleIniTempl<wchar_t,
tomwalters@0 3240 SI_Case<wchar_t>,SI_ConvertW<wchar_t> > CSimpleIniCaseW;
tomwalters@0 3241 #endif
tomwalters@0 3242
tomwalters@0 3243 #ifdef _UNICODE
tomwalters@0 3244 # define CSimpleIni CSimpleIniW
tomwalters@0 3245 # define CSimpleIniCase CSimpleIniCaseW
tomwalters@0 3246 # define SI_NEWLINE SI_NEWLINE_W
tomwalters@0 3247 #else // !_UNICODE
tomwalters@0 3248 # define CSimpleIni CSimpleIniA
tomwalters@0 3249 # define CSimpleIniCase CSimpleIniCaseA
tomwalters@0 3250 # define SI_NEWLINE SI_NEWLINE_A
tomwalters@0 3251 #endif // _UNICODE
tomwalters@0 3252
tomwalters@0 3253 #ifdef _MSC_VER
tomwalters@0 3254 # pragma warning (pop)
tomwalters@0 3255 #endif
tomwalters@0 3256
tomwalters@0 3257 #endif // INCLUDED_SimpleIni_h
tomwalters@0 3258