在gitee上找到的一个很好用的ini文件解析器,纯C++代码,移植方便。
项目地址:https://gitee.com/sollyu/IniParser
稍微修改了下,去掉了Windows平台相关定义,改了下类名称。
头文件:
#ifndef INIPARSER_H
#define INIPARSER_H #include <map>
#include <string>
#include <string.h> class IniDoc
{
public:
struct IgnoreCaseLT
{
bool operator()(const std::string& lhs, const std::string& rhs) const
{
return strcasecmp(lhs.c_str(), rhs.c_str()) < ;
}
}; public:
typedef std::map<std::string, std::string, IgnoreCaseLT> KeyMap;
typedef std::map<std::string, KeyMap, IgnoreCaseLT> SectionMap;
typedef KeyMap::iterator KeyIterator;
typedef SectionMap::iterator SectionIterator; public:
// 默认的构造函数和析构函数
IniDoc();
~IniDoc(); // 构造函数 - 加载文件
IniDoc(const std::string& file_name); // 加载一个ini文件, 如果之前的文件被修改, 那么之前的ini文件将会被保持。
bool load(const std::string& file_name); // 从字符串中作为ini文件加载
bool loadString(const std::string& str); // 保持到加载ini位置
bool save(); // 另存为一个和加载路径不一样的文件中
bool saveAs(const std::string& file_name); // 返回ini是否被修改, 或者他最后一次操作是保存
bool isModified() const { return m_modified; } public: // high level member function. // 下面的成员函数是从Section中获得一些值
long getInteger(const std::string& section, const std::string& key, long def_val);
float getFloat(const std::string& section, const std::string& key, float def_val);
long getStruct(const std::string& section, const std::string& key, void* buffer, long size);
long getString(const std::string& section, const std::string& key, const std::string& def_val, std::string& buffer);
const std::string getString(const std::string& section, const std::string& key, const std::string& def_val); void setInteger(const std::string& section, const std::string& key, long value);
void setFloat(const std::string& section, const std::string& key, float value);
void setStruct(const std::string& section, const std::string& key, const void* buffer, long size);
void setString(const std::string& section, const std::string& key, const std::string& value); public:
bool delSection( const std::string& section );
bool delKey( const std::string& section, const std::string& key ); public:
// 返回一个section的map键值对
const KeyMap& getSection(const std::string& section) const; // 返回整个ini的Sections
const SectionMap& getIni() const { return m_map; } private:
void saveBeforeLoad();
const char* key_value(const std::string& section, const std::string& key); private:
// 禁止复制构造函数和赋值操作符。
IniDoc(const IniDoc& copy);
IniDoc& operator=(const IniDoc& rhs); private:
static const KeyMap ms_emptySection;
static const char left_tag ;
static const char right_tag ;
static const char equal ;
static const char cr ;
static const char new_line ;
static const char* empty_str ;
static const int BUFFER_LEN ; SectionMap m_map;
std::string m_file_name;
bool m_modified;
}; #endif // INIPARSER_H
源文件:
#include "IniDoc.h" #include <fstream>
#include <strstream> using namespace std; const char IniDoc::left_tag = '[' ;
const char IniDoc::right_tag = ']' ;
const char IniDoc::equal = '=' ;
const char IniDoc::cr = '\r';
const char IniDoc::new_line = '\n';
const char* IniDoc::empty_str = "" ;
const int IniDoc::BUFFER_LEN = ; const IniDoc::KeyMap IniDoc::ms_emptySection; IniDoc::IniDoc() : m_modified(false)
{ } IniDoc::IniDoc(const std::string& file_name) : m_modified(false)
{
load(file_name);
} IniDoc::~IniDoc()
{
if(m_modified)
save();
} void IniDoc::saveBeforeLoad()
{
if(m_modified)
save(); m_file_name.resize(); m_map.clear(); m_modified = false;
} const char* IniDoc::key_value(const std::string& section, const std::string& key)
{
SectionIterator itSection = m_map.find(section);
if(m_map.end() != itSection)
{
KeyIterator itKey = itSection->second.find(key);
if(itKey != itSection->second.end())
return itKey->second.c_str();
} return ;
} bool IniDoc::load(const std::string& file_name)
{
saveBeforeLoad(); ifstream file(file_name);
if(!file)
return false; file.seekg(, ios::end);
long len = file.tellg();
if(len < )
return false; char* buffer = new char[len + ];
if( == buffer)
return false; file.seekg(, ios::beg);
file.read(buffer, len); buffer[len = file.gcount()] = ; loadString(buffer);
m_file_name = file_name; delete[] buffer; return true;
} bool IniDoc::loadString(const std::string& str)
{
saveBeforeLoad(); unsigned long length = str.size(); if (str.size() == )
return false; enum status
{
after_left_tag,
after_section_name,
after_section_name_ws,
after_key_name,
after_key_name_ws,
after_equal,
start
}; string section; // 当前 section.
string key; // 当前 key.
status sta = start; // 解析状态.
const char* p = str.c_str(); // 当前解析字符串的位置.
const char* beg = p; // 当前元素的开始.
const char* last_ws = p; // 最后一个空格字符. for(; length; ++p, --length)
{
if(new_line == *p)
{
if(after_equal == sta)
{
if(cr == *(p - ))
--p; m_map[section][key] = string(beg, p - beg); if(cr == *p)
++p;
}
sta = start;
}
else
{
switch(sta)
{
case after_left_tag:
if(right_tag == *p)
{
sta = start;
section = empty_str; // empty section name.
}
else if(!isspace((unsigned char)*p))
{
sta = after_section_name;
beg = p;
}
break;
case after_section_name:
if(right_tag == *p)
{
sta = start;
section = string(beg, p - beg);
}
else if(isspace((unsigned char)*p))
{
sta = after_section_name_ws;
last_ws = p;
}
break;
case after_section_name_ws:
if(right_tag == *p)
{
sta = start;
section = string(beg, last_ws - beg);
}
else if(!isspace((unsigned char)*p))
{
sta = after_section_name;
}
break;
case after_key_name:
if(equal == *p)
{
sta = after_equal;
key = string(beg, p - beg);
beg = p + ;
}
else if(isspace((unsigned char)*p))
{
sta = after_key_name_ws;
last_ws = p;
}
break;
case after_key_name_ws:
if(equal == *p)
{
sta = after_equal;
key = string(beg, last_ws - beg);
beg = p + ;
}
else if(!isspace((unsigned char)*p))
{
sta = after_key_name;
}
break;
case start:
if(left_tag == *p)
{
sta = after_left_tag;
}
else if(equal == *p)
{
key = empty_str; // an empty key.
sta = after_equal;
beg = p + ;
}
else if(!isspace((unsigned char)*p))
{
sta = after_key_name;
beg = p;
}
break;
}
}
} if(after_equal == sta)
m_map[section][key] = string(beg, p - beg); return true;
} bool IniDoc::save()
{
if(==m_file_name.c_str() || ==m_file_name[])
return false; // file name invalid ofstream file(m_file_name.c_str());
if(!file)
return false; for(SectionMap::iterator itApp=m_map.begin(); itApp!=m_map.end(); ++itApp)
{
file << left_tag << itApp->first << right_tag << endl; for(KeyMap::iterator itKey=itApp->second.begin(); itKey!=itApp->second.end(); ++itKey)
file << itKey->first << equal << itKey->second << endl; file << endl;
}
m_modified = false; return true;
} bool IniDoc::saveAs(const std::string& file_name)
{
string old_file_name = m_file_name;
m_file_name = file_name; if(save())
return true; m_file_name = old_file_name;
return false;
} long IniDoc::getInteger(const std::string& section, const std::string& key, long def_val)
{
istrstream(key_value(section, key)) >> def_val;
return def_val;
} float IniDoc::getFloat(const std::string& section, const std::string& key, float def_val)
{
istrstream(key_value(section, key)) >> def_val;
return def_val;
} long IniDoc::getStruct(const std::string& section, const std::string& key_, void* buffer, long size)
{
std::string key = key_value(section, key_); if (key.size() == )
return ; const char* p = key.c_str();
char* dst = (char*)buffer;
long read_len = ;
char value; while(*p && read_len<size)
{
switch(*p)
{
case '': case '': case '': case '': case '':
case '': case '': case '': case '': case '':
value = *p - '';
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
value = *p - 'a' + ;
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
value = *p - 'A' + ;
break;
default:
return read_len;
} if( == (p - key.c_str())%)
*(dst + read_len) = value << ;
else
*(dst + read_len) = (*(dst + read_len) & 0xf0) + value; if( == (++p - key.c_str())%)
++read_len;
} return read_len;
} long IniDoc::getString(const std::string& section, const std::string& key_, const std::string& def_val, std::string& dst_str)
{
std::string key = key_value(section, key_);
dst_str = key.length() ? key : def_val;
return dst_str.length();
} const std::string IniDoc::getString(const std::string& section, const std::string& key_, const std::string& def_val)
{
std::string key = key_value(section, key_);
if(key.length() == )
key = def_val; return key;
} void IniDoc::setInteger(const std::string& section, const std::string& key, long value)
{
char buffer[BUFFER_LEN + ];
ostrstream ostr(buffer, BUFFER_LEN);
ostr << value;
buffer[ostr.pcount()] = ;
setString(section, key, buffer);
} void IniDoc::setFloat(const std::string& section, const std::string& key, float value)
{
char buffer[BUFFER_LEN + ];
ostrstream ostr(buffer, BUFFER_LEN);
ostr << value;
buffer[ostr.pcount()] = ;
setString(section, key, buffer);
} inline char bin2hex(char bin)
{
return bin< ? bin+'' : bin-+'A';
} void IniDoc::setStruct(const std::string& section, const std::string& key, const void* buffer, long size)
{
char* dst = new char[size* + ];
if(dst)
{
const char* src = (const char*)buffer;
long i=;
for(i=; i<size; ++i)
{
dst[i << ] = bin2hex((src[i] >> ) & 0x0f );
dst[(i << ) + ] = bin2hex(src[i] & 0x0f);
} dst[i << ] = ;
setString(section, key, dst); delete[] dst;
}
} void IniDoc::setString(const std::string& section, const std::string& key, const std::string& value)
{
m_map[section][key] = value;
m_modified = true;
} bool IniDoc::delSection( const std::string& section )
{
SectionIterator itSection = m_map.find(section);
if(m_map.end() != itSection)
{
m_map.erase(itSection);
return true;
}
return false;
} bool IniDoc::delKey( const std::string& section, const std::string& key )
{
SectionIterator itSection = m_map.find(section);
if(m_map.end() != itSection)
{
KeyIterator itKey = itSection->second.find(key);
if(itKey != itSection->second.end())
{
itSection->second.erase(itKey);
return true;
}
}
return false;
} const IniDoc::KeyMap& IniDoc::getSection(const std::string& section) const
{
SectionMap::const_iterator itApp = m_map.find(section);
return m_map.end()==itApp ? ms_emptySection : itApp->second;
}