diff --git a/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs b/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs index 55b5ec91..f15fd8e6 100755 --- a/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs +++ b/shadowsocks-csharp/3rd/zxing/common/StringUtils.cs @@ -30,16 +30,16 @@ namespace ZXing.Common #if (WINDOWS_PHONE70 || WINDOWS_PHONE71 || WINDOWS_PHONE80 || SILVERLIGHT4 || SILVERLIGHT5 || NETFX_CORE || PORTABLE) private const String PLATFORM_DEFAULT_ENCODING = "UTF-8"; #else - private static String PLATFORM_DEFAULT_ENCODING = Encoding.Default.WebName; + private static string PLATFORM_DEFAULT_ENCODING = Encoding.Default.WebName; #endif - public static String SHIFT_JIS = "SJIS"; - public static String GB2312 = "GB2312"; - private const String EUC_JP = "EUC-JP"; - private const String UTF8 = "UTF-8"; - private const String ISO88591 = "ISO-8859-1"; + public static string SHIFT_JIS = "SJIS"; + public static string GB2312 = "GB2312"; + private const string EUC_JP = "EUC-JP"; + private const string UTF8 = "UTF-8"; + private const string ISO88591 = "ISO-8859-1"; private static readonly bool ASSUME_SHIFT_JIS = - String.Compare(SHIFT_JIS, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) == 0 || - String.Compare(EUC_JP, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) == 0; + string.Equals(SHIFT_JIS, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase) || + string.Equals(EUC_JP, PLATFORM_DEFAULT_ENCODING, StringComparison.OrdinalIgnoreCase); /// /// Guesses the encoding. diff --git a/shadowsocks-csharp/3rd/zxing/common/reedsolomon/GenericGFPoly.cs b/shadowsocks-csharp/3rd/zxing/common/reedsolomon/GenericGFPoly.cs index 427fe11d..96df3e69 100755 --- a/shadowsocks-csharp/3rd/zxing/common/reedsolomon/GenericGFPoly.cs +++ b/shadowsocks-csharp/3rd/zxing/common/reedsolomon/GenericGFPoly.cs @@ -145,7 +145,7 @@ namespace ZXing.Common.ReedSolomon internal GenericGFPoly addOrSubtract(GenericGFPoly other) { - if (!field.Equals(other.field)) + if (field != other.field) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } @@ -181,7 +181,7 @@ namespace ZXing.Common.ReedSolomon internal GenericGFPoly multiply(GenericGFPoly other) { - if (!field.Equals(other.field)) + if (field != other.field) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } @@ -246,7 +246,7 @@ namespace ZXing.Common.ReedSolomon internal GenericGFPoly[] divide(GenericGFPoly other) { - if (!field.Equals(other.field)) + if (field != other.field) { throw new ArgumentException("GenericGFPolys do not have same GenericGF field"); } diff --git a/shadowsocks-csharp/3rd/zxing/qrcode/encoder/Encoder.cs b/shadowsocks-csharp/3rd/zxing/qrcode/encoder/Encoder.cs index 56c9a9a8..dbae7bf3 100755 --- a/shadowsocks-csharp/3rd/zxing/qrcode/encoder/Encoder.cs +++ b/shadowsocks-csharp/3rd/zxing/qrcode/encoder/Encoder.cs @@ -86,7 +86,7 @@ namespace ZXing.QrCode.Internal { encoding = DEFAULT_BYTE_MODE_ENCODING; } - bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding); + bool generateECI = !DEFAULT_BYTE_MODE_ENCODING.Equals(encoding, StringComparison.OrdinalIgnoreCase); #else // Silverlight supports only UTF-8 and UTF-16 out-of-the-box const string encoding = "UTF-8"; @@ -514,7 +514,8 @@ namespace ZXing.QrCode.Internal BitArray bits, String encoding) { - if (mode.Equals(Mode.BYTE)) + // TODO: check the purpose of this .Equals(obj) + if (mode == Mode.BYTE) append8BitBytes(content, bits, encoding); else throw new WriterException("Invalid mode: " + mode); diff --git a/shadowsocks-csharp/Controller/FileManager.cs b/shadowsocks-csharp/Controller/FileManager.cs index f6edf147..60dc66e4 100755 --- a/shadowsocks-csharp/Controller/FileManager.cs +++ b/shadowsocks-csharp/Controller/FileManager.cs @@ -10,37 +10,35 @@ namespace Shadowsocks.Controller { try { - FileStream _FileStream = new FileStream(fileName, FileMode.Create, FileAccess.Write); - _FileStream.Write(content, 0, content.Length); - _FileStream.Close(); + using (var fs = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + fs.Write(content, 0, content.Length); return true; } - catch (Exception _Exception) + catch (Exception ex) { Console.WriteLine("Exception caught in process: {0}", - _Exception.ToString()); + ex.ToString()); } return false; } public static void UncompressFile(string fileName, byte[] content) { - FileStream destinationFile = File.Create(fileName); - // Because the uncompressed size of the file is unknown, // we are using an arbitrary buffer size. byte[] buffer = new byte[4096]; int n; - using (GZipStream input = new GZipStream(new MemoryStream(content), + using(var fs = File.Create(fileName)) + using (var input = new GZipStream( + new MemoryStream(content), CompressionMode.Decompress, false)) { while ((n = input.Read(buffer, 0, buffer.Length)) > 0) { - destinationFile.Write(buffer, 0, n); + fs.Write(buffer, 0, n); } } - destinationFile.Close(); } } diff --git a/shadowsocks-csharp/Controller/I18N.cs b/shadowsocks-csharp/Controller/I18N.cs index c99d0f14..85f3ae60 100755 --- a/shadowsocks-csharp/Controller/I18N.cs +++ b/shadowsocks-csharp/Controller/I18N.cs @@ -1,11 +1,12 @@ -using Shadowsocks.Properties; -using System; +using System; using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; +using System.Globalization; +using System.IO; namespace Shadowsocks.Controller { + using Shadowsocks.Properties; + public class I18N { protected static Dictionary Strings; @@ -13,19 +14,19 @@ namespace Shadowsocks.Controller { Strings = new Dictionary(); - if (System.Globalization.CultureInfo.CurrentCulture.IetfLanguageTag.ToLowerInvariant().StartsWith("zh")) + if (CultureInfo.CurrentCulture.IetfLanguageTag.StartsWith("zh", StringComparison.OrdinalIgnoreCase)) { - string[] lines = Regex.Split(Resources.cn, "\r\n|\r|\n"); - foreach (string line in lines) + using (var sr = new StringReader(Resources.cn)) { - if (line.StartsWith("#")) - { - continue; - } - string[] kv = Regex.Split(line, "="); - if (kv.Length == 2) + foreach (var line in sr.NonWhiteSpaceLines()) { - Strings[kv[0]] = kv[1]; + if (line[0] == '#') + continue; + + var pos = line.IndexOf('='); + if (pos < 1) + continue; + Strings[line.Substring(0, pos)] = line.Substring(pos + 1); } } } diff --git a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs index 4e6a71bf..c0467393 100644 --- a/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs +++ b/shadowsocks-csharp/Controller/Service/AvailabilityStatistics.cs @@ -316,4 +316,4 @@ namespace Shadowsocks.Controller _speedMonior.Dispose(); } } -} \ No newline at end of file +} diff --git a/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs b/shadowsocks-csharp/Controller/Service/GfwListUpdater.cs index 2497090d..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 @@ -39,12 +40,14 @@ namespace Shadowsocks.Controller if (File.Exists(PACServer.USER_RULE_FILE)) { string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8); - string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string rule in rules) + using (var sr = new StringReader(local)) { - if (rule.StartsWith("!") || rule.StartsWith("[")) - continue; - lines.Add(rule); + foreach (var rule in sr.NonWhiteSpaceLines()) + { + if (rule.BeginWithAny(IgnoredLineBegins)) + continue; + lines.Add(rule); + } } } string abpContent; @@ -93,13 +96,15 @@ namespace Shadowsocks.Controller { byte[] bytes = Convert.FromBase64String(response); string content = Encoding.ASCII.GetString(bytes); - string[] lines = content.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - List valid_lines = new List(lines.Length); - foreach (string line in lines) + List valid_lines = new List(); + using (var sr = new StringReader(content)) { - if (line.StartsWith("!") || line.StartsWith("[")) - continue; - valid_lines.Add(line); + foreach (var line in sr.NonWhiteSpaceLines()) + { + if (line.BeginWithAny(IgnoredLineBegins)) + continue; + valid_lines.Add(line); + } } return valid_lines; } diff --git a/shadowsocks-csharp/Controller/ShadowsocksController.cs b/shadowsocks-csharp/Controller/ShadowsocksController.cs index 551e2401..cb49f5f2 100755 --- a/shadowsocks-csharp/Controller/ShadowsocksController.cs +++ b/shadowsocks-csharp/Controller/ShadowsocksController.cs @@ -438,6 +438,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()) @@ -450,12 +451,14 @@ namespace Shadowsocks.Controller if (File.Exists(PACServer.USER_RULE_FILE)) { string local = File.ReadAllText(PACServer.USER_RULE_FILE, Encoding.UTF8); - string[] rules = local.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string rule in rules) + using (var sr = new StringReader(local)) { - if (rule.StartsWith("!") || rule.StartsWith("[")) - continue; - lines.Add(rule); + foreach (var rule in sr.NonWhiteSpaceLines()) + { + if (rule.BeginWithAny(IgnoredLineBegins)) + continue; + lines.Add(rule); + } } } string abpContent; diff --git a/shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs b/shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs index c2c64898..c6643a09 100644 --- a/shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs +++ b/shadowsocks-csharp/Controller/Strategy/StatisticsStrategy.cs @@ -20,7 +20,7 @@ namespace Shadowsocks.Controller.Strategy private Statistics _filteredStatistics; private AvailabilityStatistics Service => _controller.availabilityStatistics; private int ChoiceKeptMilliseconds - => (int) TimeSpan.FromMinutes(_controller.StatisticsConfiguration.ChoiceKeptMinutes).TotalMilliseconds; + => (int)TimeSpan.FromMinutes(_controller.StatisticsConfiguration.ChoiceKeptMinutes).TotalMilliseconds; public StatisticsStrategy(ShadowsocksController controller) { @@ -93,7 +93,7 @@ namespace Shadowsocks.Controller.Strategy } ).Aggregate((result1, result2) => result1.score > result2.score ? result1 : result2); - LogWhenEnabled($"Switch to server: {bestResult.server.FriendlyName()} by statistics: score {bestResult.score}"); + LogWhenEnabled($"Switch to server: {bestResult.server.FriendlyName()} by statistics: score {bestResult.score}"); _currentServer = bestResult.server; } catch (Exception e) diff --git a/shadowsocks-csharp/Controller/System/AutoStartup.cs b/shadowsocks-csharp/Controller/System/AutoStartup.cs index a2ad21c1..353056eb 100644 --- a/shadowsocks-csharp/Controller/System/AutoStartup.cs +++ b/shadowsocks-csharp/Controller/System/AutoStartup.cs @@ -1,5 +1,5 @@ -using System; -using System.Windows.Forms; +using System; +using System.Windows.Forms; using Microsoft.Win32; namespace Shadowsocks.Controller @@ -14,7 +14,7 @@ namespace Shadowsocks.Controller try { string path = Application.ExecutablePath; - runKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true); + runKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true); if (enabled) { runKey.SetValue(Key, path); @@ -47,16 +47,16 @@ namespace Shadowsocks.Controller try { string path = Application.ExecutablePath; - runKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true); + runKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Run", true); string[] runList = runKey.GetValueNames(); foreach (string item in runList) { - if (item.Equals(Key)) + if (item.Equals(Key, StringComparison.OrdinalIgnoreCase)) return true; - else if (item.Equals("Shadowsocks")) // Compatibility with older versions + else if (item.Equals("Shadowsocks", StringComparison.OrdinalIgnoreCase)) // Compatibility with older versions { string value = Convert.ToString(runKey.GetValue(item)); - if (path.Equals(value, StringComparison.InvariantCultureIgnoreCase)) + if (path.Equals(value, StringComparison.OrdinalIgnoreCase)) { runKey.DeleteValue(item); runKey.SetValue(Key, path); @@ -76,10 +76,10 @@ namespace Shadowsocks.Controller if (runKey != null) { try { runKey.Close(); } - catch(Exception e) + catch (Exception e) { Logging.LogUsefulException(e); } } } } } -} +} diff --git a/shadowsocks-csharp/Controller/System/SystemProxy.cs b/shadowsocks-csharp/Controller/System/SystemProxy.cs index 74e4beb4..bf77f999 100644 --- a/shadowsocks-csharp/Controller/System/SystemProxy.cs +++ b/shadowsocks-csharp/Controller/System/SystemProxy.cs @@ -9,7 +9,7 @@ using Shadowsocks.Model; namespace Shadowsocks.Controller { - public class SystemProxy + public static class SystemProxy { [DllImport("wininet.dll")] @@ -26,19 +26,29 @@ namespace Shadowsocks.Controller _refreshReturn = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0); } + private static readonly DateTime UnixEpoch + = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + public static long ToUnixEpochMilliseconds(this DateTime dt) + => (long)(dt - UnixEpoch).TotalMilliseconds; + private static string GetTimestamp(DateTime value) + { + return value.ToString("yyyyMMddHHmmssfff"); + } + public static void Update(Configuration config, bool forceDisable) { bool global = config.global; bool enabled = config.enabled; + if (forceDisable) { enabled = false; } + try { - RegistryKey registry = - Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", - true); + var registry = Registry.CurrentUser + .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings", true); if (enabled) { if (global) @@ -50,10 +60,10 @@ 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.ToString() + "/pac?t=" + GetTimestamp(DateTime.Now); + pacUrl = $"http://127.0.0.1:{config.localPort}/pac?t={GetTimestamp(DateTime.Now)}"; registry.SetValue("ProxyEnable", 0); var readProxyServer = registry.GetValue("ProxyServer"); registry.SetValue("ProxyServer", ""); @@ -66,9 +76,11 @@ namespace Shadowsocks.Controller registry.SetValue("ProxyServer", ""); registry.SetValue("AutoConfigURL", ""); } - //Set AutoDetectProxy Off - IEAutoDetectProxy(false); - SystemProxy.NotifyIE(); + + //Set AutoDetectProxy + IEAutoDetectProxy(!enabled); + + NotifyIE(); //Must Notify IE first, or the connections do not chanage CopyProxySettingFromLan(); } @@ -82,55 +94,66 @@ namespace Shadowsocks.Controller private static void CopyProxySettingFromLan() { - RegistryKey registry = - Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections", - true); + var registry = Registry.CurrentUser + .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true); var defaultValue = registry.GetValue("DefaultConnectionSettings"); try { var connections = registry.GetValueNames(); - foreach (String each in connections) + foreach (var each in connections) { - if (!(each.Equals("DefaultConnectionSettings") - || each.Equals("LAN Connection") - || each.Equals("SavedLegacySettings"))) + switch (each.ToUpperInvariant()) { - //set all the connections's proxy as the lan - registry.SetValue(each, defaultValue); + case "DEFAULTCONNECTIONSETTINGS": + case "LAN CONNECTION": + case "SAVEDLEGACYSETTINGS": + continue; + default: + //set all the connections's proxy as the lan + registry.SetValue(each, defaultValue); + continue; } } - SystemProxy.NotifyIE(); - } catch (IOException e) { + NotifyIE(); + } + catch (IOException e) + { Logging.LogUsefulException(e); } } - private static String GetTimestamp(DateTime value) - { - return value.ToString("yyyyMMddHHmmssffff"); - } - /// /// Checks or unchecks the IE Options Connection setting of "Automatically detect Proxy" /// /// Provide 'true' if you want to check the 'Automatically detect Proxy' check box. To uncheck, pass 'false' private static void IEAutoDetectProxy(bool set) { - RegistryKey registry = - Registry.CurrentUser.OpenSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings\\Connections", - true); - byte[] defConnection = (byte[])registry.GetValue("DefaultConnectionSettings"); - byte[] savedLegacySetting = (byte[])registry.GetValue("SavedLegacySettings"); + var registry = Registry.CurrentUser + .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections", true); + var defConnection = (byte[])registry.GetValue("DefaultConnectionSettings"); + var savedLegacySetting = (byte[])registry.GetValue("SavedLegacySettings"); + + const int versionOffset = 4; + const int optionsOffset = 8; + if (set) { - defConnection[8] = Convert.ToByte(defConnection[8] & 8); - savedLegacySetting[8] = Convert.ToByte(savedLegacySetting[8] & 8); + defConnection[optionsOffset] = (byte)(defConnection[optionsOffset] | 8); + savedLegacySetting[optionsOffset] = (byte)(savedLegacySetting[optionsOffset] | 8); } else { - defConnection[8] = Convert.ToByte(defConnection[8] & ~8); - savedLegacySetting[8] = Convert.ToByte(savedLegacySetting[8] & ~8); + defConnection[optionsOffset] = (byte)(defConnection[optionsOffset] & ~8); + savedLegacySetting[optionsOffset] = (byte)(savedLegacySetting[optionsOffset] & ~8); } + + BitConverter.GetBytes( + unchecked(BitConverter.ToUInt32(defConnection, versionOffset) + 1)) + .CopyTo(defConnection, versionOffset); + BitConverter.GetBytes( + unchecked(BitConverter.ToUInt32(savedLegacySetting, versionOffset) + 1)) + .CopyTo(savedLegacySetting, versionOffset); + registry.SetValue("DefaultConnectionSettings", defConnection); registry.SetValue("SavedLegacySettings", savedLegacySetting); } 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/Encryption/IVEncryptor.cs b/shadowsocks-csharp/Encryption/IVEncryptor.cs index f1922ac0..6d84de56 100755 --- a/shadowsocks-csharp/Encryption/IVEncryptor.cs +++ b/shadowsocks-csharp/Encryption/IVEncryptor.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Collections.Concurrent; using System.Security.Cryptography; using System.Text; using System.Net; @@ -24,7 +25,7 @@ namespace Shadowsocks.Encryption protected Dictionary ciphers; - private static readonly Dictionary CachedKeys = new Dictionary(); + private static readonly ConcurrentDictionary CachedKeys = new ConcurrentDictionary(); protected byte[] _encryptIV; protected byte[] _decryptIV; protected bool _decryptIVReceived; @@ -62,22 +63,14 @@ namespace Shadowsocks.Encryption } keyLen = ciphers[_method][0]; ivLen = ciphers[_method][1]; - if (!CachedKeys.ContainsKey(k)) + _key = CachedKeys.GetOrAdd(k, (nk) => { - lock (CachedKeys) - { - if (!CachedKeys.ContainsKey(k)) - { - byte[] passbuf = Encoding.UTF8.GetBytes(password); - _key = new byte[32]; - byte[] iv = new byte[16]; - bytesToKey(passbuf, _key); - CachedKeys[k] = _key; - } - } - } - if (_key == null) - _key = CachedKeys[k]; + byte[] passbuf = Encoding.UTF8.GetBytes(password); + byte[] key = new byte[32]; + byte[] iv = new byte[16]; + bytesToKey(passbuf, key); + return key; + }); } protected void bytesToKey(byte[] password, byte[] key) diff --git a/shadowsocks-csharp/FodyWeavers.xml b/shadowsocks-csharp/FodyWeavers.xml index 2e6d4a7a..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 54c29b6f..a42cbbf3 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 2230519e..6f3efda8 100644 --- a/shadowsocks-csharp/packages.config +++ b/shadowsocks-csharp/packages.config @@ -1,11 +1,13 @@  - + + + \ No newline at end of file diff --git a/shadowsocks-csharp/shadowsocks-csharp.csproj b/shadowsocks-csharp/shadowsocks-csharp.csproj index 389c1122..101ad9ee 100644 --- a/shadowsocks-csharp/shadowsocks-csharp.csproj +++ b/shadowsocks-csharp/shadowsocks-csharp.csproj @@ -205,6 +205,7 @@ + Form @@ -334,6 +335,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); +]]> + + + + +