From b36737f7f96d21829b73404e474aab62ad6addcd Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 22 Aug 2020 01:06:14 +0100 Subject: [PATCH] Add settings. --- RomRepoMgr.Core/Interop/DetectOS.cs | 383 ++++++++++++++++++ RomRepoMgr.Core/Interop/PlatformID.cs | 120 ++++++ RomRepoMgr.Core/Interop/Version.cs | 86 ++++ RomRepoMgr.Core/RomRepoMgr.Core.csproj | 11 + .../RomRepoMgr.Settings.csproj | 16 + RomRepoMgr.Settings/Settings.cs | 309 ++++++++++++++ RomRepoMgr.sln | 12 + 7 files changed, 937 insertions(+) create mode 100644 RomRepoMgr.Core/Interop/DetectOS.cs create mode 100644 RomRepoMgr.Core/Interop/PlatformID.cs create mode 100644 RomRepoMgr.Core/Interop/Version.cs create mode 100644 RomRepoMgr.Core/RomRepoMgr.Core.csproj create mode 100644 RomRepoMgr.Settings/RomRepoMgr.Settings.csproj create mode 100644 RomRepoMgr.Settings/Settings.cs diff --git a/RomRepoMgr.Core/Interop/DetectOS.cs b/RomRepoMgr.Core/Interop/DetectOS.cs new file mode 100644 index 0000000..3a23b56 --- /dev/null +++ b/RomRepoMgr.Core/Interop/DetectOS.cs @@ -0,0 +1,383 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : DetectOS.cs +// Author(s) : Natalia Portillo +// +// Component : Interop services. +// +// --[ Description ] ---------------------------------------------------------- +// +// Detects underlying operating system. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2020 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Principal; + +namespace Aaru.CommonTypes.Interop +{ + public static class DetectOS + { + public static readonly bool IsMono = + RuntimeInformation.FrameworkDescription.StartsWith("Mono", StringComparison.Ordinal); + public static readonly bool IsNetFramework = + RuntimeInformation.FrameworkDescription.StartsWith(".NET Framework", StringComparison.Ordinal); + public static readonly bool IsNetCore = + RuntimeInformation.FrameworkDescription.StartsWith(".NET Core", StringComparison.Ordinal); + public static readonly bool IsNetNative = + RuntimeInformation.FrameworkDescription.StartsWith(".NET Native", StringComparison.Ordinal); + + /// Checks if the underlying runtime runs in 64-bit mode + public static readonly bool Is64Bit = IntPtr.Size == 8; + + /// Checks if the underlying runtime runs in 32-bit mode + public static readonly bool Is32Bit = IntPtr.Size == 4; + + public static bool IsWindows => GetRealPlatformID() == PlatformID.Win32NT || + GetRealPlatformID() == PlatformID.Win32S || + GetRealPlatformID() == PlatformID.Win32Windows || + GetRealPlatformID() == PlatformID.WinCE || + GetRealPlatformID() == PlatformID.WindowsPhone || + GetRealPlatformID() == PlatformID.Xbox; + + public static bool IsAdmin + { + get + { + if(!IsWindows) + return Environment.UserName == "root"; + + bool isAdmin; + WindowsIdentity user = null; + + try + { + user = WindowsIdentity.GetCurrent(); + var principal = new WindowsPrincipal(user); + isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator); + } + catch(UnauthorizedAccessException) + { + isAdmin = false; + } + catch(Exception) + { + isAdmin = false; + } + finally + { + user?.Dispose(); + } + + return isAdmin; + } + } + + [DllImport("libc", SetLastError = true)] + static extern int uname(out utsname name); + + [DllImport("libc", SetLastError = true, EntryPoint = "sysctlbyname", CharSet = CharSet.Ansi)] + static extern int OSX_sysctlbyname(string name, IntPtr oldp, IntPtr oldlenp, IntPtr newp, uint newlen); + + /// Gets the real platform ID, not the incomplete .NET framework one + /// Platform ID + /// Unhandled exception + public static PlatformID GetRealPlatformID() + { + if((int)Environment.OSVersion.Platform < 4 || + (int)Environment.OSVersion.Platform == 5) + return (PlatformID)(int)Environment.OSVersion.Platform; + + int error = uname(out utsname unixname); + + if(error != 0) + throw new Exception($"Unhandled exception calling uname: {Marshal.GetLastWin32Error()}"); + + switch(unixname.sysname) + { + // TODO: Differentiate Linux, Android, Tizen + case "Linux": + { + #if __ANDROID__ + return PlatformID.Android; + #else + return PlatformID.Linux; + #endif + } + + case "Darwin": + { + IntPtr pLen = Marshal.AllocHGlobal(sizeof(int)); + int osxError = OSX_sysctlbyname("hw.machine", IntPtr.Zero, pLen, IntPtr.Zero, 0); + + if(osxError != 0) + { + Marshal.FreeHGlobal(pLen); + + throw new Exception($"Unhandled exception calling uname: {Marshal.GetLastWin32Error()}"); + } + + int length = Marshal.ReadInt32(pLen); + IntPtr pStr = Marshal.AllocHGlobal(length); + osxError = OSX_sysctlbyname("hw.machine", pStr, pLen, IntPtr.Zero, 0); + + if(osxError != 0) + { + Marshal.FreeHGlobal(pStr); + Marshal.FreeHGlobal(pLen); + + throw new Exception($"Unhandled exception calling uname: {Marshal.GetLastWin32Error()}"); + } + + string machine = Marshal.PtrToStringAnsi(pStr); + + Marshal.FreeHGlobal(pStr); + Marshal.FreeHGlobal(pLen); + + if(machine != null && + (machine.StartsWith("iPad", StringComparison.Ordinal) || + machine.StartsWith("iPod", StringComparison.Ordinal) || + machine.StartsWith("iPhone", StringComparison.Ordinal))) + return PlatformID.iOS; + + return PlatformID.MacOSX; + } + + case "GNU": return PlatformID.Hurd; + case "FreeBSD": + case "GNU/kFreeBSD": return PlatformID.FreeBSD; + case "DragonFly": return PlatformID.DragonFly; + case "Haiku": return PlatformID.Haiku; + case "HP-UX": return PlatformID.HPUX; + case "AIX": return PlatformID.AIX; + case "OS400": return PlatformID.OS400; + case "IRIX": + case "IRIX64": return PlatformID.IRIX; + case "Minix": return PlatformID.Minix; + case "NetBSD": return PlatformID.NetBSD; + case "NONSTOP_KERNEL": return PlatformID.NonStop; + case "OpenBSD": return PlatformID.OpenBSD; + case "QNX": return PlatformID.QNX; + case "SINIX-Y": return PlatformID.SINIX; + case "SunOS": return PlatformID.Solaris; + case "OSF1": return PlatformID.Tru64; + case "ULTRIX": return PlatformID.Ultrix; + case "SCO_SV": return PlatformID.OpenServer; + case "UnixWare": return PlatformID.UnixWare; + case "Interix": + case "UWIN-W7": return PlatformID.Win32NT; + default: + { + if(unixname.sysname.StartsWith("CYGWIN_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("MINGW32_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("MSYS_NT", StringComparison.Ordinal) || + unixname.sysname.StartsWith("UWIN", StringComparison.Ordinal)) + return PlatformID.Win32NT; + + return PlatformID.Unknown; + } + } + } + + /// Gets a string for the current operating system REAL version (handles Darwin 1.4 and Windows 10 falsifying) + /// Current operating system version + public static string GetVersion() + { + string environ = Environment.OSVersion.Version.ToString(); + + switch(GetRealPlatformID()) + { + case PlatformID.MacOSX: + if(Environment.OSVersion.Version.Major != 1) + return $"10.{Environment.OSVersion.Version.Major - 4}.{Environment.OSVersion.Version.Minor}"; + + switch(Environment.OSVersion.Version.Minor) + { + case 3: return "10.0"; + case 4: return "10.1"; + } + + goto default; + case PlatformID.Win32NT: + // From Windows 8.1 the reported version is simply falsified... + if((Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Major >= 2) || + Environment.OSVersion.Version.Major > 6) + return FileVersionInfo. + GetVersionInfo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System), + "KERNEL32.DLL")).ProductVersion; + + return environ; + default: return environ; + } + } + + /// From a platform ID and version returns a human-readable version + /// Platform ID + /// Version number + /// Operating system name + public static string GetPlatformName(PlatformID id, string version = null) + { + switch(id) + { + case PlatformID.AIX: return "AIX"; + case PlatformID.Android: return "Android"; + case PlatformID.DragonFly: return "DragonFly BSD"; + case PlatformID.FreeBSD: return "FreeBSD"; + case PlatformID.Haiku: return "Haiku"; + case PlatformID.HPUX: return "HP/UX"; + case PlatformID.Hurd: return "Hurd"; + case PlatformID.iOS: return "iOS"; + case PlatformID.IRIX: return "IRIX"; + case PlatformID.Linux: + if(!File.Exists("/proc/version")) + return "Linux"; + + string s = File.ReadAllText("/proc/version"); + + return s.Contains("Microsoft") || s.Contains("WSL") ? "Windows Subsystem for Linux" : "Linux"; + + case PlatformID.MacOSX: + if(string.IsNullOrEmpty(version)) + return "macOS"; + + string[] pieces = version.Split('.'); + + if(pieces.Length < 2 || + !int.TryParse(pieces[1], out int minor)) + return "macOS"; + + if(minor >= 12) + return "macOS"; + + if(minor >= 8) + return "OS X"; + + return "Mac OS X"; + + case PlatformID.Minix: return "MINIX"; + case PlatformID.NetBSD: return "NetBSD"; + case PlatformID.NonStop: return "NonStop OS"; + case PlatformID.OpenBSD: return "OpenBSD"; + case PlatformID.OpenServer: return "SCO OpenServer"; + case PlatformID.OS400: return "OS/400"; + case PlatformID.PlayStation3: return "Sony CellOS"; + case PlatformID.PlayStation4: return "Sony Orbis OS"; + case PlatformID.QNX: return "QNX"; + case PlatformID.SINIX: return "SINIX"; + case PlatformID.Solaris: return "Sun Solaris"; + case PlatformID.Tizen: return "Samsung Tizen"; + case PlatformID.Tru64: return "Tru64 UNIX"; + case PlatformID.Ultrix: return "Ultrix"; + case PlatformID.Unix: return "UNIX"; + case PlatformID.UnixWare: return "SCO UnixWare"; + case PlatformID.Wii: return "Nintendo Wii"; + case PlatformID.WiiU: return "Nintendo Wii U"; + case PlatformID.Win32NT: + if(string.IsNullOrEmpty(version)) + return "Windows NT/2000/XP/Vista/7/10"; + + if(version.StartsWith("3.", StringComparison.Ordinal) || + version.StartsWith("4.", StringComparison.Ordinal)) + return "Windows NT"; + + if(version.StartsWith("5.0", StringComparison.Ordinal)) + return "Windows 2000"; + + if(version.StartsWith("5.1", StringComparison.Ordinal)) + return "Windows XP"; + + if(version.StartsWith("5.2", StringComparison.Ordinal)) + return "Windows 2003"; + + if(version.StartsWith("6.0", StringComparison.Ordinal)) + return "Windows Vista"; + + if(version.StartsWith("6.1", StringComparison.Ordinal)) + return "Windows 7"; + + if(version.StartsWith("6.2", StringComparison.Ordinal)) + return "Windows 8"; + + if(version.StartsWith("6.3", StringComparison.Ordinal)) + return "Windows 8.1"; + + if(version.StartsWith("10.0", StringComparison.Ordinal)) + return "Windows 10"; + + return "Windows NT/2000/XP/Vista/7/10"; + case PlatformID.Win32S: return "Windows 3.x with win32s"; + case PlatformID.Win32Windows: + if(string.IsNullOrEmpty(version)) + return "Windows 9x/Me"; + + if(version.StartsWith("4.0", StringComparison.Ordinal)) + return "Windows 95"; + + if(version.StartsWith("4.10.2222", StringComparison.Ordinal)) + return "Windows 98 SE"; + + if(version.StartsWith("4.1", StringComparison.Ordinal)) + return "Windows 98"; + + if(version.StartsWith("4.9", StringComparison.Ordinal)) + return "Windows Me"; + + return "Windows 9x/Me"; + case PlatformID.WinCE: return "Windows CE/Mobile"; + case PlatformID.WindowsPhone: return "Windows Phone"; + case PlatformID.Xbox: return "Xbox OS"; + case PlatformID.zOS: return "z/OS"; + default: return id.ToString(); + } + } + + /// POSIX uname structure, size from OSX, big enough to handle extra fields + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + struct utsname + { + /// System name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string sysname; + /// Node name + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string nodename; + /// Release level + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string release; + /// Version level + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string version; + /// Hardware level + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public readonly string machine; + } + } +} \ No newline at end of file diff --git a/RomRepoMgr.Core/Interop/PlatformID.cs b/RomRepoMgr.Core/Interop/PlatformID.cs new file mode 100644 index 0000000..0bdba92 --- /dev/null +++ b/RomRepoMgr.Core/Interop/PlatformID.cs @@ -0,0 +1,120 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : PlatformID.cs +// Author(s) : Natalia Portillo +// +// Component : Interop services. +// +// --[ Description ] ---------------------------------------------------------- +// +// Contains an enhanced PlatformID enumeration. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2020 Natalia Portillo +// ****************************************************************************/ + +using System.Diagnostics.CodeAnalysis; + +namespace Aaru.CommonTypes.Interop +{ + /// Contains an arbitrary list of OSes, even if .NET does not run on them + [SuppressMessage("ReSharper", "InconsistentNaming")] + public enum PlatformID + { + /// Win32s + Win32S = 0, + /// Win32 (Windows 9x) + Win32Windows = 1, + /// Windows NT + Win32NT = 2, + /// Windows Mobile + WinCE = 3, + /// UNIX (do not use, too generic) + Unix = 4, + /// Xbox 360 + Xbox = 5, + /// OS X + MacOSX = 6, + /// iOS is not OS X + iOS = 7, + /// Linux + Linux = 8, + /// Sun Solaris + Solaris = 9, + /// NetBSD + NetBSD = 10, + /// OpenBSD + OpenBSD = 11, + /// FreeBSD + FreeBSD = 12, + /// DragonFly BSD + DragonFly = 13, + /// Nintendo Wii + Wii = 14, + /// Nintendo Wii U + WiiU = 15, + /// Sony PlayStation 3 + PlayStation3 = 16, + /// Sony Playstation 4 + PlayStation4 = 17, + /// Google Android + Android = 18, + /// Samsung Tizen + Tizen = 19, + /// Windows Phone + WindowsPhone = 20, + /// GNU/Hurd + Hurd = 21, + /// Haiku + Haiku = 22, + /// HP-UX + HPUX = 23, + /// AIX + AIX = 24, + /// OS/400 + OS400 = 25, + /// IRIX + IRIX = 26, + /// Minix + Minix = 27, + /// NonStop + NonStop = 28, + /// QNX + QNX = 29, + /// SINIX + SINIX = 30, + /// Tru64 UNIX + Tru64 = 31, + /// Ultrix + Ultrix = 32, + /// SCO OpenServer / SCO UNIX + OpenServer = 33, + /// SCO UnixWare + UnixWare = 34, + /// IBM z/OS + zOS = 35, Unknown = -1 + } +} \ No newline at end of file diff --git a/RomRepoMgr.Core/Interop/Version.cs b/RomRepoMgr.Core/Interop/Version.cs new file mode 100644 index 0000000..3bd51cd --- /dev/null +++ b/RomRepoMgr.Core/Interop/Version.cs @@ -0,0 +1,86 @@ +// /*************************************************************************** +// Aaru Data Preservation Suite +// ---------------------------------------------------------------------------- +// +// Filename : Version.cs +// Author(s) : Natalia Portillo +// +// Component : Interop services. +// +// --[ Description ] ---------------------------------------------------------- +// +// Returns Aaru version. +// +// --[ License ] -------------------------------------------------------------- +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// ---------------------------------------------------------------------------- +// Copyright © 2011-2020 Natalia Portillo +// ****************************************************************************/ + +using System; +using System.Reflection; +using System.Runtime; + +namespace Aaru.CommonTypes.Interop +{ + public static class Version + { + /// Gets version string + /// Version + public static string GetVersion() => typeof(Version).Assembly.GetName().Version?.ToString(); + + public static string GetNetCoreVersion() + { + Assembly assembly = typeof(GCSettings).Assembly; + + string[] assemblyPath = assembly.CodeBase?.Split(new[] + { + '/', '\\' + }, StringSplitOptions.RemoveEmptyEntries); + + if(assemblyPath is null) + return null; + + int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App"); + + if(netCoreAppIndex > 0 && + netCoreAppIndex < assemblyPath.Length - 2) + return assemblyPath[netCoreAppIndex + 1]; + + return null; + } + + public static string GetMonoVersion() + { + if(!DetectOS.IsMono) + return null; + + MethodInfo monoDisplayName = Type.GetType("Mono.Runtime")?. + GetMethod("GetDisplayName", BindingFlags.NonPublic | BindingFlags.Static); + + if(monoDisplayName != null) + return (string)monoDisplayName.Invoke(null, null); + + return null; + } + } +} \ No newline at end of file diff --git a/RomRepoMgr.Core/RomRepoMgr.Core.csproj b/RomRepoMgr.Core/RomRepoMgr.Core.csproj new file mode 100644 index 0000000..57ce2a0 --- /dev/null +++ b/RomRepoMgr.Core/RomRepoMgr.Core.csproj @@ -0,0 +1,11 @@ + + + + netcoreapp3.1 + + + + + + + diff --git a/RomRepoMgr.Settings/RomRepoMgr.Settings.csproj b/RomRepoMgr.Settings/RomRepoMgr.Settings.csproj new file mode 100644 index 0000000..55095ea --- /dev/null +++ b/RomRepoMgr.Settings/RomRepoMgr.Settings.csproj @@ -0,0 +1,16 @@ + + + + netcoreapp3.1 + + + + + + + + + + + + diff --git a/RomRepoMgr.Settings/Settings.cs b/RomRepoMgr.Settings/Settings.cs new file mode 100644 index 0000000..fe8a1f5 --- /dev/null +++ b/RomRepoMgr.Settings/Settings.cs @@ -0,0 +1,309 @@ +/****************************************************************************** +// RomRepoMgr - ROM repository manager +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ License ] -------------------------------------------------------------- +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// ---------------------------------------------------------------------------- +// Copyright © 2020 Natalia Portillo +*******************************************************************************/ + +using System; +using System.IO; +using System.Text.Json; +using Aaru.CommonTypes.Interop; +using Claunia.PropertyList; +using Microsoft.Win32; +using PlatformID = Aaru.CommonTypes.Interop.PlatformID; + +namespace RomRepoMgr.Settings +{ + public sealed class SetSettings + { + public string DatabasePath { get; set; } + public string RepositoryPath { get; set; } + public string TemporaryFolder { get; set; } + public string UnArchiverPath { get; set; } + } + + /// Manages statistics + public static class Settings + { + const string XDG_CONFIG_HOME = "XDG_CONFIG_HOME"; + const string XDG_CONFIG_HOME_RESOLVED = ".config"; + /// Current statistcs + public static SetSettings Current; + + /// Loads settings + public static void LoadSettings() + { + Current = new SetSettings(); + PlatformID ptId = DetectOS.GetRealPlatformID(); + string homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + FileStream prefsFs = null; + StreamReader prefsSr = null; + + try + { + switch(ptId) + { + // In case of macOS or iOS settings will be saved in ~/Library/Preferences/com.claunia.romrepomgr.plist + case PlatformID.MacOSX: + case PlatformID.iOS: + { + string preferencesPath = + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", + "Preferences"); + + string preferencesFilePath = Path.Combine(preferencesPath, "com.claunia.romrepomgr.plist"); + + if(!File.Exists(preferencesFilePath)) + { + SetDefaultSettings(); + SaveSettings(); + } + + prefsFs = new FileStream(preferencesFilePath, FileMode.Open, FileAccess.Read); + + var parsedPreferences = (NSDictionary)BinaryPropertyListParser.Parse(prefsFs); + + if(parsedPreferences != null) + { + NSObject obj; + + Current.DatabasePath = parsedPreferences.TryGetValue("DatabasePath", out obj) + ? ((NSString)obj).ToString() : null; + + Current.RepositoryPath = parsedPreferences.TryGetValue("RepositoryPath", out obj) + ? ((NSString)obj).ToString() : null; + + Current.TemporaryFolder = parsedPreferences.TryGetValue("TemporaryFolder", out obj) + ? ((NSString)obj).ToString() : null; + + Current.UnArchiverPath = parsedPreferences.TryGetValue("UnArchiverPath", out obj) + ? ((NSString)obj).ToString() : null; + + prefsFs.Close(); + } + else + { + prefsFs.Close(); + + SetDefaultSettings(); + SaveSettings(); + } + } + + break; + #if !NETSTANDARD2_0 + + // In case of Windows settings will be saved in the registry: HKLM/SOFTWARE/Claunia.com/RomRepoMgr + case PlatformID.Win32NT: + case PlatformID.Win32S: + case PlatformID.Win32Windows: + case PlatformID.WinCE: + case PlatformID.WindowsPhone: + { + RegistryKey parentKey = Registry.CurrentUser.OpenSubKey("SOFTWARE")?.OpenSubKey("Claunia.com"); + + if(parentKey == null) + { + SetDefaultSettings(); + SaveSettings(); + + return; + } + + RegistryKey key = parentKey.OpenSubKey("RomRepoMgr"); + + if(key == null) + { + SetDefaultSettings(); + SaveSettings(); + + return; + } + + Current.DatabasePath = key.GetValue("DatabasePath") as string; + Current.RepositoryPath = key.GetValue("RepositoryPath") as string; + Current.TemporaryFolder = key.GetValue("TemporaryFolder") as string; + Current.UnArchiverPath = key.GetValue("UnArchiverPath") as string; + } + + break; + #endif + + // Otherwise, settings will be saved in ~/.config/RomRepoMgr.json + default: + { + string xdgConfigPath = + Path.Combine(homePath, + Environment.GetEnvironmentVariable(XDG_CONFIG_HOME) ?? + XDG_CONFIG_HOME_RESOLVED); + + string settingsPath = Path.Combine(xdgConfigPath, "RomRepoMgr.json"); + + if(!File.Exists(settingsPath)) + { + SetDefaultSettings(); + SaveSettings(); + + return; + } + + prefsSr = new StreamReader(settingsPath); + + Current = JsonSerializer.Deserialize(prefsSr.ReadToEnd(), new JsonSerializerOptions + { + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip, + WriteIndented = true + }); + } + + break; + } + } + catch + { + prefsFs?.Close(); + prefsSr?.Close(); + SetDefaultSettings(); + SaveSettings(); + } + } + + public static void SaveSettings() + { + try + { + PlatformID ptId = DetectOS.GetRealPlatformID(); + + switch(ptId) + { + // In case of macOS or iOS settings will be saved in ~/Library/Preferences/com.claunia.romrepomgr.plist + case PlatformID.MacOSX: + case PlatformID.iOS: + { + var root = new NSDictionary + { + { + "DatabasePath", Current.DatabasePath + }, + { + "RepositoryPath", Current.RepositoryPath + }, + { + "TemporaryFolder", Current.TemporaryFolder + }, + { + "UnArchiverPath", Current.UnArchiverPath + } + }; + + string preferencesPath = + Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", + "Preferences"); + + string preferencesFilePath = Path.Combine(preferencesPath, "com.claunia.romrepomgr.plist"); + + var fs = new FileStream(preferencesFilePath, FileMode.Create); + BinaryPropertyListWriter.Write(fs, root); + fs.Close(); + } + + break; + #if !NETSTANDARD2_0 + + // In case of Windows settings will be saved in the registry: HKLM/SOFTWARE/Claunia.com/RomRepoMgr + case PlatformID.Win32NT: + case PlatformID.Win32S: + case PlatformID.Win32Windows: + case PlatformID.WinCE: + case PlatformID.WindowsPhone: + { + RegistryKey parentKey = Registry.CurrentUser.OpenSubKey("SOFTWARE", true)?. + CreateSubKey("Claunia.com"); + + RegistryKey key = parentKey?.CreateSubKey("RomRepoMgr"); + + key?.SetValue("DatabasePath", Current.DatabasePath); + key?.SetValue("RepositoryPath", Current.RepositoryPath); + key?.SetValue("TemporaryFolder", Current.TemporaryFolder); + key?.SetValue("UnArchiverPath", Current.UnArchiverPath); + } + + break; + #endif + + // Otherwise, settings will be saved in ~/.config/RomRepoMgr.json + default: + { + string homePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + string xdgConfigPath = + Path.Combine(homePath, + Environment.GetEnvironmentVariable(XDG_CONFIG_HOME) ?? + XDG_CONFIG_HOME_RESOLVED); + + string settingsPath = Path.Combine(xdgConfigPath, "RomRepoMgr.json"); + + if(!Directory.Exists(xdgConfigPath)) + Directory.CreateDirectory(xdgConfigPath); + + var prefsSr = new StreamWriter(settingsPath); + + prefsSr.Write(JsonSerializer.Serialize(Current, new JsonSerializerOptions + { + AllowTrailingCommas = true, + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip, + WriteIndented = true + })); + + prefsSr.Close(); + } + + break; + } + } + #pragma warning disable RECS0022 // A catch clause that catches System.Exception and has an empty body + catch + { + // ignored + } + #pragma warning restore RECS0022 // A catch clause that catches System.Exception and has an empty body + } + + /// Sets default settings as all statistics, share everything + static void SetDefaultSettings() + { + string docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + string dataPath = Path.Combine(docsPath, "RomRepoMgr"); + + Current = new SetSettings + { + DatabasePath = Path.Combine(dataPath, "romrepo.db"), + RepositoryPath = Path.Combine(dataPath, "repo"), + TemporaryFolder = Path.GetTempPath() + }; + } + } +} \ No newline at end of file diff --git a/RomRepoMgr.sln b/RomRepoMgr.sln index 53f794c..8c0b7e3 100644 --- a/RomRepoMgr.sln +++ b/RomRepoMgr.sln @@ -4,6 +4,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RomRepoMgr", "RomRepoMgr\Ro EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RomRepoMgr.Database", "RomRepoMgr.Database\RomRepoMgr.Database.csproj", "{FE5ACD61-90F1-4B9F-9BDA-50934040882A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RomRepoMgr.Settings", "RomRepoMgr.Settings\RomRepoMgr.Settings.csproj", "{FEAC8090-8F64-44D4-9DE2-C9E6CEDB4FC5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RomRepoMgr.Core", "RomRepoMgr.Core\RomRepoMgr.Core.csproj", "{1C7E7286-1BA6-43B0-A042-4A3C378BDDC1}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -18,5 +22,13 @@ Global {FE5ACD61-90F1-4B9F-9BDA-50934040882A}.Debug|Any CPU.Build.0 = Debug|Any CPU {FE5ACD61-90F1-4B9F-9BDA-50934040882A}.Release|Any CPU.ActiveCfg = Release|Any CPU {FE5ACD61-90F1-4B9F-9BDA-50934040882A}.Release|Any CPU.Build.0 = Release|Any CPU + {FEAC8090-8F64-44D4-9DE2-C9E6CEDB4FC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FEAC8090-8F64-44D4-9DE2-C9E6CEDB4FC5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FEAC8090-8F64-44D4-9DE2-C9E6CEDB4FC5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FEAC8090-8F64-44D4-9DE2-C9E6CEDB4FC5}.Release|Any CPU.Build.0 = Release|Any CPU + {1C7E7286-1BA6-43B0-A042-4A3C378BDDC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1C7E7286-1BA6-43B0-A042-4A3C378BDDC1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1C7E7286-1BA6-43B0-A042-4A3C378BDDC1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1C7E7286-1BA6-43B0-A042-4A3C378BDDC1}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal