diff --git a/shadowsocks-csharp/Controller/I18N.cs b/shadowsocks-csharp/Controller/I18N.cs index b298ae0c..85f3ae60 100755 --- a/shadowsocks-csharp/Controller/I18N.cs +++ b/shadowsocks-csharp/Controller/I18N.cs @@ -18,10 +18,9 @@ namespace Shadowsocks.Controller { using (var sr = new StringReader(Resources.cn)) { - string line; - while ((line = sr.ReadLine()) != null) + foreach (var line in sr.NonWhiteSpaceLines()) { - if (line == "" || line[0] == '#') + if (line[0] == '#') continue; var pos = line.IndexOf('='); diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index f6e6831b..3a89ed8b 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -247,7 +247,7 @@ namespace Shadowsocks.Controller { var currentHour = DateTime.Now.Hour; filteredData = filteredData.Where(data => - data.Timestamp != UnknownDateTime && data.Timestamp.Hour.Equals(currentHour) + data.Timestamp != UnknownDateTime && data.Timestamp.Hour == currentHour ); if (filteredData.LongCount() == 0) return; } diff --git a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs index e89935b2..3d04fafc 100644 --- a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs +++ b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs @@ -30,6 +30,7 @@ namespace Shadowsocks.Controller } } + private static readonly IEnumerable IgnoredLineBegins = new[] { '!', '[' }; private void http_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e) { try @@ -41,10 +42,9 @@ namespace Shadowsocks.Controller string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8); using (var sr = new StringReader(local)) { - string rule; - while ((rule = sr.ReadLine()) != null) + foreach (var rule in sr.NonWhiteSpaceLines()) { - if (rule == "" || rule[0] == '!' || rule[0] == '[') + if (rule.BeginWithAny(IgnoredLineBegins)) continue; lines.Add(rule); } @@ -99,10 +99,9 @@ namespace Shadowsocks.Controller List valid_lines = new List(); using (var sr = new StringReader(content)) { - string line; - while ((line = sr.ReadLine()) != null) + foreach (var line in sr.NonWhiteSpaceLines()) { - if (line == "" || line[0] == '!' || line[0] == '[') + if (line.BeginWithAny(IgnoredLineBegins)) continue; valid_lines.Add(line); } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 960b8f97..4b86a204 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -442,6 +442,7 @@ namespace Shadowsocks.Controller UpdatePACFromGFWListError(this, e); } + private static readonly IEnumerable IgnoredLineBegins = new[] { '!', '[' }; private void pacServer_UserRuleFileChanged(object sender, EventArgs e) { // TODO: this is a dirty hack. (from code GListUpdater.http_DownloadStringCompleted()) @@ -456,10 +457,9 @@ namespace Shadowsocks.Controller string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8); using (var sr = new StringReader(local)) { - string rule; - while ((rule = sr.ReadLine()) != null) + foreach (var rule in sr.NonWhiteSpaceLines()) { - if (rule == "" || rule[0] == '!' || rule[0] == '[') + if (rule.BeginWithAny(IgnoredLineBegins)) continue; lines.Add(rule); } diff --git a/shadowsocks-csharp/Controller/System/SystemProxy.cs b/shadowsocks-csharp/Controller/System/SystemProxy.cs index c13c2f10..bf77f999 100644 --- a/shadowsocks-csharp/Controller/System/SystemProxy.cs +++ b/shadowsocks-csharp/Controller/System/SystemProxy.cs @@ -60,7 +60,7 @@ namespace Shadowsocks.Controller else { string pacUrl; - if (config.useOnlinePac && !string.IsNullOrEmpty(config.pacUrl)) + if (config.useOnlinePac && !config.pacUrl.IsNullOrEmpty()) pacUrl = config.pacUrl; else pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}"; diff --git a/shadowsocks-csharp/Encryption/EncryptorFactory.cs b/shadowsocks-csharp/Encryption/EncryptorFactory.cs index b9cda1a7..41bd5c64 100644 --- a/shadowsocks-csharp/Encryption/EncryptorFactory.cs +++ b/shadowsocks-csharp/Encryption/EncryptorFactory.cs @@ -25,7 +25,7 @@ namespace Shadowsocks.Encryption public static IEncryptor GetEncryptor(string method, string password, bool onetimeauth, bool isudp) { - if (string.IsNullOrEmpty(method)) + if (method.IsNullOrEmpty()) { method = "aes-256-cfb"; } diff --git a/shadowsocks-csharp/FodyWeavers.xml b/shadowsocks-csharp/FodyWeavers.xml index 17e88514..7d3f21a9 100644 --- a/shadowsocks-csharp/FodyWeavers.xml +++ b/shadowsocks-csharp/FodyWeavers.xml @@ -1,5 +1,5 @@  - - + + \ No newline at end of file diff --git a/shadowsocks-csharp/Model/Configuration.cs b/shadowsocks-csharp/Model/Configuration.cs index d65c23a9..10a42124 100755 --- a/shadowsocks-csharp/Model/Configuration.cs +++ b/shadowsocks-csharp/Model/Configuration.cs @@ -124,13 +124,13 @@ namespace Shadowsocks.Model private static void CheckPassword(string password) { - if (string.IsNullOrEmpty(password)) + if (password.IsNullOrEmpty()) throw new ArgumentException(I18N.GetString("Password can not be blank")); } private static void CheckServer(string server) { - if (string.IsNullOrEmpty(server)) + if (server.IsNullOrEmpty()) throw new ArgumentException(I18N.GetString("Server IP can not be blank")); } } diff --git a/shadowsocks-csharp/Model/Server.cs b/shadowsocks-csharp/Model/Server.cs index 8306d9e3..69682302 100755 --- a/shadowsocks-csharp/Model/Server.cs +++ b/shadowsocks-csharp/Model/Server.cs @@ -29,11 +29,11 @@ namespace Shadowsocks.Model public string FriendlyName() { - if (string.IsNullOrEmpty(server)) + if (server.IsNullOrEmpty()) { return I18N.GetString("New server"); } - if (string.IsNullOrEmpty(remarks)) + if (remarks.IsNullOrEmpty()) { return server + ":" + server_port; } diff --git a/shadowsocks-csharp/StringEx.cs b/shadowsocks-csharp/StringEx.cs new file mode 100644 index 00000000..5f107a50 --- /dev/null +++ b/shadowsocks-csharp/StringEx.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; + +static partial class StringEx +{ +#pragma warning disable 1591 + + public static StringComparison GlobalDefaultComparison { get; set; } = StringComparison.Ordinal; + + [ThreadStatic] + private static StringComparison? _DefaultComparison; + public static StringComparison DefaultComparison + { + get { return _DefaultComparison ?? GlobalDefaultComparison; } + set { _DefaultComparison = value; } + } + + #region basic String methods + + public static bool IsNullOrEmpty(this string value) + => string.IsNullOrEmpty(value); + + public static bool IsNullOrWhiteSpace(this string value) + => string.IsNullOrWhiteSpace(value); + + public static bool IsWhiteSpace(this string value) + { + foreach(var c in value) + { + if (char.IsWhiteSpace(c)) continue; + + return false; + } + return true; + } + +#if !PCL + public static string IsInterned(this string value) + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + return string.IsInterned(value); + } + + public static string Intern(this string value) + { + if (value == null) + throw new ArgumentNullException(nameof(value)); + + return string.Intern(value); + } +#endif + + #endregion + + #region comparing + + #region Is + + public static bool Is(this string a, string b) + => string.Equals(a, b, DefaultComparison); + public static bool Is(this string a, string b, StringComparison comparisonType) + => string.Equals(a, b, comparisonType); + + #endregion + + #region BeginWith + + public static bool BeginWith(this string s, char c) + { + if (s.IsNullOrEmpty()) return false; + return s[0] == c; + } + public static bool BeginWithAny(this string s, IEnumerable chars) + { + if (s.IsNullOrEmpty()) return false; + return chars.Contains(s[0]); + } + public static bool BeginWithAny(this string s, params char[] chars) + => s.BeginWithAny(chars.AsEnumerable()); + + public static bool BeginWith(this string a, string b) + { + if (a == null || b == null) return false; + + return a.StartsWith(b, DefaultComparison); + } + public static bool BeginWith(this string a, string b, StringComparison comparisonType) + { + if (a == null || b == null) return false; + + return a.StartsWith(b, comparisonType); + } +#if !PCL + public static bool BeginWith(this string a, string b, bool ignoreCase, CultureInfo culture) + { + if (a == null || b == null) return false; + + return a.StartsWith(b, ignoreCase, culture); + } +#endif + + #endregion + + #region FinishWith + + public static bool FinishWith(this string s, char c) + { + if (s.IsNullOrEmpty()) return false; + return s.Last() == c; + } + public static bool FinishWithAny(this string s, IEnumerable chars) + { + if (s.IsNullOrEmpty()) return false; + return chars.Contains(s.Last()); + } + public static bool FinishWithAny(this string s, params char[] chars) + => s.FinishWithAny(chars.AsEnumerable()); + + public static bool FinishWith(this string a, string b) + { + if (a == null || b == null) return false; + + return a.EndsWith(b, DefaultComparison); + } + public static bool FinishWith(this string a, string b, StringComparison comparisonType) + { + if (a == null || b == null) return false; + + return a.EndsWith(b, comparisonType); + } +#if !PCL + public static bool FinishWith(this string a, string b, bool ignoreCase, CultureInfo culture) + { + if (a == null || b == null) return false; + + return a.EndsWith(b, ignoreCase, culture); + } +#endif + + #endregion + + #endregion + + #region ToLines + + public static IEnumerable ToLines(this TextReader reader) + { + string line; + while ((line = reader.ReadLine()) != null) + yield return line; + } + public static IEnumerable NonEmptyLines(this TextReader reader) + { + string line; + while ((line = reader.ReadLine()) != null) + { + if (line == "") continue; + yield return line; + } + } + public static IEnumerable NonWhiteSpaceLines(this TextReader reader) + { + string line; + while ((line = reader.ReadLine()) != null) + { + if (line.IsWhiteSpace()) continue; + yield return line; + } + } + + #endregion + + #region others + + private static readonly char[][] Quotes = new[] + { + "\"\"", + "''", + "“”", + "‘’", + "『』", + "「」", + "〖〗", + "【】", + }.Select(s => s.ToCharArray()).ToArray(); + public static string Enquote(this string value) + { + if (value == null) + return "(null)"; + + foreach (var pair in Quotes) + { + if (value.IndexOfAny(pair) < 0) + return pair[0] + value + pair[1]; + } + + return '"' + value.Replace("\\", @"\\").Replace("\"", @"\""") + '"'; + } + + public static string Replace(this string value, string find, string rep, StringComparison comparsionType) + { + if (find.IsNullOrEmpty()) + throw new ArgumentException(null, nameof(find)); + if (rep == null) + rep = ""; + if (value.IsNullOrEmpty()) + return value; + + var sb = new StringBuilder(value.Length); + + var last = 0; + var len = find.Length; + var idx = value.IndexOf(find, DefaultComparison); + while (idx != -1) + { + sb.Append(value.Substring(last, idx - last)); + sb.Append(rep); + idx += len; + + last = idx; + idx = value.IndexOf(find, idx, comparsionType); + } + sb.Append(value.Substring(last)); + + return sb.ToString(); + } + public static string ReplaceEx(this string value, string find, string rep) + => value.Replace(find, rep, DefaultComparison); + + #endregion +} diff --git a/shadowsocks-csharp/View/MenuViewController.cs b/shadowsocks-csharp/View/MenuViewController.cs index 32eb992d..fc942835 100755 --- a/shadowsocks-csharp/View/MenuViewController.cs +++ b/shadowsocks-csharp/View/MenuViewController.cs @@ -630,11 +630,11 @@ namespace Shadowsocks.View { if (!onlinePACItem.Checked) { - if (String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl)) + if (controller.GetConfigurationCopy().pacUrl.IsNullOrEmpty()) { UpdateOnlinePACURLItem_Click(sender, e); } - if (!String.IsNullOrEmpty(controller.GetConfigurationCopy().pacUrl)) + if (!controller.GetConfigurationCopy().pacUrl.IsNullOrEmpty()) { localPACItem.Checked = false; onlinePACItem.Checked = true; @@ -651,7 +651,7 @@ namespace Shadowsocks.View I18N.GetString("Please input PAC Url"), I18N.GetString("Edit Online PAC URL"), origPacUrl, -1, -1); - if (!string.IsNullOrEmpty(pacUrl) && pacUrl != origPacUrl) + if (!pacUrl.IsNullOrEmpty() && pacUrl != origPacUrl) { controller.SavePACUrl(pacUrl); } diff --git a/shadowsocks-csharp/packages.config b/shadowsocks-csharp/packages.config index c0fab934..6f3efda8 100644 --- a/shadowsocks-csharp/packages.config +++ b/shadowsocks-csharp/packages.config @@ -1,12 +1,13 @@  - - + + + \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 69f7b546..d401a59a 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -204,6 +204,7 @@ + Form @@ -333,6 +334,43 @@ + + + + + + + + + + + + +(); +var attribute = config.Attribute("ExcludeAssemblies"); +if (attribute != null) + foreach (var item in attribute.Value.Split('|').Select(x => x.Trim()).Where(x => x != string.Empty)) + excludedAssemblies.Add(item); +var element = config.Element("ExcludeAssemblies"); +if (element != null) + foreach (var item in element.Value.Split(new[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).Where(x => x != string.Empty)) + excludedAssemblies.Add(item); + +var filesToCleanup = Files.Select(f => f.ItemSpec).Where(f => !excludedAssemblies.Contains(Path.GetFileNameWithoutExtension(f), StringComparer.InvariantCultureIgnoreCase)); + +foreach (var item in filesToCleanup) + File.Delete(item); +]]> + + + + +