C++ ini解析器

  在gitee上找到的一个很好用的ini文件解析器,纯C++代码,移植方便。

  项目地址:https://gitee.com/sollyu/IniParser

  稍微修改了下,去掉了Windows平台相关定义,改了下类名称。

  头文件:

 1 #ifndef INIPARSER_H
 2 #define INIPARSER_H
 3 
 4 
 5 #include <map>
 6 #include <string>
 7 #include <string.h>
 8 
 9 class IniDoc
10 {
11 public:
12     struct IgnoreCaseLT
13     {
14         bool operator()(const std::string& lhs, const std::string& rhs) const
15         {
16             return strcasecmp(lhs.c_str(), rhs.c_str()) < 0;
17         }
18     };
19 
20 public:
21     typedef std::map<std::string, std::string, IgnoreCaseLT> KeyMap;
22     typedef std::map<std::string, KeyMap,      IgnoreCaseLT> SectionMap;
23     typedef KeyMap::iterator     KeyIterator;
24     typedef SectionMap::iterator SectionIterator;
25 
26 public:
27     // 默认的构造函数和析构函数
28     IniDoc();
29     ~IniDoc();
30 
31     // 构造函数 - 加载文件
32     IniDoc(const std::string& file_name);
33 
34     // 加载一个ini文件, 如果之前的文件被修改, 那么之前的ini文件将会被保持。
35     bool load(const std::string& file_name);
36 
37     // 从字符串中作为ini文件加载
38     bool loadString(const std::string& str);
39 
40     // 保持到加载ini位置
41     bool save();
42 
43     // 另存为一个和加载路径不一样的文件中
44     bool saveAs(const std::string& file_name);
45 
46     // 返回ini是否被修改, 或者他最后一次操作是保存
47     bool isModified() const { return m_modified; }
48 
49 public:    // high level member function.
50 
51     // 下面的成员函数是从Section中获得一些值
52     long getInteger(const std::string& section, const std::string& key, long def_val);
53     float getFloat(const std::string& section, const std::string& key, float def_val);
54     long getStruct(const std::string& section, const std::string& key, void* buffer, long size);
55     long getString(const std::string&  section, const std::string& key, const std::string& def_val, std::string& buffer);
56     const std::string getString(const std::string&  section, const std::string& key, const std::string& def_val);
57 
58     void setInteger(const std::string& section, const std::string& key, long value);
59     void setFloat(const std::string& section, const std::string& key, float value);
60     void setStruct(const std::string& section, const std::string& key, const void* buffer, long size);
61     void setString(const std::string& section, const std::string& key, const std::string& value);
62 
63 public:
64     bool delSection( const std::string& section );
65     bool delKey( const std::string& section, const std::string& key );
66 
67 public:
68     // 返回一个section的map键值对
69     const KeyMap& getSection(const std::string& section) const;
70 
71     // 返回整个ini的Sections
72     const SectionMap& getIni() const { return m_map; }
73 
74 private:
75     void saveBeforeLoad();
76     const char* key_value(const std::string& section, const std::string& key);
77 
78 private:
79     // 禁止复制构造函数和赋值操作符。
80     IniDoc(const IniDoc& copy);
81     IniDoc& operator=(const IniDoc& rhs);
82 
83 private:
84     static const KeyMap ms_emptySection;
85     static const char   left_tag       ;
86     static const char   right_tag      ;
87     static const char   equal          ;
88     static const char   cr             ;
89     static const char   new_line       ;
90     static const char*  empty_str      ;
91     static const int    BUFFER_LEN     ;
92 
93     SectionMap  m_map;
94     std::string m_file_name;
95     bool        m_modified;
96 };
97 
98 #endif // INIPARSER_H
View Code

  源文件:

  1 #include "IniDoc.h"
  2 
  3 #include <fstream>
  4 #include <strstream>
  5 
  6 using namespace std;
  7 
  8 const char  IniDoc::left_tag   = '[' ;
  9 const char  IniDoc::right_tag  = ']' ;
 10 const char  IniDoc::equal      = '=' ;
 11 const char  IniDoc::cr         = '
';
 12 const char  IniDoc::new_line   = '
';
 13 const char* IniDoc::empty_str  = ""  ;
 14 const int   IniDoc::BUFFER_LEN = 255 ;
 15 
 16 const IniDoc::KeyMap IniDoc::ms_emptySection;
 17 
 18 IniDoc::IniDoc() : m_modified(false)
 19 {
 20 
 21 }
 22 
 23 IniDoc::IniDoc(const std::string& file_name) : m_modified(false)
 24 {
 25     load(file_name);
 26 }
 27 
 28 IniDoc::~IniDoc()
 29 {
 30     if(m_modified)
 31         save();
 32 }
 33 
 34 void IniDoc::saveBeforeLoad()
 35 {
 36     if(m_modified)
 37         save();
 38 
 39     m_file_name.resize(0);
 40 
 41     m_map.clear();
 42 
 43     m_modified = false;
 44 }
 45 
 46 const char* IniDoc::key_value(const std::string& section, const std::string& key)
 47 {
 48     SectionIterator itSection = m_map.find(section);
 49     if(m_map.end() != itSection)
 50     {
 51         KeyIterator itKey = itSection->second.find(key);
 52         if(itKey != itSection->second.end())
 53             return itKey->second.c_str();
 54     }
 55 
 56     return 0;
 57 }
 58 
 59 bool IniDoc::load(const std::string& file_name)
 60 {
 61     saveBeforeLoad();
 62 
 63     ifstream file(file_name);
 64     if(!file)
 65         return false;
 66 
 67     file.seekg(0, ios::end);
 68     long len = file.tellg();
 69     if(len < 0)
 70         return false;
 71 
 72 
 73     char* buffer = new char[len + 1];
 74     if(0 == buffer)
 75         return false;
 76 
 77 
 78     file.seekg(0, ios::beg);
 79     file.read(buffer, len);
 80 
 81     buffer[len = file.gcount()] = 0;
 82 
 83     loadString(buffer);
 84     m_file_name = file_name;
 85 
 86     delete[] buffer;
 87 
 88     return true;
 89 }
 90 
 91 bool IniDoc::loadString(const std::string& str)
 92 {
 93     saveBeforeLoad();
 94 
 95     unsigned long length = str.size();
 96 
 97     if (str.size() == 0)
 98         return false;
 99 
100     enum status
101     {
102         after_left_tag,
103         after_section_name,
104         after_section_name_ws,
105         after_key_name,
106         after_key_name_ws,
107         after_equal,
108         start
109     };
110 
111     string section;                       // 当前 section.
112     string key;                           // 当前 key.
113     status sta          = start;          // 解析状态.
114     const char* p       = str.c_str();    // 当前解析字符串的位置.
115     const char* beg     = p;              // 当前元素的开始.
116     const char* last_ws = p;              // 最后一个空格字符.
117 
118     for(; length; ++p, --length)
119     {
120         if(new_line == *p)
121         {
122             if(after_equal == sta)
123             {
124                 if(cr == *(p - 1))
125                     --p;
126 
127                 m_map[section][key] = string(beg, p - beg);
128 
129                 if(cr == *p)
130                     ++p;
131             }
132             sta = start;
133         }
134         else
135         {
136             switch(sta)
137             {
138             case after_left_tag:
139                 if(right_tag == *p)
140                 {
141                     sta     = start;
142                     section = empty_str; // empty section name.
143                 }
144                 else if(!isspace((unsigned char)*p))
145                 {
146                     sta = after_section_name;
147                     beg = p;
148                 }
149                 break;
150             case after_section_name:
151                 if(right_tag == *p)
152                 {
153                     sta     = start;
154                     section = string(beg, p - beg);
155                 }
156                 else if(isspace((unsigned char)*p))
157                 {
158                     sta     = after_section_name_ws;
159                     last_ws = p;
160                 }
161                 break;
162             case after_section_name_ws:
163                 if(right_tag == *p)
164                 {
165                     sta     = start;
166                     section = string(beg, last_ws - beg);
167                 }
168                 else if(!isspace((unsigned char)*p))
169                 {
170                     sta = after_section_name;
171                 }
172                 break;
173             case after_key_name:
174                 if(equal == *p)
175                 {
176                     sta = after_equal;
177                     key = string(beg, p - beg);
178                     beg = p + 1;
179                 }
180                 else if(isspace((unsigned char)*p))
181                 {
182                     sta     = after_key_name_ws;
183                     last_ws = p;
184                 }
185                 break;
186             case after_key_name_ws:
187                 if(equal == *p)
188                 {
189                     sta = after_equal;
190                     key = string(beg, last_ws - beg);
191                     beg = p + 1;
192                 }
193                 else if(!isspace((unsigned char)*p))
194                 {
195                     sta = after_key_name;
196                 }
197                 break;
198             case start:
199                 if(left_tag == *p)
200                 {
201                     sta = after_left_tag;
202                 }
203                 else if(equal == *p)
204                 {
205                     key = empty_str;  // an empty key.
206                     sta = after_equal;
207                     beg = p + 1;
208                 }
209                 else if(!isspace((unsigned char)*p))
210                 {
211                     sta = after_key_name;
212                     beg = p;
213                 }
214                 break;
215             }
216         }
217     }
218 
219     if(after_equal == sta)
220         m_map[section][key] = string(beg, p - beg);
221 
222     return true;
223 }
224 
225 bool IniDoc::save()
226 {
227     if(0==m_file_name.c_str() || 0==m_file_name[0])
228         return false;    // file name invalid
229 
230     ofstream file(m_file_name.c_str());
231     if(!file)
232         return false;
233 
234     for(SectionMap::iterator itApp=m_map.begin(); itApp!=m_map.end(); ++itApp)
235     {
236         file << left_tag << itApp->first << right_tag << endl;
237 
238         for(KeyMap::iterator itKey=itApp->second.begin(); itKey!=itApp->second.end(); ++itKey)
239             file << itKey->first << equal << itKey->second << endl;
240 
241         file << endl;
242     }
243     m_modified = false;
244 
245     return true;
246 }
247 
248 bool IniDoc::saveAs(const std::string& file_name)
249 {
250     string old_file_name = m_file_name;
251     m_file_name = file_name;
252 
253     if(save())
254         return true;
255 
256     m_file_name = old_file_name;
257     return false;
258 }
259 
260 long IniDoc::getInteger(const std::string& section, const std::string& key, long def_val)
261 {
262     istrstream(key_value(section, key)) >> def_val;
263     return def_val;
264 }
265 
266 float IniDoc::getFloat(const std::string& section, const std::string& key, float def_val)
267 {
268     istrstream(key_value(section, key)) >> def_val;
269     return def_val;
270 }
271 
272 long IniDoc::getStruct(const std::string& section, const std::string& key_, void* buffer, long size)
273 {
274     std::string key = key_value(section, key_);
275 
276     if (key.size() == 0)
277         return 0;
278 
279     const char* p        = key.c_str();
280     char*       dst      = (char*)buffer;
281     long        read_len = 0;
282     char        value;
283 
284     while(*p && read_len<size)
285     {
286         switch(*p)
287         {
288         case '0': case '1': case '2': case '3': case '4':
289         case '5': case '6': case '7': case '8': case '9':
290             value = *p - '0';
291             break;
292         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
293             value = *p - 'a' + 10;
294             break;
295         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
296             value = *p - 'A' + 10;
297             break;
298         default:
299             return read_len;
300         }
301 
302 
303         if(0 == (p - key.c_str())%2)
304             *(dst + read_len) = value << 4;
305         else
306             *(dst + read_len) = (*(dst + read_len) & 0xf0) + value;
307 
308 
309         if(0 == (++p - key.c_str())%2)
310             ++read_len;
311     }
312 
313     return read_len;
314 }
315 
316 long IniDoc::getString(const std::string& section, const std::string& key_, const std::string& def_val, std::string& dst_str)
317 {
318     std::string key = key_value(section, key_);
319     dst_str = key.length() ? key : def_val;
320     return dst_str.length();
321 }
322 
323 const std::string IniDoc::getString(const std::string& section, const std::string& key_, const std::string& def_val)
324 {
325     std::string key = key_value(section, key_);
326     if(key.length() == 0)
327         key = def_val;
328 
329     return key;
330 }
331 
332 void IniDoc::setInteger(const std::string& section, const std::string& key, long value)
333 {
334     char buffer[BUFFER_LEN + 1];
335     ostrstream ostr(buffer, BUFFER_LEN);
336     ostr << value;
337     buffer[ostr.pcount()] = 0;
338     setString(section, key, buffer);
339 }
340 
341 void IniDoc::setFloat(const std::string& section, const std::string& key, float value)
342 {
343     char buffer[BUFFER_LEN + 1];
344     ostrstream ostr(buffer, BUFFER_LEN);
345     ostr << value;
346     buffer[ostr.pcount()] = 0;
347     setString(section, key, buffer);
348 }
349 
350 inline char bin2hex(char bin)
351 {
352     return bin<10 ? bin+'0' : bin-10+'A';
353 }
354 
355 void IniDoc::setStruct(const std::string& section, const std::string& key, const void* buffer, long size)
356 {
357     char* dst = new char[size*2 + 1];
358     if(dst)
359     {
360         const char* src = (const char*)buffer;
361         long i=0;
362         for(i=0; i<size; ++i)
363         {
364             dst[i << 1]       = bin2hex((src[i] >> 4) & 0x0f );
365             dst[(i << 1) + 1] = bin2hex(src[i] & 0x0f);
366         }
367 
368         dst[i << 1] = 0;
369         setString(section, key, dst);
370 
371         delete[] dst;
372     }
373 }
374 
375 void IniDoc::setString(const std::string& section, const std::string& key, const std::string& value)
376 {
377     m_map[section][key] = value;
378     m_modified = true;
379 }
380 
381 bool IniDoc::delSection( const std::string& section )
382 {
383     SectionIterator itSection = m_map.find(section);
384     if(m_map.end() != itSection)
385     {
386         m_map.erase(itSection);
387         return true;
388     }
389     return false;
390 }
391 
392 bool IniDoc::delKey( const std::string& section, const std::string& key )
393 {
394     SectionIterator itSection = m_map.find(section);
395     if(m_map.end() != itSection)
396     {
397         KeyIterator itKey = itSection->second.find(key);
398         if(itKey != itSection->second.end())
399         {
400             itSection->second.erase(itKey);
401             return true;
402         }
403     }
404     return false;
405 }
406 
407 const IniDoc::KeyMap& IniDoc::getSection(const std::string& section) const
408 {
409     SectionMap::const_iterator itApp = m_map.find(section);
410     return m_map.end()==itApp ? ms_emptySection : itApp->second;
411 }
View Code

  

原文地址:https://www.cnblogs.com/kanite/p/9182640.html