Fix a bug that internal parser may incorrectly process spaces in configs

Issue [#70](https://github.com/tindy2013/subconverter/issues/70).
This commit is contained in:
Tindy X committed 2020-02-23 18:06:02 +08:00
1 parent ac0dedecf0
commit 9bf13e792b
2 files changed
+85 -61

No files matched your search

+79 -61
View File
@@ -19,8 +19,6 @@ enum
INIREADER_EXCEPTION_NONE INIREADER_EXCEPTION_NONE
}; };
#define __SAVE_ERROR_AND_RETURN(x) {last_error = x; return last_error;}
typedef std::map<std::string, std::multimap<std::string, std::string>> ini_data_struct; typedef std::map<std::string, std::multimap<std::string, std::string>> ini_data_struct;
typedef std::multimap<std::string, std::string> string_multimap; typedef std::multimap<std::string, std::string> string_multimap;
typedef std::vector<std::string> string_array; typedef std::vector<std::string> string_array;
@@ -38,8 +36,8 @@ private:
bool parsed = false; bool parsed = false;
std::string current_section; std::string current_section;
ini_data_struct ini_content; ini_data_struct ini_content;
string_array exclude_sections, include_sections, read_sections; string_array exclude_sections, include_sections, direct_save_sections;
string_array section_order; string_array read_sections, section_order;
std::string cached_section; std::string cached_section;
string_multimap cached_section_content; string_multimap cached_section_content;
@@ -50,7 +48,13 @@ private:
int last_error = INIREADER_EXCEPTION_NONE; int last_error = INIREADER_EXCEPTION_NONE;
unsigned int last_error_index = 0; unsigned int last_error_index = 0;
bool chkIgnore(std::string section) inline int __priv_save_error_and_return(int x)
{
last_error = x;
return last_error;
}
inline bool __priv_chk_ignore(const std::string &section)
{ {
bool excluded = false, included = false; bool excluded = false, included = false;
excluded = std::find(exclude_sections.cbegin(), exclude_sections.cend(), section) != exclude_sections.cend(); excluded = std::find(exclude_sections.cbegin(), exclude_sections.cend(), section) != exclude_sections.cend();
@@ -61,6 +65,30 @@ private:
return excluded || !included; return excluded || !included;
} }
inline bool __priv_chk_direct_save(const std::string &section)
{
return std::find(direct_save_sections.cbegin(), direct_save_sections.cend(), section) != direct_save_sections.cend();
}
inline std::string __priv_get_err_str(int error)
{
switch(error)
{
case INIREADER_EXCEPTION_EMPTY:
return "Empty document";
case INIREADER_EXCEPTION_DUPLICATE:
return "Duplicate section";
case INIREADER_EXCEPTION_NOTEXIST:
return "Target does not exist";
case INIREADER_EXCEPTION_OUTOFBOUND:
return "Item exists outside of any section";
case INIREADER_EXCEPTION_NOTPARSED:
return "Parse error";
default:
return "Undefined";
}
}
public: public:
/** /**
* @brief Set this flag to true to do a UTF8-To-GBK conversion before parsing data. Only useful in Windows. * @brief Set this flag to true to do a UTF8-To-GBK conversion before parsing data. Only useful in Windows.
@@ -129,31 +157,12 @@ public:
INIReader(const INIReader &src) = default; INIReader(const INIReader &src) = default;
std::string GetErrorString(int error)
{
switch(error)
{
case INIREADER_EXCEPTION_EMPTY:
return "Empty document";
case INIREADER_EXCEPTION_DUPLICATE:
return "Duplicate section";
case INIREADER_EXCEPTION_NOTEXIST:
return "Target does not exist";
case INIREADER_EXCEPTION_OUTOFBOUND:
return "Item exists outside of any section";
case INIREADER_EXCEPTION_NOTPARSED:
return "Parse error";
default:
return "Undefined";
}
}
std::string GetLastError() std::string GetLastError()
{ {
if(parsed) if(parsed)
return GetErrorString(last_error); return __priv_get_err_str(last_error);
else else
return "line " + std::to_string(last_error_index) + ": " + GetErrorString(last_error); return "line " + std::to_string(last_error_index) + ": " + __priv_get_err_str(last_error);
} }
/** /**
@@ -172,6 +181,14 @@ public:
include_sections.emplace_back(section); include_sections.emplace_back(section);
} }
/**
* @brief Add a section to the direct-save sections list.
*/
void AddDirectSaveSection(std::string section)
{
direct_save_sections.emplace_back(section);
}
/** /**
* @brief Set isolated items to given section. * @brief Set isolated items to given section.
*/ */
@@ -188,13 +205,13 @@ public:
int Parse(std::string content) //parse content into mapped data int Parse(std::string content) //parse content into mapped data
{ {
if(!content.size()) //empty content if(!content.size()) //empty content
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_EMPTY); return __priv_save_error_and_return(INIREADER_EXCEPTION_EMPTY);
//remove UTF-8 BOM //remove UTF-8 BOM
if(content.compare(0, 3, "\xEF\xBB\xBF") == 0) if(content.compare(0, 3, "\xEF\xBB\xBF") == 0)
content.erase(0, 3); content.erase(0, 3);
bool inExcludedSection = false; bool inExcludedSection = false, inDirectSaveSection = false;
std::string strLine, thisSection, curSection, itemName, itemVal; std::string strLine, thisSection, curSection, itemName, itemVal;
string_multimap itemGroup, existItemGroup; string_multimap itemGroup, existItemGroup;
std::stringstream strStrm; std::stringstream strStrm;
@@ -220,20 +237,11 @@ public:
} }
if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored if(!lineSize || strLine[0] == ';' || strLine[0] == '#' || (lineSize >= 2 && strLine[0] == '/' && strLine[1] == '/')) //empty lines and comments are ignored
continue; continue;
if(strLine.find("=") != strLine.npos) //is an item if(strLine[0] == '[' && strLine[lineSize - 1] == ']') //is a section title
{
if(inExcludedSection) //this section is excluded
continue;
if(!curSection.size()) //not in any section
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_OUTOFBOUND);
itemName = trim(strLine.substr(0, strLine.find("=")));
itemVal = trim(strLine.substr(strLine.find("=") + 1));
itemGroup.emplace(itemName, itemVal); //insert to current section
}
else if(strLine[0] == '[' && strLine[lineSize - 1] == ']') //is a section title
{ {
thisSection = strLine.substr(1, lineSize - 2); //save section title thisSection = strLine.substr(1, lineSize - 2); //save section title
inExcludedSection = chkIgnore(thisSection); //check if this section is excluded inExcludedSection = __priv_chk_ignore(thisSection); //check if this section is excluded
inDirectSaveSection = __priv_chk_direct_save(thisSection); //check if this section requires direct-save
if(curSection.size() && (keep_empty_section || itemGroup.size())) //just finished reading a section if(curSection.size() && (keep_empty_section || itemGroup.size())) //just finished reading a section
{ {
@@ -247,7 +255,7 @@ public:
itemGroup.emplace(x); //insert them all into new section itemGroup.emplace(x); //insert them all into new section
} }
else if(ini_content.at(curSection).size()) else if(ini_content.at(curSection).size())
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop return __priv_save_error_and_return(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
ini_content.erase(curSection); //remove the old section ini_content.erase(curSection); //remove the old section
} }
else if(itemGroup.size()) else if(itemGroup.size())
@@ -260,10 +268,20 @@ public:
eraseElements(itemGroup); //reset section storage eraseElements(itemGroup); //reset section storage
curSection = thisSection; //start a new section curSection = thisSection; //start a new section
} }
else if(store_any_line && !inExcludedSection && curSection.size()) //store a line without name else if((store_any_line || inDirectSaveSection) && !inExcludedSection && curSection.size()) //store a line without name
{ {
itemGroup.emplace("{NONAME}", strLine); itemGroup.emplace("{NONAME}", strLine);
} }
else if(strLine.find("=") != strLine.npos) //is an item
{
if(inExcludedSection) //this section is excluded
continue;
if(!curSection.size()) //not in any section
return __priv_save_error_and_return(INIREADER_EXCEPTION_OUTOFBOUND);
itemName = trim(strLine.substr(0, strLine.find("=")));
itemVal = trim(strLine.substr(strLine.find("=") + 1));
itemGroup.emplace(itemName, itemVal); //insert to current section
}
if(include_sections.size() && include_sections == read_sections) //all included sections has been read if(include_sections.size() && include_sections == read_sections) //all included sections has been read
break; //exit now break; //exit now
} }
@@ -279,7 +297,7 @@ public:
itemGroup.emplace(x); //insert them all into new section itemGroup.emplace(x); //insert them all into new section
} }
else if(ini_content.at(curSection).size()) else if(ini_content.at(curSection).size())
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop return __priv_save_error_and_return(INIREADER_EXCEPTION_DUPLICATE); //not allowed, stop
ini_content.erase(curSection); //remove the old section ini_content.erase(curSection); //remove the old section
} }
else if(itemGroup.size()) else if(itemGroup.size())
@@ -289,7 +307,7 @@ public:
section_order.emplace_back(curSection); section_order.emplace_back(curSection);
} }
parsed = true; parsed = true;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); //all done return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE); //all done
} }
/** /**
@@ -298,7 +316,7 @@ public:
int ParseFile(std::string filePath) int ParseFile(std::string filePath)
{ {
if(!fileExist(filePath)) if(!fileExist(filePath))
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
return Parse(fileGet(filePath)); return Parse(fileGet(filePath));
} }
@@ -340,10 +358,10 @@ public:
int EnterSection(std::string section) int EnterSection(std::string section)
{ {
if(!SectionExist(section)) if(!SectionExist(section))
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
current_section = cached_section = section; current_section = cached_section = section;
cached_section_content = ini_content.at(section); cached_section_content = ini_content.at(section);
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
} }
/** /**
@@ -416,7 +434,7 @@ public:
unsigned int ItemCount(std::string section) unsigned int ItemCount(std::string section)
{ {
if(!parsed || !SectionExist(section)) if(!parsed || !SectionExist(section))
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTPARSED); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTPARSED);
return ini_content.at(section).size(); return ini_content.at(section).size();
} }
@@ -437,7 +455,7 @@ public:
int GetItems(std::string section, string_multimap &data) int GetItems(std::string section, string_multimap &data)
{ {
if(!parsed || !SectionExist(section)) if(!parsed || !SectionExist(section))
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
if(cached_section != section) if(cached_section != section)
{ {
@@ -446,7 +464,7 @@ public:
} }
data = cached_section_content; data = cached_section_content;
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
} }
/** /**
@@ -463,12 +481,12 @@ public:
int GetAll(std::string section, std::string itemName, string_array &results) //retrieve item(s) with the same itemName prefix int GetAll(std::string section, std::string itemName, string_array &results) //retrieve item(s) with the same itemName prefix
{ {
if(!parsed) if(!parsed)
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTPARSED); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTPARSED);
string_multimap mapTemp; string_multimap mapTemp;
if(GetItems(section, mapTemp) != 0) if(GetItems(section, mapTemp) != 0)
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
for(auto &x : mapTemp) for(auto &x : mapTemp)
{ {
@@ -476,7 +494,7 @@ public:
results.emplace_back(x.second); results.emplace_back(x.second);
} }
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
} }
/** /**
@@ -600,7 +618,7 @@ public:
int Set(std::string section, std::string itemName, std::string itemVal) int Set(std::string section, std::string itemName, std::string itemVal)
{ {
if(!section.size()) if(!section.size())
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
if(!parsed) if(!parsed)
parsed = true; parsed = true;
@@ -618,7 +636,7 @@ public:
section_order.emplace_back(section); section_order.emplace_back(section);
} }
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
} }
/** /**
@@ -627,7 +645,7 @@ public:
int Set(std::string itemName, std::string itemVal) int Set(std::string itemName, std::string itemVal)
{ {
if(!current_section.size()) if(!current_section.size())
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
return Set(current_section, itemName, itemVal); return Set(current_section, itemName, itemVal);
} }
@@ -702,7 +720,7 @@ public:
int RenameSection(std::string oldName, std::string newName) int RenameSection(std::string oldName, std::string newName)
{ {
if(!SectionExist(oldName) || SectionExist(newName)) if(!SectionExist(oldName) || SectionExist(newName))
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_DUPLICATE); return __priv_save_error_and_return(INIREADER_EXCEPTION_DUPLICATE);
/* /*
auto nodeHandler = ini_content.extract(oldName); auto nodeHandler = ini_content.extract(oldName);
nodeHandler.key() = newName; nodeHandler.key() = newName;
@@ -711,7 +729,7 @@ public:
ini_content[newName] = std::move(ini_content[oldName]); ini_content[newName] = std::move(ini_content[oldName]);
ini_content.erase(oldName); ini_content.erase(oldName);
std::replace(section_order.begin(), section_order.end(), oldName, newName); std::replace(section_order.begin(), section_order.end(), oldName, newName);
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
} }
/** /**
@@ -721,7 +739,7 @@ public:
{ {
int retVal; int retVal;
if(!SectionExist(section)) if(!SectionExist(section))
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
retVal = ini_content.at(section).erase(itemName); retVal = ini_content.at(section).erase(itemName);
if(retVal && cached_section == section) if(retVal && cached_section == section)
@@ -753,11 +771,11 @@ public:
{ {
cached_section_content = mapTemp; cached_section_content = mapTemp;
} }
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NONE); return __priv_save_error_and_return(INIREADER_EXCEPTION_NONE);
} }
else else
{ {
__SAVE_ERROR_AND_RETURN(INIREADER_EXCEPTION_NOTEXIST); return __priv_save_error_and_return(INIREADER_EXCEPTION_NOTEXIST);
} }
} }
+6
View File
@@ -874,6 +874,11 @@ std::string netchToSurge(std::vector<nodeInfo> &nodes, std::string &base_conf, s
string_array vArray, remarks_list, filtered_nodelist, args; string_array vArray, remarks_list, filtered_nodelist, args;
ini.store_any_line = true; ini.store_any_line = true;
// filter out sections that requires direct-save
ini.AddDirectSaveSection("Rule");
ini.AddDirectSaveSection("Script");
ini.AddDirectSaveSection("URL Rewrite");
ini.AddDirectSaveSection("Header Rewrite");
if(ini.Parse(base_conf) != 0 && !ext.nodelist) if(ini.Parse(base_conf) != 0 && !ext.nodelist)
return std::string(); return std::string();
@@ -1566,6 +1571,7 @@ std::string netchToQuanX(std::vector<nodeInfo> &nodes, std::string &base_conf, s
{ {
INIReader ini; INIReader ini;
ini.store_any_line = true; ini.store_any_line = true;
ini.AddDirectSaveSection("rewrite_local");
if(!ext.nodelist && ini.Parse(base_conf) != 0) if(!ext.nodelist && ini.Parse(base_conf) != 0)
return std::string(); return std::string();