| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390 |
- #include "iniparser.h"
- #include <sstream>
- #include "hdef.h"
- #include "herr.h"
- #include "hstring.h"
- #include "hfile.h"
- #include "hbase.h"
- using namespace hv;
- /**********************************
- # div
- [section]
- key = value # span
- # div
- ***********************************/
- class IniNode {
- public:
- enum Type {
- INI_NODE_TYPE_UNKNOWN,
- INI_NODE_TYPE_ROOT,
- INI_NODE_TYPE_SECTION,
- INI_NODE_TYPE_KEY_VALUE,
- INI_NODE_TYPE_DIV,
- INI_NODE_TYPE_SPAN,
- } type;
- std::string label; // section|key|comment
- std::string value;
- std::list<IniNode*> children;
- virtual ~IniNode() {
- for (auto pNode : children) {
- if (pNode) {
- delete pNode;
- }
- }
- children.clear();
- }
- void Add(IniNode* pNode) {
- children.push_back(pNode);
- }
- void Del(IniNode* pNode) {
- for (auto iter = children.begin(); iter != children.end(); ++iter) {
- if ((*iter) == pNode) {
- delete (*iter);
- children.erase(iter);
- return;
- }
- }
- }
- IniNode* Get(const std::string& label, Type type = INI_NODE_TYPE_KEY_VALUE) {
- for (auto pNode : children) {
- if (pNode->type == type && pNode->label == label) {
- return pNode;
- }
- }
- return NULL;
- }
- };
- class IniSection : public IniNode {
- public:
- IniSection() : IniNode(), section(label) {
- type = INI_NODE_TYPE_SECTION;
- }
- std::string §ion;
- };
- class IniKeyValue : public IniNode {
- public:
- IniKeyValue() : IniNode(), key(label) {
- type = INI_NODE_TYPE_KEY_VALUE;
- }
- std::string &key;
- };
- class IniComment : public IniNode {
- public:
- IniComment() : IniNode(), comment(label) {
- }
- std::string &comment;
- };
- IniParser::IniParser() {
- _comment = DEFAULT_INI_COMMENT;
- _delim = DEFAULT_INI_DELIM;
- root_ = NULL;
- }
- IniParser::~IniParser() {
- Unload();
- }
- int IniParser::Unload() {
- SAFE_DELETE(root_);
- return 0;
- }
- int IniParser::Reload() {
- return LoadFromFile(_filepath.c_str());
- }
- int IniParser::LoadFromFile(const char* filepath) {
- _filepath = filepath;
- HFile file;
- if (file.open(filepath, "r") != 0) {
- return ERR_OPEN_FILE;
- }
- std::string str;
- file.readall(str);
- const char* c_str = str.c_str();
- unsigned char utf8_bom[3] = { 0xEF, 0xBB, 0xBF };
- if (str.size() >= 3 && memcmp(c_str, utf8_bom, 3) == 0) {
- c_str += 3;
- }
- return LoadFromMem(c_str);
- }
- int IniParser::LoadFromMem(const char* data) {
- Unload();
- root_ = new IniNode;
- root_->type = IniNode::INI_NODE_TYPE_ROOT;
- std::stringstream ss;
- ss << data;
- std::string strLine;
- int line = 0;
- std::string::size_type pos;
- std::string content, comment, strDiv;
- IniNode* pScopeNode = root_;
- IniNode* pNewNode = NULL;
- while (std::getline(ss, strLine)) {
- ++line;
- content = ltrim(strLine);
- if (content.length() == 0) {
- // blank line
- strDiv += '\n';
- continue;
- }
- // trim_comment
- comment = "";
- pos = content.find_first_of(_comment);
- if (pos != std::string::npos) {
- comment = content.substr(pos);
- content = content.substr(0, pos);
- }
- content = rtrim(content);
- if (content.length() == 0) {
- strDiv += strLine;
- strDiv += '\n';
- continue;
- } else if (strDiv.length() != 0) {
- IniNode* pNode = new IniNode;
- pNode->type = IniNode::INI_NODE_TYPE_DIV;
- pNode->label = strDiv;
- pScopeNode->Add(pNode);
- strDiv = "";
- }
- if (content[0] == '[') {
- if (content[content.length()-1] == ']') {
- // section
- content = trim(content.substr(1, content.length()-2));
- pNewNode = new IniNode;
- pNewNode->type = IniNode::INI_NODE_TYPE_SECTION;
- pNewNode->label = content;
- root_->Add(pNewNode);
- pScopeNode = pNewNode;
- } else {
- // hlogw("format error, line:%d", line);
- continue; // ignore
- }
- } else {
- pos = content.find_first_of(_delim);
- if (pos != std::string::npos) {
- // key-value
- pNewNode = new IniNode;
- pNewNode->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
- pNewNode->label = trim(content.substr(0, pos));
- pNewNode->value = trim(content.substr(pos+_delim.length()));
- pScopeNode->Add(pNewNode);
- } else {
- // hlogw("format error, line:%d", line);
- continue; // ignore
- }
- }
- if (comment.length() != 0) {
- // tail_comment
- IniNode* pNode = new IniNode;
- pNode->type = IniNode::INI_NODE_TYPE_SPAN;
- pNode->label = comment;
- pNewNode->Add(pNode);
- comment = "";
- }
- }
- // file end comment
- if (strDiv.length() != 0) {
- IniNode* pNode = new IniNode;
- pNode->type = IniNode::INI_NODE_TYPE_DIV;
- pNode->label = strDiv;
- root_->Add(pNode);
- }
- return 0;
- }
- void IniParser::DumpString(IniNode* pNode, std::string& str) {
- if (pNode == NULL) return;
- if (pNode->type != IniNode::INI_NODE_TYPE_SPAN) {
- if (str.length() > 0 && str[str.length()-1] != '\n') {
- str += '\n';
- }
- }
- switch (pNode->type) {
- case IniNode::INI_NODE_TYPE_SECTION: {
- str += '[';
- str += pNode->label;
- str += ']';
- }
- break;
- case IniNode::INI_NODE_TYPE_KEY_VALUE: {
- str += asprintf("%s %s %s", pNode->label.c_str(), _delim.c_str(), pNode->value.c_str());
- }
- break;
- case IniNode::INI_NODE_TYPE_DIV: {
- str += pNode->label;
- }
- break;
- case IniNode::INI_NODE_TYPE_SPAN: {
- str += '\t';
- str += pNode->label;
- }
- break;
- default:
- break;
- }
- for (auto p : pNode->children) {
- DumpString(p, str);
- }
- }
- std::string IniParser::DumpString() {
- std::string str;
- DumpString(root_, str);
- return str;
- }
- int IniParser::Save() {
- return SaveAs(_filepath.c_str());
- }
- int IniParser::SaveAs(const char* filepath) {
- std::string str = DumpString();
- if (str.length() == 0) {
- return 0;
- }
- HFile file;
- if (file.open(filepath, "w") != 0) {
- return ERR_SAVE_FILE;
- }
- file.write(str.c_str(), str.length());
- return 0;
- }
- std::list<std::string> IniParser::GetSections() {
- std::list<std::string> ret;
- if (root_ == NULL) return std::move(ret);
- for (auto pNode : root_->children) {
- if (pNode->type == IniNode::INI_NODE_TYPE_SECTION) {
- ret.push_back(pNode->label);
- }
- }
- return std::move(ret);
- }
- std::list<std::string> IniParser::GetKeys(const std::string& section) {
- std::list<std::string> ret;
- if (root_ == NULL) return std::move(ret);
- IniNode* pSection = root_;
- if (section.length() != 0) {
- pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
- if (pSection == NULL) return std::move(ret);
- }
- for (auto pNode : pSection->children) {
- if (pNode->type == IniNode::INI_NODE_TYPE_KEY_VALUE) {
- ret.push_back(pNode->label);
- }
- }
- return std::move(ret);
- }
- std::string IniParser::GetValue(const std::string& key, const std::string& section) {
- if (root_ == NULL) return "";
- IniNode* pSection = root_;
- if (section.length() != 0) {
- pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
- if (pSection == NULL) return "";
- }
- IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
- if (pKV == NULL) return "";
- return pKV->value;
- }
- void IniParser::SetValue(const std::string& key, const std::string& value, const std::string& section) {
- if (root_ == NULL) {
- root_ = new IniNode;
- }
- IniNode* pSection = root_;
- if (section.length() != 0) {
- pSection = root_->Get(section, IniNode::INI_NODE_TYPE_SECTION);
- if (pSection == NULL) {
- pSection = new IniNode;
- pSection->type = IniNode::INI_NODE_TYPE_SECTION;
- pSection->label = section;
- root_->Add(pSection);
- }
- }
- IniNode* pKV = pSection->Get(key, IniNode::INI_NODE_TYPE_KEY_VALUE);
- if (pKV == NULL) {
- pKV = new IniNode;
- pKV->type = IniNode::INI_NODE_TYPE_KEY_VALUE;
- pKV->label = key;
- pSection->Add(pKV);
- }
- pKV->value = value;
- }
- template<>
- HV_EXPORT bool IniParser::Get(const std::string& key, const std::string& section, bool defvalue) {
- std::string str = GetValue(key, section);
- return str.empty() ? defvalue : hv_getboolean(str.c_str());
- }
- template<>
- HV_EXPORT int IniParser::Get(const std::string& key, const std::string& section, int defvalue) {
- std::string str = GetValue(key, section);
- return str.empty() ? defvalue : atoi(str.c_str());
- }
- template<>
- HV_EXPORT float IniParser::Get(const std::string& key, const std::string& section, float defvalue) {
- std::string str = GetValue(key, section);
- return str.empty() ? defvalue : atof(str.c_str());
- }
- template<>
- HV_EXPORT void IniParser::Set(const std::string& key, const bool& value, const std::string& section) {
- SetValue(key, value ? "true" : "false", section);
- }
- template<>
- HV_EXPORT void IniParser::Set(const std::string& key, const int& value, const std::string& section) {
- SetValue(key, asprintf("%d", value), section);
- }
- template<>
- HV_EXPORT void IniParser::Set(const std::string& key, const float& value, const std::string& section) {
- SetValue(key, asprintf("%f", value), section);
- }
|