diff --git a/src/generator/config/ruleconvert.cpp b/src/generator/config/ruleconvert.cpp index a38849189..543cec488 100644 --- a/src/generator/config/ruleconvert.cpp +++ b/src/generator/config/ruleconvert.cpp @@ -457,18 +457,25 @@ void rulesetToSurge(INIReader &base_rule, std::vector &ruleset_c } } -static rapidjson::Value transformRuleToSingBox(const std::string& rule, rapidjson::MemoryPoolAllocator<>& allocator) +static rapidjson::Value transformRuleToSingBox(const std::string& rule, const std::string &group, rapidjson::MemoryPoolAllocator<>& allocator) { - std::string type, value, group, option; + auto args = split(rule, ","); + if (args.size() < 2) return rapidjson::Value(rapidjson::kObjectType); + auto type = toLower(std::string(args[0])); + auto value = args[1]; +// std::string_view option; +// if (args.size() >= 3) option = args[2]; - regGetMatch(rule, "^(.*?),(.*?)(?:,(.*?))?(,.*)?$", 5, nullptr, &type, &value, &group, &option); rapidjson::Value rule_obj(rapidjson::kObjectType); type = replaceAllDistinct(toLower(type), "-", "_"); type = replaceAllDistinct(type, "ip_cidr6", "ip_cidr"); - if (type == "match" || type == "final") { - rule_obj.AddMember("outbound", rapidjson::Value(value.c_str(), allocator), allocator); - } else { - rule_obj.AddMember(rapidjson::Value(type.c_str(), allocator), rapidjson::Value(value.c_str(), allocator), allocator); + if (type == "match" || type == "final") + { + rule_obj.AddMember("outbound", rapidjson::Value(value.data(), value.size(), allocator), allocator); + } + else + { + rule_obj.AddMember(rapidjson::Value(type.c_str(), allocator), rapidjson::Value(value.data(), value.size(), allocator), allocator); rule_obj.AddMember("outbound", rapidjson::Value(group.c_str(), allocator), allocator); } return rule_obj; @@ -476,6 +483,7 @@ static rapidjson::Value transformRuleToSingBox(const std::string& rule, rapidjso void rulesetToSingBox(rapidjson::Document &base_rule, std::vector &ruleset_content_array, bool overwrite_original_rules) { + using namespace rapidjson_ext; std::string rule_group, retrieved_rules, strLine, final; std::stringstream strStrm; size_t total_rules = 0; @@ -507,10 +515,7 @@ void rulesetToSingBox(rapidjson::Document &base_rule, std::vector &nodes, int types, extra_settings & std::string proxyToSSSub(std::string base_conf, std::vector &nodes, extra_settings &ext) { - rapidjson::Document json, base; - std::string output_content; - - auto &alloc = json.GetAllocator(); - json.SetObject(); - json.AddMember("remarks", "", alloc); - json.AddMember("server", "", alloc); - json.AddMember("server_port", 0, alloc); - json.AddMember("method", "", alloc); - json.AddMember("password", "", alloc); - json.AddMember("plugin", "", alloc); - json.AddMember("plugin_opts", "", alloc); + using namespace rapidjson_ext; + rapidjson::Document base; + + auto &alloc = base.GetAllocator(); base_conf = trimWhitespace(base_conf); if(base_conf.empty()) base_conf = "{}"; rapidjson::ParseResult result = base.Parse(base_conf.data()); - if(result) - { - for(auto iter = base.MemberBegin(); iter != base.MemberEnd(); iter++) - json.AddMember(iter->name, iter->value, alloc); - } - else + if (!result) writeLog(0, std::string("SIP008 base loader failed with error: ") + rapidjson::GetParseError_En(result.Code()) + " (" + std::to_string(result.Offset()) + ")", LOG_LEVEL_ERROR); - rapidjson::Value jsondata; - jsondata = json.Move(); - - output_content = "["; + rapidjson::Value proxies(rapidjson::kArrayType); for(Proxy &x : nodes) { std::string &remark = x.Remark; @@ -1051,19 +1035,18 @@ std::string proxyToSSSub(std::string base_conf, std::vector &nodes, extra default: continue; } - jsondata["remarks"].SetString(rapidjson::StringRef(remark.c_str(), remark.size())); - jsondata["server"].SetString(rapidjson::StringRef(hostname.c_str(), hostname.size())); - jsondata["server_port"] = x.Port; - jsondata["password"].SetString(rapidjson::StringRef(password.c_str(), password.size())); - jsondata["method"].SetString(rapidjson::StringRef(method.c_str(), method.size())); - jsondata["plugin"].SetString(rapidjson::StringRef(plugin.c_str(), plugin.size())); - jsondata["plugin_opts"].SetString(rapidjson::StringRef(pluginopts.c_str(), pluginopts.size())); - output_content += SerializeObject(jsondata) + ","; + rapidjson::Value proxy(rapidjson::kObjectType); + proxy.CopyFrom(base, alloc) + | AddMemberOrReplace("remarks", rapidjson::Value(remark.c_str(), remark.size()), alloc) + | AddMemberOrReplace("server", rapidjson::Value(hostname.c_str(), hostname.size()), alloc) + | AddMemberOrReplace("server_port", rapidjson::Value(x.Port), alloc) + | AddMemberOrReplace("method", rapidjson::Value(method.c_str(), method.size()), alloc) + | AddMemberOrReplace("password", rapidjson::Value(password.c_str(), password.size()), alloc) + | AddMemberOrReplace("plugin", rapidjson::Value(plugin.c_str(), plugin.size()), alloc) + | AddMemberOrReplace("plugin_opts", rapidjson::Value(pluginopts.c_str(), pluginopts.size()), alloc); + proxies.PushBack(proxy, alloc); } - if(output_content.size() > 1) - output_content.erase(output_content.size() - 1); - output_content += "]"; - return output_content; + return proxies | SerializeObject(); } std::string proxyToQuan(std::vector &nodes, const std::string &base_conf, std::vector &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) @@ -2101,6 +2084,7 @@ static rapidjson::Value buildV2RayTransport(const Proxy& proxy, rapidjson::Memor } void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::vector &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) { + using namespace rapidjson_ext; rapidjson::Document::AllocatorType &allocator = json.GetAllocator(); rapidjson::Value outbounds(rapidjson::kArrayType), route(rapidjson::kArrayType); std::vector nodelist; @@ -2231,11 +2215,8 @@ void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::v proxy.AddMember("tag", rapidjson::StringRef(x.Remark.c_str()), allocator); proxy.AddMember("server", rapidjson::StringRef(x.Hostname.c_str()), allocator); proxy.AddMember("server_port", x.Port, allocator); - if (x.TLSSecure) - { - proxy.AddMember("username", rapidjson::StringRef(x.Username.c_str()), allocator); - proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator); - } + proxy.AddMember("username", rapidjson::StringRef(x.Username.c_str()), allocator); + proxy.AddMember("password", rapidjson::StringRef(x.Password.c_str()), allocator); break; } case ProxyType::SOCKS5: @@ -2272,7 +2253,7 @@ void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::v nodelist.push_back(x); outbounds.PushBack(proxy, allocator); } - for (const ProxyGroupConfig& x: extra_proxy_group) + for (const ProxyGroupConfig &x: extra_proxy_group) { string_array filtered_nodelist; std::string type; @@ -2318,16 +2299,14 @@ void proxyToSingBox(std::vector &nodes, rapidjson::Document &json, std::v if (x.Tolerance > 0) group.AddMember("tolerance", x.Tolerance, allocator); } - outbounds.PushBack(group, allocator); } - if (json.HasMember("outbounds")) - json.RemoveMember("outbounds"); - json.AddMember("outbounds", outbounds, allocator); + json | AddMemberOrReplace("outbounds", outbounds, allocator); } std::string proxyToSingBox(std::vector &nodes, const std::string &base_conf, std::vector &ruleset_content_array, const ProxyGroupConfigs &extra_proxy_group, extra_settings &ext) { + using namespace rapidjson_ext; rapidjson::Document json; json.Parse(base_conf.data()); if(json.HasParseError()) @@ -2339,5 +2318,5 @@ std::string proxyToSingBox(std::vector &nodes, const std::string &base_co proxyToSingBox(nodes, json, ruleset_content_array, extra_proxy_group, ext); rulesetToSingBox(json, ruleset_content_array, ext.overwrite_original_rules); - return SerializeObject(json); + return json | SerializeObject(); } diff --git a/src/parser/subparser.cpp b/src/parser/subparser.cpp index 35cbf7c66..07cd39412 100644 --- a/src/parser/subparser.cpp +++ b/src/parser/subparser.cpp @@ -14,6 +14,7 @@ #include "subparser.h" using namespace rapidjson; +using namespace rapidjson_ext; using namespace YAML; string_array ss_ciphers = {"rc4-md5", "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf"}; @@ -2140,7 +2141,7 @@ void explodeNetchConf(std::string netch, std::vector &nodes) for(uint32_t i = 0; i < json["Server"].Size(); i++) { Proxy node; - explodeNetch("Netch://" + base64Encode(SerializeObject(json["Server"][i])), node); + explodeNetch("Netch://" + base64Encode(json["Server"][i] | SerializeObject()), node); node.Id = index; nodes.emplace_back(std::move(node)); diff --git a/src/utils/rapidjson_extra.h b/src/utils/rapidjson_extra.h index c3f580095..5404d822e 100644 --- a/src/utils/rapidjson_extra.h +++ b/src/utils/rapidjson_extra.h @@ -19,7 +19,7 @@ template void exception_thrower(T e, const std::string &cond, const #include #include -inline void operator >> (const rapidjson::Value& value, std::string& i) +inline void operator >> (const rapidjson::Value &value, std::string &i) { if(value.IsNull()) i = ""; @@ -35,7 +35,7 @@ inline void operator >> (const rapidjson::Value& value, std::string& i) i = ""; } -inline void operator >> (const rapidjson::Value& value, int& i) +inline void operator >> (const rapidjson::Value &value, int &i) { if(value.IsNull()) i = 0; @@ -49,7 +49,7 @@ inline void operator >> (const rapidjson::Value& value, int& i) i = 0; } -inline std::string GetMember(const rapidjson::Value& value, const std::string &member) +inline std::string GetMember(const rapidjson::Value &value, const std::string &member) { std::string retStr; if(value.IsObject() && value.HasMember(member.data())) @@ -57,23 +57,15 @@ inline std::string GetMember(const rapidjson::Value& value, const std::string &m return retStr; } -inline void GetMember(const rapidjson::Value& value, const std::string &member, std::string& target) +inline void GetMember(const rapidjson::Value &value, const std::string &member, std::string &target) { std::string retStr = GetMember(value, member); - if(retStr.size()) + if(!retStr.empty()) target.assign(retStr); } -inline std::string SerializeObject(const rapidjson::Value& value) -{ - rapidjson::StringBuffer sb; - rapidjson::Writer writer_json(sb); - value.Accept(writer_json); - return sb.GetString(); -} - template -inline rapidjson::Value buildObject(rapidjson::MemoryPoolAllocator<> & allocator, Args... kvs) +inline rapidjson::Value buildObject(rapidjson::MemoryPoolAllocator<> &allocator, Args... kvs) { static_assert(sizeof...(kvs) % 2 == 0, "buildObject requires an even number of arguments"); static_assert((std::is_same::value && ...), "buildObject requires all arguments to be const char*"); @@ -93,5 +85,57 @@ inline rapidjson::Value buildBooleanValue(bool value) return value ? rapidjson::Value(rapidjson::kTrueType) : rapidjson::Value(rapidjson::kFalseType); } +namespace rapidjson_ext { + template + struct ExtensionFunction { + virtual ReturnType operator() (rapidjson::Value &root) const = 0; + virtual ReturnType operator() (rapidjson::Value &&root) const + { + return (*this)(root); + }; + }; + + struct AddMemberOrReplace : public ExtensionFunction { + rapidjson::Value &member; + const rapidjson::Value::Ch *name; + rapidjson::MemoryPoolAllocator<> &allocator; + AddMemberOrReplace(const rapidjson::Value::Ch *name, rapidjson::Value &value, + rapidjson::MemoryPoolAllocator<> &allocator) : member(value), name(name), allocator(allocator) {} + AddMemberOrReplace(const rapidjson::Value::Ch *name, rapidjson::Value &&value, + rapidjson::MemoryPoolAllocator<> &allocator) : member(value), name(name), allocator(allocator) {} + + inline rapidjson::Value & operator() (rapidjson::Value &root) const override + { + if (root.HasMember(name)) + root[name] = member; + else + root.AddMember(rapidjson::StringRef(name), member, allocator); + return root; + } + }; + + struct SerializeObject : public ExtensionFunction { + inline std::string operator() (rapidjson::Value &root) const override + { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + root.Accept(writer); + return buffer.GetString(); + } + }; + + template + inline ReturnType operator| (rapidjson::Value &root, const ExtensionFunction &func) + { + return func(root); + } + + template + inline ReturnType operator| (rapidjson::Value &&root, const ExtensionFunction &func) + { + return func(root); + } +} + #endif // RAPIDJSON_EXTRA_H_INCLUDED diff --git a/src/utils/string.cpp b/src/utils/string.cpp index 7e2789eba..897edc83a 100644 --- a/src/utils/string.cpp +++ b/src/utils/string.cpp @@ -19,8 +19,8 @@ std::vector split(const std::string &s, const std::string &seperato while(i != s.size() && flag == 0) { flag = 1; - for(string_size x = 0; x < seperator.size(); ++x) - if(s[i] == seperator[x]) + for(char x : seperator) + if(s[i] == x) { ++i; flag = 0; @@ -32,8 +32,8 @@ std::vector split(const std::string &s, const std::string &seperato string_size j = i; while(j != s.size() && flag == 0) { - for(string_size x = 0; x < seperator.size(); ++x) - if(s[j] == seperator[x]) + for(char x : seperator) + if(s[j] == x) { flag = 1; break;