using NLog; using System; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Runtime.InteropServices; using System.Windows.Forms; using Microsoft.Win32; using Shadowsocks.Controller; using Shadowsocks.Model; using System.Drawing; using ZXing; using ZXing.QrCode; using ZXing.Common; namespace Shadowsocks.Util { public struct BandwidthScaleInfo { public float value; public string unitName; public long unit; public BandwidthScaleInfo(float value, string unitName, long unit) { this.value = value; this.unitName = unitName; this.unit = unit; } } public static class Utils { private static Logger logger = LogManager.GetCurrentClassLogger(); private static string _tempPath = null; // return path to store temporary files public static string GetTempPath() { if (_tempPath == null) { bool isPortableMode = Configuration.Load().portableMode; try { if (isPortableMode) { _tempPath = Directory.CreateDirectory("ss_win_temp").FullName; // don't use "/", it will fail when we call explorer /select xxx/ss_win_temp\xxx.log } else { _tempPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), @"Shadowsocks\ss_win_temp_" + Program.ExecutablePath.GetHashCode())).FullName; } } catch (Exception e) { logger.Error(e); throw; } } return _tempPath; } public enum WindowsThemeMode { Dark, Light } // Support on Windows 10 1903+ public static WindowsThemeMode GetWindows10SystemThemeSetting() { WindowsThemeMode themeMode = WindowsThemeMode.Dark; try { RegistryKey reg_ThemesPersonalize = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false); if (reg_ThemesPersonalize.GetValue("SystemUsesLightTheme") != null) { if ((int)(reg_ThemesPersonalize.GetValue("SystemUsesLightTheme")) == 0) // 0:dark mode, 1:light mode themeMode = WindowsThemeMode.Dark; else themeMode = WindowsThemeMode.Light; } else { throw new Exception("Reg-Value SystemUsesLightTheme not found."); } } catch { logger.Debug( $"Cannot get Windows 10 system theme mode, return default value 0 (dark mode)."); } return themeMode; } // return a full path with filename combined which pointed to the temporary directory public static string GetTempPath(string filename) { return Path.Combine(GetTempPath(), filename); } public static string UnGzip(byte[] buf) { byte[] buffer = new byte[1024]; int n; using (MemoryStream sb = new MemoryStream()) { using (GZipStream input = new GZipStream(new MemoryStream(buf), CompressionMode.Decompress, false)) { while ((n = input.Read(buffer, 0, buffer.Length)) > 0) { sb.Write(buffer, 0, n); } } return System.Text.Encoding.UTF8.GetString(sb.ToArray()); } } public static string FormatBandwidth(long n) { var result = GetBandwidthScale(n); return $"{result.value:0.##}{result.unitName}"; } public static string FormatBytes(long bytes) { const long K = 1024L; const long M = K * 1024L; const long G = M * 1024L; const long T = G * 1024L; const long P = T * 1024L; const long E = P * 1024L; if (bytes >= P * 990) return (bytes / (double)E).ToString("F5") + "EiB"; if (bytes >= T * 990) return (bytes / (double)P).ToString("F5") + "PiB"; if (bytes >= G * 990) return (bytes / (double)T).ToString("F5") + "TiB"; if (bytes >= M * 990) { return (bytes / (double)G).ToString("F4") + "GiB"; } if (bytes >= M * 100) { return (bytes / (double)M).ToString("F1") + "MiB"; } if (bytes >= M * 10) { return (bytes / (double)M).ToString("F2") + "MiB"; } if (bytes >= K * 990) { return (bytes / (double)M).ToString("F3") + "MiB"; } if (bytes > K * 2) { return (bytes / (double)K).ToString("F1") + "KiB"; } return bytes.ToString() + "B"; } /// /// Return scaled bandwidth /// /// Raw bandwidth /// /// The BandwidthScaleInfo struct /// public static BandwidthScaleInfo GetBandwidthScale(long n) { long scale = 1; float f = n; string unit = "B"; if (f > 1024) { f = f / 1024; scale <<= 10; unit = "KiB"; } if (f > 1024) { f = f / 1024; scale <<= 10; unit = "MiB"; } if (f > 1024) { f = f / 1024; scale <<= 10; unit = "GiB"; } if (f > 1024) { f = f / 1024; scale <<= 10; unit = "TiB"; } return new BandwidthScaleInfo(f, unit, scale); } public static RegistryKey OpenRegKey(string name, bool writable, RegistryHive hive = RegistryHive.CurrentUser) { // we are building x86 binary for both x86 and x64, which will // cause problem when opening registry key // detect operating system instead of CPU if (string.IsNullOrEmpty(name)) throw new ArgumentException(nameof(name)); try { RegistryKey userKey = RegistryKey.OpenBaseKey(hive, Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32) .OpenSubKey(name, writable); return userKey; } catch (ArgumentException ae) { MessageBox.Show("OpenRegKey: " + ae.ToString()); return null; } catch (Exception e) { logger.LogUsefulException(e); return null; } } public static bool IsWinVistaOrHigher() { return Environment.OSVersion.Version.Major > 5; } public static string ScanQRCodeFromScreen() { foreach (Screen screen in Screen.AllScreens) { using (Bitmap fullImage = new Bitmap(screen.Bounds.Width, screen.Bounds.Height)) { using (Graphics g = Graphics.FromImage(fullImage)) { g.CopyFromScreen(screen.Bounds.X, screen.Bounds.Y, 0, 0, fullImage.Size, CopyPixelOperation.SourceCopy); } int maxTry = 10; for (int i = 0; i < maxTry; i++) { int marginLeft = (int)((double)fullImage.Width * i / 2.5 / maxTry); int marginTop = (int)((double)fullImage.Height * i / 2.5 / maxTry); Rectangle cropRect = new Rectangle(marginLeft, marginTop, fullImage.Width - marginLeft * 2, fullImage.Height - marginTop * 2); Bitmap target = new Bitmap(screen.Bounds.Width, screen.Bounds.Height); double imageScale = (double)screen.Bounds.Width / (double)cropRect.Width; using (Graphics g = Graphics.FromImage(target)) { g.DrawImage(fullImage, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel); } var source = new BitmapLuminanceSource(target); var bitmap = new BinaryBitmap(new HybridBinarizer(source)); QRCodeReader reader = new QRCodeReader(); var result = reader.decode(bitmap); if (result != null) return result.Text; } } } return null; } // See: https://msdn.microsoft.com/en-us/library/hh925568(v=vs.110).aspx public static bool IsSupportedRuntimeVersion() { /* * +-----------------------------------------------------------------+----------------------------+ * | Version | Value of the Release DWORD | * +-----------------------------------------------------------------+----------------------------+ * | .NET Framework 4.6.2 installed on Windows 10 Anniversary Update | 394802 | * | .NET Framework 4.6.2 installed on all other Windows OS versions | 394806 | * +-----------------------------------------------------------------+----------------------------+ */ const int minSupportedRelease = 394802; const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; using (var ndpKey = OpenRegKey(subkey, false, RegistryHive.LocalMachine)) { if (ndpKey?.GetValue("Release") != null) { var releaseKey = (int)ndpKey.GetValue("Release"); if (releaseKey >= minSupportedRelease) { return true; } } } return false; } } }