一个基于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 §ion, 28 const std::string &key); 29 int GetPrivateProfileInt(const std::string §ion, const std::string &key); 30 bool SetPrivateProfileString(const std::string §ion, 31 const std::string &key, const std::string &value); 32 bool SetPrivateProfileInt(const std::string §ion, 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 §ion, 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 §ion, 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 §ion, 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 §ion, 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 }