1 /* 2 * This file is part of Dune Legacy. 3 * 4 * Dune Legacy is free software: you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * Dune Legacy is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with Dune Legacy. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #ifndef INIFILE_H 19 #define INIFILE_H 20 21 #include <string> 22 #include <list> 23 #include <algorithm> 24 #include <SDL_rwops.h> 25 #include <SDL.h> 26 27 #define INVALID_LINE (-1) 28 29 //! A class for reading and writing *.ini configuration files. 30 /*! 31 This class can be used to read or write to a *.ini file. An ini-File has a very simple format.<br> 32 Example:<br> 33 <br> 34 ; Comments start with ; or #<br> 35 ; start of the first section with name ""<br> 36 key1 = value1<br> 37 key2 = value2<br> 38 ; start of a section with name "Section1"<br> 39 [Section1]<br> 40 key3 = value3<br> 41 key4 = value4<br> 42 <br> 43 The section names and key names are treated case insensitive. 44 */ 45 class INIFile 46 { 47 public: 48 49 //\cond 50 class INIFileLine; 51 class Key; 52 class KeyIterator; 53 class Section; 54 class SectionIterator; 55 56 57 class INIFileLine 58 { 59 public: 60 INIFileLine(const std::string& completeLine, int lineNumber); 61 getLineNumber()62 inline int getLineNumber() const { return line; }; 63 64 friend class INIFile; 65 friend class INIFile::Section; 66 67 protected: shiftLineNumber(int shift)68 inline void shiftLineNumber(int shift) { 69 INIFileLine* pCurrentLine = this; 70 while(pCurrentLine != nullptr) { 71 pCurrentLine->line += shift; 72 pCurrentLine = pCurrentLine->nextLine; 73 } 74 } 75 76 std::string completeLine; 77 int line; 78 INIFileLine* nextLine; 79 INIFileLine* prevLine; 80 }; 81 82 83 class Key : public INIFileLine 84 { 85 public: 86 Key(const std::string& completeLine, int lineNumber, int keystringbegin, int keystringlength, int valuestringbegin, int valuestringlength); 87 Key(const std::string& keyname, const std::string& value, bool bEscapeIfNeeded = true, bool bWhitespace = true); 88 89 std::string getKeyName() const; 90 std::string getStringValue() const; 91 int getIntValue(int defaultValue = 0) const; 92 bool getBoolValue(bool defaultValue = false) const; 93 float getFloatValue(float defaultValue = 0.0f) const; 94 double getDoubleValue(double defaultValue = 0.0) const; 95 96 void setStringValue(const std::string& newValue, bool bEscapeIfNeeded = true); 97 void setIntValue(int newValue); 98 void setBoolValue(bool newValue); 99 void setDoubleValue(double newValue); 100 101 friend class INIFile; 102 friend class INIFile::KeyIterator; 103 friend class INIFile::Section; 104 friend class INIFile::SectionIterator; 105 106 protected: 107 static bool escapingValueNeeded(const std::string& value); 108 static std::string escapeValue(const std::string& value); 109 110 int keyStringBegin; 111 int keyStringLength; 112 int valueStringBegin; 113 int valueStringLength; 114 Key* nextKey; 115 Key* prevKey; 116 }; 117 118 119 class KeyIterator 120 { 121 public: KeyIterator()122 KeyIterator() : key(nullptr) { 123 } 124 KeyIterator(Key * pKey)125 explicit KeyIterator(Key* pKey) : key(pKey) { 126 } 127 128 Key& operator*() const { 129 return *key; 130 } 131 132 Key* operator->() const { 133 return key; 134 } 135 136 bool operator==(const KeyIterator& other) const { 137 return (key == other.key); 138 } 139 140 bool operator!=(const KeyIterator& other) const { 141 return !(operator==(other)); 142 } 143 144 void operator++() { 145 if(key != nullptr) { 146 key = key->nextKey; 147 } 148 } 149 150 private: 151 Key* key; 152 }; 153 154 155 class Section : public INIFileLine 156 { 157 public: 158 Section(const std::string& completeLine, int lineNumber, int sectionstringbegin, int sectionstringlength, bool bWhitespace = true); 159 Section(const std::string& sectionname, bool bWhitespace = true); 160 161 std::string getSectionName() const; 162 KeyIterator begin() const; 163 KeyIterator end() const; 164 165 bool hasKey(const std::string& key) const; 166 Key* getKey(const std::string& keyname) const; 167 168 void setStringValue(const std::string& key, const std::string& newValue, bool bEscapeIfNeeded = true); 169 void setIntValue(const std::string& key, int newValue); 170 void setBoolValue(const std::string& key, bool newValue); 171 void setDoubleValue(const std::string& key, double newValue); 172 173 friend class INIFile; 174 friend class INIFile::SectionIterator; 175 176 protected: 177 void insertKey(Key* newKey); 178 179 int sectionStringBegin; 180 int sectionStringLength; 181 Section* nextSection; 182 Section* prevSection; 183 Key* keyRoot; 184 bool bWhitespace; 185 }; 186 187 188 class SectionIterator 189 { 190 public: SectionIterator()191 SectionIterator() : section(nullptr) { 192 } 193 SectionIterator(Section * pSection)194 explicit SectionIterator(Section* pSection) : section(pSection) { 195 } 196 197 Section& operator*() const { 198 return *section; 199 } 200 201 Section* operator->() const { 202 return section; 203 } 204 205 bool operator==(const SectionIterator& other) const { 206 return (section == other.section); 207 } 208 209 bool operator!=(const SectionIterator& other) const { 210 return !(operator==(other)); 211 } 212 213 void operator++() { 214 if(section != nullptr) { 215 section = section->nextSection; 216 } 217 } 218 219 private: 220 Section* section; 221 }; 222 //\endcond 223 224 225 226 public: 227 228 INIFile(bool bWhitespace, const std::string& firstLineComment); 229 INIFile(const std::string& filename, bool bWhitespace = true); 230 INIFile(SDL_RWops * RWopsFile, bool bWhitespace = true); 231 INIFile(const INIFile& o) = delete; 232 ~INIFile(); 233 234 bool hasSection(const std::string& section) const; 235 const Section& getSection(const std::string& sectionname) const; 236 bool removeSection(const std::string& sectionname); 237 bool clearSection(const std::string& sectionname, bool bBlankLineAtSectionEnd = true); 238 bool hasKey(const std::string& section, const std::string& key) const; 239 const Key* getKey(const std::string& sectionname, const std::string& keyname) const; 240 bool removeKey(const std::string& section, const std::string& key); 241 242 std::string getStringValue(const std::string& section, const std::string& key, const std::string& defaultValue = "") const; 243 int getIntValue(const std::string& section, const std::string& key, int defaultValue = 0) const; 244 bool getBoolValue(const std::string& section, const std::string& key, bool defaultValue = false) const; 245 float getFloatValue(const std::string& section, const std::string& key, float defaultValue = 0.0f) const; 246 double getDoubleValue(const std::string& section, const std::string& key, double defaultValue = 0.0) const; 247 248 void setStringValue(const std::string& section, const std::string& key, const std::string& value, bool bEscapeIfNeeded = true); 249 void setIntValue(const std::string& section, const std::string& key, int value); 250 void setBoolValue(const std::string& section, const std::string& key, bool value); 251 void setDoubleValue(const std::string& section, const std::string& key, double value); 252 253 SectionIterator begin() const; 254 SectionIterator end() const; 255 256 KeyIterator begin(const std::string& section) const; 257 KeyIterator end(const std::string& section) const; 258 259 bool saveChangesTo(const std::string& filename, bool bDOSLineEnding = false) const; 260 bool saveChangesTo(SDL_RWops * file, bool bDOSLineEnding = false) const; 261 262 private: 263 INIFileLine* firstLine; 264 Section* sectionRoot; 265 bool bWhitespace; 266 267 void flush() const; 268 void readfile(SDL_RWops * file); 269 270 void insertSection(Section* newSection); 271 272 const Section* getSectionInternal(const std::string& sectionname) const; 273 Section* getSectionOrCreate(const std::string& sectionname); 274 275 static bool isValidSectionName(const std::string& sectionname); 276 static bool isValidKeyName(const std::string& keyname); 277 278 static int getNextChar(const unsigned char* line, int startpos); 279 static int skipName(const unsigned char* line,int startpos); 280 static int skipValue(const unsigned char* line,int startpos); 281 static int skipKey(const unsigned char* line,int startpos); 282 static int getNextQuote(const unsigned char* line,int startpos); 283 284 static bool isWhitespace(unsigned char s); 285 static bool isNormalChar(unsigned char s); 286 287 static int strncicmp(const char *s1, const char *s2, size_t n); 288 }; 289 290 #endif // INIFILE_H 291 292