一个基于STL的ini文件解析类,测试通过

windows平台自带ini解析的接口,但是如果要跨平台的话,就要自己来实现一个,网上找了下,发现在跨平台不够理想

遂自己修改了一个出来。支持解析utf-8, unicode big endian, unicode little endian格式文件,请勿使用windows的

ansi保存的文件测试。文件操作时,空格和注释会被丢弃,可能下次有空考虑加上来吧。

代码如下:

 1 //head file
 2 
 3 #ifndef IniParser_
 4 #define IniParser_
 5 
 6 #include <vector>
 7 #include <string>
 8 #include <map>
 9 
10 class IniParser
11 {
12 public:
13     IniParser();
14     ~IniParser();
15 protected:
16     typedef unsigned char Byte;
17     typedef std::map<std::string, std::string> KeyVector;
18     typedef std::map<std::string, KeyVector> SectionVector;
19     enum FileEncode {
20         Unknow_Encode,
21         Unicode_BE,
22         Unicode_LE,
23         Utf8_Encode,
24     };
25 public:
26     bool Open(const std::string &szIni);
27     std::string GetPrivateProfileString(const std::string &section, 
28             const std::string &key);
29     int GetPrivateProfileInt(const std::string &section, const std::string &key);
30     bool SetPrivateProfileString(const std::string &section, 
31             const std::string &key, const std::string &value);
32     bool SetPrivateProfileInt(const std::string &section, 
33             const std::string &key, int value);
34     bool Flush(void);
35 protected:
36     bool Parser(const std::string &strbuf);
37     std::string GetLine(void);
38     bool IsComment(const std::string &line);
39     bool IsSection(const std::string &line);
40     std::string GetKeyValueFromLine(const std::string &line);
41     std::string GetKeyNameFromLine(const std::string &line);
42     std::string GetSectionNameFromLine(const std::string &line);
43     std::string RemoveSpace(const std::string &strbuf);
44     void ResetOffset();
45     bool IsOffsetEnd();
46 private:
47     FileEncode m_encode;
48     std::string m_strIni;
49     std::string m_fileBuff;
50     std::string::size_type m_offset;
51     SectionVector m_mpValue;
52 };
53 
54 #endif
  1 // source file
  2 
  3 #include <fstream>
  4 #include <iostream>
  5 #include <algorithm>
  6 #include <deque>
  7 #include <sstream>
  8 #include "IniParser.h"
  9 
 10 // Convert Unicode big endian to Unicode little endian
 11 static unsigned Ucs2BeToUcs2Le(unsigned short *ucs2bige, unsigned int size)
 12 {
 13     printf("@ %s %d line\n", __FUNCTION__, __LINE__);
 14 
 15     if (!ucs2bige) {
 16         return 0;
 17     }
 18     
 19     unsigned int length = size;
 20     unsigned short *tmp = ucs2bige;
 21     
 22     while (*tmp && length) {
 23         
 24         length--;
 25         unsigned char val_high = *tmp >> 8;
 26         unsigned char val_low = (unsigned char)*tmp;
 27         
 28         *tmp = val_low << 8 | val_high;
 29         
 30         tmp++;
 31     }
 32     
 33     return size - length;
 34 }
 35 
 36 // Convert Unicode little endian to Unicode big endian
 37 static unsigned Ucs2LeToUcs2Be(unsigned short *ucs2le, unsigned int size)
 38 {
 39     if (!ucs2le) {
 40         return 0;
 41     }
 42     
 43     printf("@ %s %d line\n", __FUNCTION__, __LINE__);
 44 
 45     unsigned int length = size;
 46     unsigned short *tmp = ucs2le;
 47     
 48     while (*tmp && length) {
 49         
 50         length--;
 51         unsigned char val_high = *tmp >> 8;
 52         unsigned char val_low = (unsigned char)*tmp;
 53         
 54         *tmp = val_low << 8 | val_high;
 55         
 56         tmp++;
 57     }
 58     
 59     return size - length;
 60 }
 61 
 62 // Convert Ucs-2 to Utf-8
 63 static unsigned int Ucs2ToUtf8(unsigned short *ucs2, unsigned int ucs2_size, 
 64                         unsigned char *utf8, unsigned int utf8_size)
 65 {
 66     unsigned int length = 0;
 67     
 68     if (!ucs2) {
 69         return 0;
 70     }
 71     
 72     unsigned short *inbuf = ucs2;
 73     unsigned char *outbuf = utf8;
 74     
 75     if (*inbuf == 0xFFFE) {
 76         Ucs2BeToUcs2Le(inbuf, ucs2_size);
 77     }
 78     
 79     if (!utf8) {
 80         unsigned int insize = ucs2_size;
 81         
 82         while (*inbuf && insize) {
 83             insize--;
 84             
 85             if (0x0080 > *inbuf) {
 86                 length++;
 87             } else if (0x0800 > *inbuf) {
 88                 length += 2;                
 89             } else {
 90                 length += 3;
 91             }
 92             
 93             inbuf++;
 94         }
 95         return length;
 96         
 97     } else {        
 98         unsigned int insize = ucs2_size;
 99         
100         while (*inbuf && insize && length < utf8_size) {            
101             insize--;
102             
103             if (*inbuf == 0xFFFE) {
104                 inbuf++;
105                 continue;
106             }
107             
108             if (0x0080 > *inbuf) {
109                 /* 1 byte UTF-8 Character.*/
110                 *outbuf++ = (unsigned char)(*inbuf);
111                 length++;
112             } else if (0x0800 > *inbuf) {
113                 /*2 bytes UTF-8 Character.*/
114                 *outbuf++ = 0xc0 | ((unsigned char)(*inbuf >> 6));
115                 *outbuf++ = 0x80 | ((unsigned char)(*inbuf & 0x3F));
116                 length += 2;
117                 
118             } else {
119                 /* 3 bytes UTF-8 Character .*/
120                 *outbuf++ = 0xE0 | ((unsigned char)(*inbuf >> 12));
121                 *outbuf++ = 0x80 | ((unsigned char)((*inbuf >> 6) & 0x3F));
122                 *outbuf++ = 0x80 | ((unsigned char)(*inbuf & 0x3F));
123                 length += 3; 
124             }
125             
126             inbuf++;
127         }
128         
129         return length;
130     }
131 }
132 
133 //// Convert Ucs-2 to Utf-8
134 static unsigned int Utf8ToUcs2(unsigned char *utf8, unsigned int utf8_size, 
135                         unsigned short *ucs2, unsigned int ucs2_size)
136 {
137     int length = 0;
138     unsigned int insize = utf8_size;
139     unsigned char *inbuf = utf8;
140     
141     if(!utf8)
142         return 0;
143     
144     if(!ucs2) {
145         while(*inbuf && insize) {
146             unsigned char c = *inbuf;
147             if((c & 0x80) == 0) {
148                 length += 1;
149                 insize -= 1;
150                 inbuf++;
151             }
152             else if((c & 0xE0) == 0xC0) {
153                 length += 1;
154                 insize -= 2;
155                 inbuf += 2;
156             } else if((c & 0xF0) == 0xE0) {
157                 length += 1;
158                 insize -= 3;
159                 inbuf += 3;
160             }
161         }
162         return length;
163         
164     } else {
165         unsigned short *outbuf = ucs2;
166         unsigned int outsize = ucs2_size;
167         
168         while(*inbuf && insize && length < outsize) {
169             unsigned char c = *inbuf;
170             if((c & 0x80) == 0) {
171                 *outbuf++ = c;
172                 inbuf++;
173                 length++;
174                 insize--;
175             } else if((c & 0xE0) == 0xC0) {
176                 unsigned short val;
177                 
178                 val = (c & 0x3F) << 6;
179                 inbuf++;
180                 c = *inbuf;
181                 val |= (c & 0x3F);
182                 inbuf++;
183                 
184                 length++;
185                 insize -= 2;
186                 
187                 *outbuf++ = val;
188             } else if((c & 0xF0) == 0xE0) {
189                 unsigned short val;
190                 
191                 val = (c & 0x1F) << 12;
192                 inbuf++;
193                 c = *inbuf;
194                 val |= (c & 0x3F) << 6;
195                 inbuf++;
196                 c = *inbuf;
197                 val |= (c & 0x3F);
198                 inbuf++;
199                 
200                 insize -= 3;
201                 length++;
202                 
203                 *outbuf++ = val;
204             }
205         }
206         return length;
207     }
208     return 0;
209 }
210 
211 IniParser::IniParser()
212 : m_strIni("")
213 , m_fileBuff("")
214 , m_offset(0)
215 , m_encode(Unknow_Encode)
216 {
217 }
218 
219 IniParser::~IniParser()
220 {
221 }
222 
223 bool IniParser::Open(const std::string &szIni)
224 {
225     m_strIni = szIni;
226     
227     if (m_strIni.empty()) {
228         return false;
229     }
230     
231     std::ifstream infile(m_strIni.c_str());
232     if (!infile) {
233         return false;
234     }
235     
236     infile.seekg(0, std::ios::end);
237     unsigned length = infile.tellg();
238     infile.seekg(0, std::ios::beg);
239     
240     if (length < 3) {
241         return false;
242     }
243     
244     unsigned int buff_size = length / sizeof(unsigned short) + 1;
245     unsigned short *buff = new unsigned short[buff_size];
246     infile.read((char *)buff, length);
247     buff[buff_size] = '\0';
248     
249     unsigned char *utf8 = NULL;
250     
251     // support unicode & utf-8 encode
252     if (*buff == 0xFEFF || *buff == 0xFFFE) {
253 
254         if (*buff == 0xFEFF) {
255             m_encode = Unicode_LE;
256         } else {
257             m_encode = Unicode_BE;
258         }
259 
260         unsigned int utf8_size = Ucs2ToUtf8(buff, buff_size, utf8, 0);
261         utf8 = new unsigned char [utf8_size + 1];
262         Ucs2ToUtf8(buff, buff_size, utf8, utf8_size);
263 
264         delete [] buff;
265 
266     } else if (*(unsigned char *)buff == 0xEF && *((unsigned char *)buff + 1) == 0xBB 
267                && *((unsigned char *)buff + 2) == 0xBF) {
268 
269         utf8 = (unsigned char *)buff;
270         m_encode = Utf8_Encode;
271 
272     } else {
273 
274         delete [] buff;
275         return false;
276     }
277     
278     m_fileBuff = (char *)utf8;
279     
280     delete [] utf8;
281     infile.close();
282     
283     return Parser(m_fileBuff);    
284 }
285 
286 bool IniParser::IsSection(const std::string &line)
287 {
288     std::string::size_type stLeft = line.find("[");
289     std::string::size_type stRight = line.find("]");
290     
291     if (!line.empty() && stLeft != std::string::npos && 
292             stRight != std::string::npos && stRight > stLeft) {
293         return true;
294     }
295     
296     return false;
297 }
298 
299 std::string IniParser::GetSectionNameFromLine(const std::string &line)
300 {
301     std::string::size_type stLeft = line.find("[");
302     std::string::size_type stRight = line.find("]");
303     
304     if (!line.empty() && stLeft != std::string::npos && 
305             stRight != std::string::npos && stRight > stLeft) {
306         std::string section(line, stLeft + 1, stRight - stLeft - 1);
307         return RemoveSpace(section);
308     }
309     
310     return std::string();
311 }
312 
313 std::string IniParser::RemoveSpace(const std::string &strbuf)
314 {
315     std::string stReturn = strbuf;
316 
317     if(strbuf.empty())
318         return stReturn;
319 
320     std::string::size_type stLeft = 0;
321     std::string::size_type stRight = 0;
322     stLeft = strbuf.find_first_not_of(' ');
323     stRight = strbuf.find_last_not_of(' ');
324 
325     if(stLeft == std::string::npos || stRight == std::string::npos)
326         return stReturn;
327 
328     std::string st(strbuf, stLeft, stRight - stLeft + 1);
329     return st;
330 }
331 
332 std::string IniParser::GetKeyNameFromLine(const std::string &line)
333 {
334     std::string::size_type stpos = line.find("=");
335     if (stpos == 0) {
336         return std::string();
337     }
338     
339     std::string strbuf;
340     if (stpos == std::string::npos) {
341         strbuf = line;
342     } else {
343         strbuf.clear();
344         strbuf.insert(0, line, 0, stpos);
345     }
346     
347     return RemoveSpace(strbuf);
348 }
349 
350 std::string IniParser::GetKeyValueFromLine(const std::string &line)
351 {
352     std::string::size_type stpos = line.find("=");
353     if (stpos == std::string::npos) {
354         return std::string();
355     }
356     
357     std::string strbuf;
358     strbuf.clear();
359     strbuf.insert(0, line, stpos + 1, line.size());
360     
361     return RemoveSpace(strbuf);
362 }
363 
364 bool IniParser::Parser(const std::string &strbuf)
365 {
366     ResetOffset();
367     
368     KeyVector mpKey;
369     std::string section;
370     
371     while (true) {
372         std::string line = GetLine();
373         if (line.empty() || IsComment(line)) {
374             if (IsOffsetEnd()) {
375                 break;
376             } else {
377                 continue;
378             }
379         }
380         
381         if (IsSection(line)) {
382             if (section.empty()) {
383                 section = GetSectionNameFromLine(line);
384                 continue;
385             } 
386             
387             m_mpValue.insert(std::make_pair(section, mpKey));
388             section = GetSectionNameFromLine(line);
389             mpKey.clear();
390         } else {
391             if (section.empty()) {
392                 continue;
393             }
394             std::string strKey = GetKeyNameFromLine(line);
395             if (!strKey.empty()) {
396                 mpKey.insert(std::make_pair(strKey, GetKeyValueFromLine(line)));
397             }
398         }
399     }
400     
401     if (!section.empty()) {
402         m_mpValue.insert(std::make_pair(section, mpKey));
403     }
404 
405     return true;
406 }
407 
408 std::string IniParser::GetLine()
409 {
410     std::string line;
411     if (m_offset >= m_fileBuff.size()) {
412         return std::string();
413     }
414     
415     std::string::size_type stPos = m_fileBuff.find("\r\n", m_offset);
416     if (stPos == std::string::npos) {
417         line.insert(0, m_fileBuff, m_offset, m_fileBuff.size() - m_offset + 1);
418         m_offset = m_fileBuff.size() + 1;
419     } else {
420         line.insert(0, m_fileBuff, m_offset, stPos - m_offset);
421         m_offset = stPos + 2;
422     }
423     
424     return line;
425 }
426 
427 void IniParser::ResetOffset()
428 {
429     m_offset = 0;
430 }
431 
432 bool IniParser::IsOffsetEnd()
433 {
434     if (m_offset >= m_fileBuff.size()) {
435         return true;
436     }
437     return false;
438 }
439 
440 bool IniParser::IsComment(const std::string &line)
441 {
442     if (line.empty() || line[0] == ';') {
443         return true;
444     }
445     
446     return false;
447 }
448 
449 /*
450 std::string IniParser::ConvertToLowercase(const std::string &strBuf)
451 {
452     std::string str = strBuf;
453     std::transform(str.begin(), str.end(), str.begin(), tolower);
454     return str;
455 }
456 */
457 
458 std::string IniParser::GetPrivateProfileString(const std::string &section, 
459         const std::string &key)
460 {
461     if (m_mpValue.empty() || section.empty() || key.empty()) {
462         return std::string();
463     }
464     
465     for (SectionVector::iterator iter_section = m_mpValue.begin(); 
466             iter_section != m_mpValue.end(); iter_section++) {
467         if (section == iter_section->first) {
468             for (KeyVector::iterator iter_key = iter_section->second.begin(); 
469                  iter_key != iter_section->second.end(); iter_key++) {
470                 if (key == iter_key->first) {
471                     return iter_key->second;
472                 }
473             }
474         }
475     }
476 
477     return std::string();
478 }
479 
480 bool IniParser::SetPrivateProfileString(const std::string &section, 
481         const std::string &key, const std::string &value)
482 {
483     for (SectionVector::iterator iter_section = m_mpValue.begin(); 
484             iter_section != m_mpValue.end(); iter_section++) {
485         if (section == iter_section->first) {
486             //find exist section
487             for (KeyVector::iterator iter_key = iter_section->second.begin(); 
488                     iter_key != iter_section->second.end(); iter_key++) {
489                 if (key == iter_key->first) {
490                     // find exist key
491                     iter_key->second = value;
492                     return true;
493                 }
494             }
495             
496             // add new key
497             std::cout << "new key " << key << " in" << std::endl;
498             iter_section->second.insert(std::make_pair(key, value));
499             return true;
500         }
501     }
502     
503     //add new section
504     KeyVector mpKey;
505     mpKey.insert(std::make_pair(key, value));
506     m_mpValue.insert(std::make_pair(section, mpKey));
507     return true;
508 }
509 
510 bool IniParser::SetPrivateProfileInt(const std::string &section, 
511         const std::string &key, int value)
512 {
513     std::stringstream ss;
514     ss << value;
515     
516     std::string str_value;
517     ss >> str_value;
518     
519     return SetPrivateProfileString(section, key, str_value);
520 }
521 
522 int IniParser::GetPrivateProfileInt(const std::string &section, 
523         const std::string &key)
524 {
525     return atoi(GetPrivateProfileString(section, key).c_str());
526 }
527 
528 bool IniParser::Flush()
529 {
530     if (m_encode == Unknow_Encode) {
531         return false;
532     }
533     
534     std::ofstream outfile(m_strIni.c_str(), 
535             std::ofstream::binary | std::ofstream::trunc);
536     if (!outfile) {
537         std::cout << "Open file " << m_strIni << " failed." << std::endl;
538         return false;
539     }
540     
541     m_fileBuff.clear();
542     for (SectionVector::iterator iter_section = m_mpValue.begin(); 
543             iter_section != m_mpValue.end(); iter_section++) {
544         m_fileBuff += "[";
545         m_fileBuff += iter_section->first;
546         m_fileBuff += "]\r\n";
547         
548         for (KeyVector::iterator iter_key = iter_section->second.begin(); 
549                 iter_key != iter_section->second.end(); iter_key++) {
550             m_fileBuff += iter_key->first;
551             m_fileBuff += "=";
552             m_fileBuff += iter_key->second;
553             m_fileBuff += "\r\n";
554         }
555         m_fileBuff += "\r\n";
556     }
557     
558     unsigned char file_head[3];
559     
560     if (m_encode == Utf8_Encode) {
561         file_head[0] = 0xEF; file_head[1] = 0xBB; file_head[2] = 0xBF;
562         
563         outfile.write((char *)file_head, 3);
564         outfile.write(m_fileBuff.c_str(), m_fileBuff.size());
565         
566     } else if (m_encode == Unicode_BE) {
567         unsigned short *ucs2buf = NULL;
568         unsigned int ucs2_size = Utf8ToUcs2((unsigned char *)m_fileBuff.c_str(), 
569                 m_fileBuff.size(), ucs2buf, 0);
570         ucs2buf = new unsigned short [ucs2_size];
571         Utf8ToUcs2((unsigned char *)m_fileBuff.c_str(), m_fileBuff.size(), 
572                 ucs2buf, ucs2_size);
573         Ucs2LeToUcs2Be(ucs2buf, ucs2_size);
574         
575         file_head[0] = 0xFE; file_head[1] = 0xFF;
576         
577         outfile.write((char *)file_head, 2);
578         outfile.write((char *)ucs2buf, ucs2_size * sizeof(unsigned short));
579         
580         delete ucs2buf;
581     } else if (m_encode == Unicode_LE) {
582         unsigned short *ucs2buf = NULL;
583         unsigned int ucs2_size = Utf8ToUcs2((unsigned char *)m_fileBuff.c_str(), 
584                 m_fileBuff.size(), ucs2buf, 0);
585         ucs2buf = new unsigned short [ucs2_size];
586         Utf8ToUcs2((unsigned char *)m_fileBuff.c_str(), m_fileBuff.size(), 
587                 ucs2buf, ucs2_size);
588                 
589         file_head[0] = 0xFF; file_head[1] = 0xFE;
590         
591         outfile.write((char *)file_head, 2);
592         outfile.write((char *)ucs2buf, ucs2_size * sizeof(unsigned short));
593         
594         delete ucs2buf;
595     }
596     
597     outfile.close();
598     return true;
599 }
posted @ 2012-07-04 17:15  Jojodru  阅读(843)  评论(0编辑  收藏  举报