diff --git a/WPinternals/App.xaml.cs b/WPinternals/App.xaml.cs index d8283bb..653753d 100644 --- a/WPinternals/App.xaml.cs +++ b/WPinternals/App.xaml.cs @@ -22,6 +22,8 @@ using System.IO; using System.Threading; using System.Windows; +using WPinternals.HelperClasses; +using WPinternals.Config; namespace WPinternals { diff --git a/WPinternals/CommandLine.cs b/WPinternals/CommandLine.cs index 622c229..f280b44 100644 --- a/WPinternals/CommandLine.cs +++ b/WPinternals/CommandLine.cs @@ -26,6 +26,12 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; +using WPinternals.Config; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/Config/EmergencyFileEntry.cs b/WPinternals/Config/EmergencyFileEntry.cs new file mode 100644 index 0000000..c643d75 --- /dev/null +++ b/WPinternals/Config/EmergencyFileEntry.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System.IO; +using System.Xml.Serialization; +using WPinternals.HelperClasses; + +namespace WPinternals.Config +{ + public class EmergencyFileEntry + { + public string Type; + + [XmlIgnore] + public byte[] RKH; + [XmlElement(ElementName = "RKH")] + public string RKHAsString + { + get + { + return RKH == null ? null : Converter.ConvertHexToString(RKH, ""); + } + set + { + RKH = value == null ? null : Converter.ConvertStringToHex(value); + } + } + + public string ProgrammerPath; + public string PayloadPath; + + internal bool ProgrammerExists() + { + return File.Exists(ProgrammerPath); + } + + internal bool PayloadExists() + { + return File.Exists(PayloadPath); + } + } +} diff --git a/WPinternals/Models/PhoneInfo/CommonPhoneInfo.cs b/WPinternals/Config/FFUEntry.cs similarity index 69% rename from WPinternals/Models/PhoneInfo/CommonPhoneInfo.cs rename to WPinternals/Config/FFUEntry.cs index d2b85ae..1ae15c3 100644 --- a/WPinternals/Models/PhoneInfo/CommonPhoneInfo.cs +++ b/WPinternals/Config/FFUEntry.cs @@ -18,23 +18,20 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace WPinternals +using System.IO; + +namespace WPinternals.Config { - internal class CommonPhoneInfo + public class FFUEntry { - public PhoneInfoState State = PhoneInfoState.Empty; - - public FlashAppType App; - - public byte VersionMajor; - public byte VersionMinor; - public byte ProtocolVersionMajor; - public byte ProtocolVersionMinor; + public string PlatformID; + public string FirmwareVersion; + public string OSVersion; + public string Path; - internal void Log(LogType Type) + internal bool Exists() { - LogFile.Log($"App: {VersionMajor}.{VersionMinor}", Type); - LogFile.Log($"Protocol: {ProtocolVersionMajor}.{ProtocolVersionMinor}", Type); + return File.Exists(Path); } } } diff --git a/WPinternals/Config/FlashProfile.cs b/WPinternals/Config/FlashProfile.cs new file mode 100644 index 0000000..f3025d3 --- /dev/null +++ b/WPinternals/Config/FlashProfile.cs @@ -0,0 +1,75 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System; +using System.Xml.Serialization; + +namespace WPinternals.Config +{ + public class FlashProfile + { + public string Type; + public string PlatformID; + public string ProductCode; + public string PhoneFirmware; + public string FfuFirmware; + + [XmlIgnore] + internal uint FillSize; + [XmlIgnore] + internal uint HeaderSize; + [XmlIgnore] + internal bool AssumeImageHeaderFallsInGap; + [XmlIgnore] + internal bool AllocateAsyncBuffersOnPhone; + + [XmlElement(ElementName = "Profile")] + public string ProfileAsString + { + get + { + byte[] ValueBuffer = new byte[10]; + ValueBuffer[0] = 1; // Profile version + ByteOperations.WriteUInt32(ValueBuffer, 1, FillSize); + ByteOperations.WriteUInt32(ValueBuffer, 5, HeaderSize); + if (AssumeImageHeaderFallsInGap) + { + ValueBuffer[9] |= 1; + } + + if (AllocateAsyncBuffersOnPhone) + { + ValueBuffer[9] |= 2; + } + + return Convert.ToBase64String(ValueBuffer); + } + set + { + byte[] ValueBuffer = Convert.FromBase64String(value); + byte Version = ValueBuffer[0]; + FillSize = ByteOperations.ReadUInt32(ValueBuffer, 1); + HeaderSize = ByteOperations.ReadUInt32(ValueBuffer, 5); + AssumeImageHeaderFallsInGap = (ValueBuffer[9] & 1) != 0; + AllocateAsyncBuffersOnPhone = (ValueBuffer[9] & 2) != 0; + } + } + } +} diff --git a/WPinternals/Config/Registration.cs b/WPinternals/Config/Registration.cs new file mode 100644 index 0000000..ea9f39a --- /dev/null +++ b/WPinternals/Config/Registration.cs @@ -0,0 +1,84 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Windows; + +namespace WPinternals.Config +{ + internal static class Registration + { +#if PREVIEW + internal const bool IsPrerelease = true; +#else + internal const bool IsPrerelease = false; +#endif + + internal static readonly DateTime ExpirationDate = new(2024, 12, 21); + + internal static void CheckExpiration() + { +#if PREVIEW + //if (IsPrerelease && (DateTime.Now >= ExpirationDate)) + if (DateTime.Now >= ExpirationDate) + { + if (Environment.GetCommandLineArgs().Count() > 1) + { + Console.WriteLine("This prerelease version is expired!"); + CommandLine.CloseConsole(); + } + else + MessageBox.Show("This prerelease version is expired!", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation); + Environment.Exit(0); + } +#endif + } + + internal static bool IsRegistered() + { + bool Result = false; + if (App.Config.RegistrationName != null) + { + Result = CalcRegKey() == App.Config.RegistrationKey; + } + return Result; + } + + internal static string CalcRegKey() + { + string KeyBase = App.Config.RegistrationName; + if (Environment.MachineName == null) + { + KeyBase += "-Unknown"; + } + else + { + KeyBase += "-" + Environment.MachineName; + } + + byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(KeyBase); + SHA1Managed sha = new(); + byte[] Key = sha.ComputeHash(KeyBytes); + return Convert.ToBase64String(Key); + } + } +} diff --git a/WPinternals/Config/SecWimEntry.cs b/WPinternals/Config/SecWimEntry.cs new file mode 100644 index 0000000..f5eab27 --- /dev/null +++ b/WPinternals/Config/SecWimEntry.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System.IO; + +namespace WPinternals.Config +{ + public class SecWimEntry + { + public string FirmwareVersion; + public string Path; + + internal bool Exists() + { + return File.Exists(Path); + } + } +} diff --git a/WPinternals/WPinternalsConfig.cs b/WPinternals/Config/WPinternalsConfig.cs similarity index 64% rename from WPinternals/WPinternalsConfig.cs rename to WPinternals/Config/WPinternalsConfig.cs index 4181fac..0de38c0 100644 --- a/WPinternals/WPinternalsConfig.cs +++ b/WPinternals/Config/WPinternalsConfig.cs @@ -22,68 +22,11 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Security.Cryptography; -using System.Windows; using System.Xml.Serialization; +using WPinternals.HelperClasses; -namespace WPinternals +namespace WPinternals.Config { - internal static class Registration - { -#if PREVIEW - internal const bool IsPrerelease = true; -#else - internal const bool IsPrerelease = false; -#endif - - internal static readonly DateTime ExpirationDate = new(2024, 12, 21); - - internal static void CheckExpiration() - { -#if PREVIEW - //if (IsPrerelease && (DateTime.Now >= ExpirationDate)) - if (DateTime.Now >= ExpirationDate) - { - if (Environment.GetCommandLineArgs().Count() > 1) - { - Console.WriteLine("This prerelease version is expired!"); - CommandLine.CloseConsole(); - } - else - MessageBox.Show("This prerelease version is expired!", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation); - Environment.Exit(0); - } -#endif - } - - internal static bool IsRegistered() - { - bool Result = false; - if (App.Config.RegistrationName != null) - { - Result = CalcRegKey() == App.Config.RegistrationKey; - } - return Result; - } - - internal static string CalcRegKey() - { - string KeyBase = App.Config.RegistrationName; - if (Environment.MachineName == null) - { - KeyBase += "-Unknown"; - } - else - { - KeyBase += "-" + Environment.MachineName; - } - - byte[] KeyBytes = System.Text.Encoding.UTF8.GetBytes(KeyBase); - SHA1Managed sha = new(); - byte[] Key = sha.ComputeHash(KeyBytes); - return Convert.ToBase64String(Key); - } - } public class WPinternalsConfig { @@ -122,7 +65,7 @@ internal void WriteConfig() FileWriter.Close(); } - internal void SetProfile(string Type, string PlatformID, string ProductCode, string PhoneFirmware, string FfuFirmware, UInt32 FillSize, UInt32 HeaderSize, bool AssumeImageHeaderFallsInGap, bool AllocateAsyncBuffersOnPhone) + internal void SetProfile(string Type, string PlatformID, string ProductCode, string PhoneFirmware, string FfuFirmware, uint FillSize, uint HeaderSize, bool AssumeImageHeaderFallsInGap, bool AllocateAsyncBuffersOnPhone) { FlashProfile Profile = GetProfile(PlatformID, PhoneFirmware, FfuFirmware); if (Profile == null) @@ -148,7 +91,7 @@ internal void SetProfile(string Type, string PlatformID, string ProductCode, str internal FlashProfile GetProfile(string PlatformID, string PhoneFirmware, string FfuFirmware = null) { - return FlashProfiles.Find(p => string.Equals(p.PlatformID, PlatformID, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PhoneFirmware, PhoneFirmware, StringComparison.CurrentCultureIgnoreCase) && ((FfuFirmware == null) || string.Equals(p.FfuFirmware, FfuFirmware, StringComparison.CurrentCultureIgnoreCase))); + return FlashProfiles.Find(p => string.Equals(p.PlatformID, PlatformID, StringComparison.CurrentCultureIgnoreCase) && string.Equals(p.PhoneFirmware, PhoneFirmware, StringComparison.CurrentCultureIgnoreCase) && (FfuFirmware == null || string.Equals(p.FfuFirmware, FfuFirmware, StringComparison.CurrentCultureIgnoreCase))); } public List FlashProfiles = []; @@ -168,7 +111,7 @@ internal void AddFfuToRepository(string FFUPath) internal void AddFfuToRepository(string FFUPath, string PlatformID, string FirmwareVersion, string OSVersion) { - FFUEntry Entry = FFURepository.Find(e => (e.PlatformID == PlatformID) && (e.FirmwareVersion == FirmwareVersion) && string.Equals(e.Path, FFUPath, StringComparison.CurrentCultureIgnoreCase)); + FFUEntry Entry = FFURepository.Find(e => e.PlatformID == PlatformID && e.FirmwareVersion == FirmwareVersion && string.Equals(e.Path, FFUPath, StringComparison.CurrentCultureIgnoreCase)); if (Entry == null) { LogFile.Log("Adding FFU to repository: " + FFUPath, LogType.FileAndConsole); @@ -222,7 +165,7 @@ internal void RemoveFfuFromRepository(string FFUPath) internal void AddSecWimToRepository(string SecWimPath, string FirmwareVersion) { - SecWimEntry Entry = SecWimRepository.Find(e => (e.FirmwareVersion == FirmwareVersion) && string.Equals(e.Path, SecWimPath, StringComparison.CurrentCultureIgnoreCase)); + SecWimEntry Entry = SecWimRepository.Find(e => e.FirmwareVersion == FirmwareVersion && string.Equals(e.Path, SecWimPath, StringComparison.CurrentCultureIgnoreCase)); if (Entry == null) { LogFile.Log("Adding Secure WIM to repository: " + SecWimPath, LogType.FileAndConsole); @@ -270,8 +213,8 @@ internal void RemoveSecWimFromRepository(string SecWimPath) internal void AddEmergencyToRepository(string Type, string ProgrammerPath, string PayloadPath) { - EmergencyFileEntry Entry = EmergencyRepository.Find(e => (e.Type == Type) && string.Equals(e.ProgrammerPath, ProgrammerPath, StringComparison.CurrentCultureIgnoreCase)); - if ((Entry != null) && (PayloadPath != null) && (!string.Equals(Entry.PayloadPath, PayloadPath, StringComparison.CurrentCultureIgnoreCase))) + EmergencyFileEntry Entry = EmergencyRepository.Find(e => e.Type == Type && string.Equals(e.ProgrammerPath, ProgrammerPath, StringComparison.CurrentCultureIgnoreCase)); + if (Entry != null && PayloadPath != null && !string.Equals(Entry.PayloadPath, PayloadPath, StringComparison.CurrentCultureIgnoreCase)) { LogFile.Log("Updating emergency payload path in repository: " + PayloadPath, LogType.FileAndConsole); Entry.PayloadPath = PayloadPath; @@ -326,111 +269,4 @@ internal void RemoveEmergencyFromRepository(string ProgrammerPath) public string RegistrationTelegramID; public string RegistrationKey; } - - public class FlashProfile - { - public string Type; - public string PlatformID; - public string ProductCode; - public string PhoneFirmware; - public string FfuFirmware; - - [XmlIgnore] - internal UInt32 FillSize; - [XmlIgnore] - internal UInt32 HeaderSize; - [XmlIgnore] - internal bool AssumeImageHeaderFallsInGap; - [XmlIgnore] - internal bool AllocateAsyncBuffersOnPhone; - - [XmlElement(ElementName = "Profile")] - public string ProfileAsString - { - get - { - byte[] ValueBuffer = new byte[10]; - ValueBuffer[0] = 1; // Profile version - ByteOperations.WriteUInt32(ValueBuffer, 1, FillSize); - ByteOperations.WriteUInt32(ValueBuffer, 5, HeaderSize); - if (AssumeImageHeaderFallsInGap) - { - ValueBuffer[9] |= 1; - } - - if (AllocateAsyncBuffersOnPhone) - { - ValueBuffer[9] |= 2; - } - - return Convert.ToBase64String(ValueBuffer); - } - set - { - byte[] ValueBuffer = Convert.FromBase64String(value); - byte Version = ValueBuffer[0]; - FillSize = ByteOperations.ReadUInt32(ValueBuffer, 1); - HeaderSize = ByteOperations.ReadUInt32(ValueBuffer, 5); - AssumeImageHeaderFallsInGap = (ValueBuffer[9] & 1) != 0; - AllocateAsyncBuffersOnPhone = (ValueBuffer[9] & 2) != 0; - } - } - } - - public class FFUEntry - { - public string PlatformID; - public string FirmwareVersion; - public string OSVersion; - public string Path; - - internal bool Exists() - { - return File.Exists(Path); - } - } - - public class SecWimEntry - { - public string FirmwareVersion; - public string Path; - - internal bool Exists() - { - return File.Exists(Path); - } - } - - public class EmergencyFileEntry - { - public string Type; - - [XmlIgnore] - public byte[] RKH; - [XmlElement(ElementName = "RKH")] - public string RKHAsString - { - get - { - return RKH == null ? null : Converter.ConvertHexToString(RKH, ""); - } - set - { - RKH = value == null ? null : Converter.ConvertStringToHex(value); - } - } - - public string ProgrammerPath; - public string PayloadPath; - - internal bool ProgrammerExists() - { - return File.Exists(ProgrammerPath); - } - - internal bool PayloadExists() - { - return File.Exists(PayloadPath); - } - } } diff --git a/WPinternals/FilePickerControl.xaml.cs b/WPinternals/FilePickerControl.xaml.cs index 9cccdb6..53f0059 100644 --- a/WPinternals/FilePickerControl.xaml.cs +++ b/WPinternals/FilePickerControl.xaml.cs @@ -24,6 +24,7 @@ using System.Threading; using System.Windows; using System.Windows.Media; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/HelperClasses.cs b/WPinternals/HelperClasses.cs deleted file mode 100644 index ba11ded..0000000 --- a/WPinternals/HelperClasses.cs +++ /dev/null @@ -1,2354 +0,0 @@ -// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda -// -// 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. -// -// Some of the classes and functions in this file were found online. -// Where possible the original authors are referenced. - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Linq; -using System.Net; -using System.Reflection; -using System.Text; -using System.Threading; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media.Animation; -using System.Windows.Media.Imaging; -using System.Windows.Threading; - -namespace WPinternals -{ - internal delegate void SetWorkingStatus(string Message, string SubMessage = null, ulong? MaxProgressValue = null, bool ShowAnimation = true, WPinternalsStatus Status = WPinternalsStatus.Undefined); - internal delegate void UpdateWorkingStatus(string Message, string SubMessage = null, ulong? CurrentProgressValue = null, WPinternalsStatus Status = WPinternalsStatus.Undefined); - internal delegate void ExitSuccess(string Message, string SubMessage = null); - internal delegate void ExitFailure(string Message, string SubMessage = null); - - internal enum WPinternalsStatus - { - Undefined, - Scanning, - Flashing, - Patching, - WaitingForManualReset, - SwitchingMode, - Initializing - }; - - public class BooleanConverter : DependencyObject, IValueConverter - { - public static readonly DependencyProperty OnTrueProperty = - DependencyProperty.Register("OnTrue", typeof(object), typeof(BooleanConverter), - new PropertyMetadata(default(object))); - - public static readonly DependencyProperty OnFalseProperty = - DependencyProperty.Register("OnFalse", typeof(object), typeof(BooleanConverter), - new PropertyMetadata(default(object))); - - public static readonly DependencyProperty OnNullProperty = - DependencyProperty.Register("OnNull", typeof(object), typeof(BooleanConverter), - new PropertyMetadata(default(object))); - - public object OnTrue - { - get { return GetValue(OnTrueProperty); } - set { SetValue(OnTrueProperty, value); } - } - - public object OnFalse - { - get { return GetValue(OnFalseProperty); } - set { SetValue(OnFalseProperty, value); } - } - - public object OnNull - { - get { return GetValue(OnNullProperty); } - set { SetValue(OnNullProperty, value); } - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - return value == null - ? OnNull ?? Default(targetType) - : (string.Equals(value.ToString(), false.ToString(), StringComparison.CurrentCultureIgnoreCase) - ? OnFalse - : OnTrue); - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == OnNull) - { - return Default(targetType); - } - - if (value == OnFalse) - { - return false; - } - - if (value == OnTrue) - { - return true; - } - - if (value == null) - { - return null; - } - - if (OnNull != null && - string.Equals(value.ToString(), OnNull.ToString(), StringComparison.CurrentCultureIgnoreCase)) - { - return Default(targetType); - } - - if (OnFalse != null && - string.Equals(value.ToString(), OnFalse.ToString(), StringComparison.CurrentCultureIgnoreCase)) - { - return false; - } - - if (OnTrue != null && - string.Equals(value.ToString(), OnTrue.ToString(), StringComparison.CurrentCultureIgnoreCase)) - { - return true; - } - - return null; - } - - public static object Default(Type type) - { - return type.IsValueType ? Activator.CreateInstance(type) : null; - } - } - - public class HexConverter : DependencyObject, IValueConverter - { - public static readonly DependencyProperty SeparatorProperty = - DependencyProperty.Register("OnTrue", typeof(object), typeof(HexConverter), - new PropertyMetadata(" ")); - - public object Separator - { - get { return GetValue(SeparatorProperty); } - set { SetValue(SeparatorProperty, value); } - } - - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value is byte[] bytes) - { - StringBuilder s = new(1000); - for (int i = bytes.GetLowerBound(0); i <= bytes.GetUpperBound(0); i++) - { - if (i != bytes.GetLowerBound(0)) - { - s.Append(Separator); - } - - s.Append(bytes[i].ToString("X2")); - } - return s.ToString(); - } - else - { - return ""; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - - public static object Default(Type type) - { - return type.IsValueType ? Activator.CreateInstance(type) : null; - } - } - - public class ObjectToVisibilityConverter : DependencyObject, IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return "Collapsed"; - } - else - { - return "Visible"; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - - public static object Default(Type type) - { - return type.IsValueType ? Activator.CreateInstance(type) : null; - } - } - - public class InverseObjectToVisibilityConverter : DependencyObject, IValueConverter - { - public object Convert(object value, Type targetType, object parameter, CultureInfo culture) - { - if (value == null) - { - return "Visible"; - } - else - { - return "Collapsed"; - } - } - - public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) - { - throw new NotImplementedException(); - } - - public static object Default(Type type) - { - return type.IsValueType ? Activator.CreateInstance(type) : null; - } - } - - internal class CollapsibleRun : Run - { - private string CollapsibleText; - - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - - CollapsibleText = Text; - } - - public Boolean IsVisible - { - get - { - return (Boolean)this.GetValue(IsVisibleProperty); - } - set - { - this.SetValue(IsVisibleProperty, value); - } - } - public static readonly DependencyProperty IsVisibleProperty = DependencyProperty.Register( - "IsVisible", typeof(Boolean), typeof(CollapsibleRun), new PropertyMetadata(true, IsVisibleChanged)); - public static void IsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - ((CollapsibleRun)d).Text = (bool)e.NewValue ? ((CollapsibleRun)d).CollapsibleText : String.Empty; - } - } - - internal class CollapsibleSection : Section - { - public CollapsibleSection() - { - CollapsibleBlocks = []; - } - - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - - foreach (Block Block in Blocks) - { - CollapsibleBlocks.Add(Block); - } - - Blocks.Clear(); - } - - public List CollapsibleBlocks { get; } - - public Boolean IsCollapsed - { - get - { - return (Boolean)this.GetValue(IsCollapsedProperty); - } - set - { - this.SetValue(IsCollapsedProperty, value); - - Blocks.Clear(); - - if (IsInitialized && !value) - { - foreach (Block Block in CollapsibleBlocks) - { - Blocks.Add(Block); - } - } - } - } - public static readonly DependencyProperty IsCollapsedProperty = DependencyProperty.Register( - "IsCollapsed", typeof(Boolean), typeof(CollapsibleSection), new PropertyMetadata(false)); - } - - // Overloaded Paragraph class to remove empty Run-elements, caused by auto-formatting new-lines in the XAML - // Use local:Paragraph in a FlowDocument - // This correction only works at run-time - public class Paragraph : System.Windows.Documents.Paragraph - { - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - int inlinesCount = this.Inlines.Count; - for (int i = 0; i < inlinesCount; i++) - { - Inline inline = this.Inlines.ElementAt(i); - if (inline is Run run) - { - if (run.Text == Convert.ToChar(32).ToString()) //ACSII 32 is the white space - { - run.Text = string.Empty; - } - } - } - } - } - - internal class ArrivalEventArgs : EventArgs - { - public PhoneInterfaces NewInterface; - public IDisposable NewModel; - - public ArrivalEventArgs(PhoneInterfaces NewInterface, IDisposable NewModel) - : base() - { - this.NewInterface = NewInterface; - this.NewModel = NewModel; - } - } - - internal static class BigEndian - { - public static byte[] GetBytes(object Value) - { - byte[] Bytes; - if (Value is short) - { - Bytes = BitConverter.GetBytes((short)Value); - } - else if (Value is ushort) - { - Bytes = BitConverter.GetBytes((ushort)Value); - } - else if (Value is int) - { - Bytes = BitConverter.GetBytes((int)Value); - } - else - { - Bytes = Value is uint ? BitConverter.GetBytes((uint)Value) : throw new NotSupportedException(); - } - - byte[] Result = new byte[Bytes.Length]; - for (int i = 0; i < Bytes.Length; i++) - { - Result[i] = Bytes[Bytes.Length - 1 - i]; - } - - return Result; - } - - public static byte[] GetBytes(object Value, int Width) - { - byte[] Result; - byte[] BigEndianBytes = GetBytes(Value); - if (BigEndianBytes.Length == Width) - { - return BigEndianBytes; - } - else if (BigEndianBytes.Length > Width) - { - Result = new byte[Width]; - Buffer.BlockCopy(BigEndianBytes, BigEndianBytes.Length - Width, Result, 0, Width); - return Result; - } - else - { - Result = new byte[Width]; - Buffer.BlockCopy(BigEndianBytes, 0, Result, Width - BigEndianBytes.Length, BigEndianBytes.Length); - return Result; - } - } - - public static UInt16 ToUInt16(byte[] Buffer, int Offset) - { - byte[] Bytes = new byte[2]; - for (int i = 0; i < 2; i++) - { - Bytes[i] = Buffer[Offset + 1 - i]; - } - - return BitConverter.ToUInt16(Bytes, 0); - } - - public static Int16 ToInt16(byte[] Buffer, int Offset) - { - byte[] Bytes = new byte[2]; - for (int i = 0; i < 2; i++) - { - Bytes[i] = Buffer[Offset + 1 - i]; - } - - return BitConverter.ToInt16(Bytes, 0); - } - - public static UInt32 ToUInt32(byte[] Buffer, int Offset) - { - byte[] Bytes = new byte[4]; - for (int i = 0; i < 4; i++) - { - Bytes[i] = Buffer[Offset + 3 - i]; - } - - return BitConverter.ToUInt32(Bytes, 0); - } - - public static Int32 ToInt32(byte[] Buffer, int Offset) - { - byte[] Bytes = new byte[4]; - for (int i = 0; i < 4; i++) - { - Bytes[i] = Buffer[Offset + 3 - i]; - } - - return BitConverter.ToInt32(Bytes, 0); - } - } - - // This class was found online. - // Original author is probably: mdm20 - // https://stackoverflow.com/questions/5566330/get-gif-to-play-in-wpf-with-gifimage-class/5568703#5568703 - internal class GifImage : Image - { - private bool _isInitialized; - private GifBitmapDecoder _gifDecoder; - private Int32Animation _animation; - - public int FrameIndex - { - get { return (int)GetValue(FrameIndexProperty); } - set { SetValue(FrameIndexProperty, value); } - } - - private void Initialize() - { - _gifDecoder = new GifBitmapDecoder(new Uri("pack://application:,,," + this.GifSource), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); - _animation = new Int32Animation(0, _gifDecoder.Frames.Count - 1, new Duration(new TimeSpan(0, 0, 0, _gifDecoder.Frames.Count / 10, (int)(((_gifDecoder.Frames.Count / 10.0) - (_gifDecoder.Frames.Count / 10)) * 1000)))) - { - RepeatBehavior = RepeatBehavior.Forever - }; - this.Source = _gifDecoder.Frames[0]; - - _isInitialized = true; - } - - static GifImage() - { - VisibilityProperty.OverrideMetadata(typeof(GifImage), - new FrameworkPropertyMetadata(VisibilityPropertyChanged)); - } - - private static void VisibilityPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) - { - if ((Visibility)e.NewValue == Visibility.Visible) - { - ((GifImage)sender).StartAnimation(); - } - else - { - ((GifImage)sender).StopAnimation(); - } - } - - public static readonly DependencyProperty FrameIndexProperty = - DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new UIPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex))); - - private static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev) - { - var gifImage = obj as GifImage; - gifImage.Source = gifImage._gifDecoder.Frames[(int)ev.NewValue]; - } - - public bool AutoStart - { - get { return (bool)GetValue(AutoStartProperty); } - set { SetValue(AutoStartProperty, value); } - } - - public static readonly DependencyProperty AutoStartProperty = - DependencyProperty.Register("AutoStart", typeof(bool), typeof(GifImage), new UIPropertyMetadata(false, AutoStartPropertyChanged)); - - private static void AutoStartPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) - { - if ((bool)e.NewValue) - { - (sender as GifImage)?.StartAnimation(); - } - } - - public string GifSource - { - get { return (string)GetValue(GifSourceProperty); } - set { SetValue(GifSourceProperty, value); } - } - - public static readonly DependencyProperty GifSourceProperty = - DependencyProperty.Register("GifSource", typeof(string), typeof(GifImage), new UIPropertyMetadata(string.Empty, GifSourcePropertyChanged)); - - private static void GifSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) - { - (sender as GifImage)?.Initialize(); - } - - public void StartAnimation() - { - if (!_isInitialized) - { - this.Initialize(); - } - - BeginAnimation(FrameIndexProperty, _animation); - } - - public void StopAnimation() - { - BeginAnimation(FrameIndexProperty, null); - } - } - - internal enum LogType - { - FileOnly, - FileAndConsole, - ConsoleOnly - }; - - internal static class LogFile - { - private static readonly StreamWriter w = null; - private static readonly object lockobject = new(); -#if PREVIEW - private static string LogAction = null; - private static StringBuilder LogBuilder; -#endif - - static LogFile() - { - try - { - if (!Directory.Exists(Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals"))) - { - Directory.CreateDirectory(Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals")); - } - - w = File.AppendText(Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\WPInternals.log")); - } - catch { } - } - - public static void Log(string logMessage, LogType Type = LogType.FileOnly) - { - if (w == null) - { - return; - } - - lock (lockobject) - { - if ((Type == LogType.FileOnly) || (Type == LogType.FileAndConsole)) - { - DateTime Now = DateTime.Now; - string Text = Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + ": " + logMessage; - w.WriteLine(Text); - w.Flush(); - -#if PREVIEW - if (LogAction != null) - LogBuilder.AppendLine(Text); -#endif - } - - if (CommandLine.IsConsoleVisible && ((Type == LogType.ConsoleOnly) || (Type == LogType.FileAndConsole))) - { - Console.WriteLine(logMessage); - } - } - } - - public static void LogException(Exception Ex, LogType Type = LogType.FileAndConsole, string AdditionalInfo = null) - { - string Indent = ""; - Exception CurrentEx = Ex; - while (CurrentEx != null) - { - Log(Indent + "Error: " + RemoveBadChars(CurrentEx.Message).Replace("of type '.' ", "") + (AdditionalInfo == null ? "" : " - " + AdditionalInfo), Type); - AdditionalInfo = null; - if (CurrentEx is WPinternalsException) - { - Log(Indent + ((WPinternalsException)CurrentEx).SubMessage, Type); - } -#if DEBUG - if (CurrentEx.StackTrace != null) - { - Log(Indent + CurrentEx.StackTrace, LogType.FileOnly); - } -#endif - Indent += " "; - CurrentEx = CurrentEx.InnerException; - } - } - - private static string RemoveBadChars(string Text) - { - return System.Text.RegularExpressions.Regex.Replace(Text, @"[^\u0020-\u007E]+", string.Empty); - } - - public static void DumpLog(StreamReader r) - { - string line; - while ((line = r.ReadLine()) != null) - { - Console.WriteLine(line); - } - } - - public static void LogApplicationVersion() - { - Log("Windows Phone Internals version " + - Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Build.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString(), LogType.FileAndConsole); - Log("Copyright Heathcliff74", LogType.FileAndConsole); - } - - internal static void BeginAction(string Action) - { -#if PREVIEW - if (LogAction == null) - { - LogAction = Action; - LogBuilder = new StringBuilder(); - LogBuilder.AppendLine("Windows Phone Internals version " + - Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Build.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString()); - LogBuilder.AppendLine("Copyright Heathcliff74"); - LogBuilder.AppendLine("Action: " + Action); - if (App.Config.RegistrationName != null) - LogBuilder.AppendLine("Name: " + App.Config.RegistrationName); - if (App.Config.RegistrationEmail != null) - LogBuilder.AppendLine("Mail: " + App.Config.RegistrationEmail); - if (App.Config.RegistrationSkypeID != null) - LogBuilder.AppendLine("Skype: " + App.Config.RegistrationSkypeID); - if (App.Config.RegistrationTelegramID != null) - LogBuilder.AppendLine("Telegram: " + App.Config.RegistrationTelegramID); - if (Environment.MachineName != null) - LogBuilder.AppendLine("Machine: " + Environment.MachineName); - } -#endif - } - - internal static void EndAction() - { - EndAction(null); - } - - internal static void EndAction(string Action) - { -#if PREVIEW - if ((LogAction != null) && ((Action == null) || (LogAction == Action))) - { - Action = LogAction; - LogAction = null; - string FileName = ""; - if (App.Config.RegistrationName != null) - FileName += App.Config.RegistrationName + " - "; - FileName += DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + " - " + Action + " - " + - Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Build.ToString() + "." + - Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString() + ".log"; - - // Normalize filename - try - { - FileName = System.Text.Encoding.ASCII.GetString(System.Text.Encoding.GetEncoding("ISO-8859-8").GetBytes(FileName)); - } - catch { } - FileName = FileName.Replace("?", ""); - - if (Action.ToLower() == "registration") - Uploader.Upload(FileName, LogBuilder.ToString()); - else - { - try - { - Uploader.Upload(FileName, LogBuilder.ToString()); - } - catch { } - } - } -#endif - } - } - - public static class Converter - { - public static string ConvertHexToString(byte[] Bytes, string Separator) - { - StringBuilder s = new(1000); - for (int i = Bytes.GetLowerBound(0); i <= Bytes.GetUpperBound(0); i++) - { - if (i != Bytes.GetLowerBound(0)) - { - s.Append(Separator); - } - - s.Append(Bytes[i].ToString("X2")); - } - return s.ToString(); - } - - public static byte[] ConvertStringToHex(string HexString) - { - if (HexString.Length % 2 == 1) - { - throw new Exception("The binary key cannot have an odd number of digits"); - } - - byte[] arr = new byte[HexString.Length >> 1]; - - for (int i = 0; i < (HexString.Length >> 1); ++i) - { - arr[i] = (byte)((GetHexVal(HexString[i << 1]) << 4) + GetHexVal(HexString[(i << 1) + 1])); - } - - return arr; - } - - public static int GetHexVal(char hex) - { - int val = hex; - //For uppercase A-F letters: - //return val - (val < 58 ? 48 : 55); - //For lowercase a-f letters: - //return val - (val < 58 ? 48 : 87); - //Or the two combined, but a bit slower: - return val - (val < 58 ? 48 : (val < 97 ? 55 : 87)); - } - } - - // This class was found online. - // Original author is probably: John Melville - // https://social.msdn.microsoft.com/Forums/en-US/163ef755-ff7b-4ea5-b226-bbe8ef5f4796/is-there-a-pattern-for-calling-an-async-method-synchronously?forum=async - public static class AsyncHelpers - { - /// - /// Execute's an async Task method which has a void return value synchronously - /// - /// Task method to execute - public static void RunSync(Func task) - { - var oldContext = SynchronizationContext.Current; - var synch = new ExclusiveSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synch); - synch.Post(async _ => - { - try - { - await task(); - } - catch (Exception e) - { - synch.InnerException = e; - throw; - } - finally - { - synch.EndMessageLoop(); - } - }, null); - synch.BeginMessageLoop(); - - SynchronizationContext.SetSynchronizationContext(oldContext); - } - - /// - /// Execute's an async Task method which has a T return type synchronously - /// - /// Return Type - /// Task method to execute - /// - public static T RunSync(Func> task) - { - var oldContext = SynchronizationContext.Current; - var synch = new ExclusiveSynchronizationContext(); - SynchronizationContext.SetSynchronizationContext(synch); - T ret = default; - synch.Post(async _ => - { - try - { - ret = await task(); - } - catch (Exception e) - { - synch.InnerException = e; - throw; - } - finally - { - synch.EndMessageLoop(); - } - }, null); - synch.BeginMessageLoop(); - SynchronizationContext.SetSynchronizationContext(oldContext); - return ret; - } - - private class ExclusiveSynchronizationContext : SynchronizationContext - { - private bool done; - public Exception InnerException { get; set; } - private readonly AutoResetEvent workItemsWaiting = new(false); - private readonly Queue> items = - new(); - - public override void Send(SendOrPostCallback d, object state) - { - throw new NotSupportedException("We cannot send to our same thread"); - } - - public override void Post(SendOrPostCallback d, object state) - { - lock (items) - { - items.Enqueue(Tuple.Create(d, state)); - } - workItemsWaiting.Set(); - } - - public void EndMessageLoop() - { - Post(_ => done = true, null); - } - - public void BeginMessageLoop() - { - while (!done) - { - Tuple task = null; - lock (items) - { - if (items.Count > 0) - { - task = items.Dequeue(); - } - } - if (task != null) - { - task.Item1(task.Item2); - if (InnerException != null) // the method threw an exeption - { - throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); - } - } - else - { - workItemsWaiting.WaitOne(); - } - } - } - - public override SynchronizationContext CreateCopy() - { - return this; - } - } - } - - // This class is taken from the Prism library by Microsoft Patterns & Practices - // License: http://compositewpf.codeplex.com/license - internal static class WeakEventHandlerManager - { - public static void AddWeakReferenceHandler(ref List handlers, EventHandler handler, int defaultListSize) - { - (handlers ??= (defaultListSize > 0) ? new List(defaultListSize) : []).Add(new WeakReference(handler)); - } - - private static void CallHandler(object sender, EventHandler eventHandler) - { - DispatcherProxy proxy = DispatcherProxy.CreateDispatcher(); - if (eventHandler != null) - { - if (proxy?.CheckAccess() == false) - { - proxy.BeginInvoke(new Action(CallHandler), [sender, eventHandler]); - } - else - { - eventHandler(sender, EventArgs.Empty); - } - } - } - - public static void CallWeakReferenceHandlers(object sender, List handlers) - { - if (handlers != null) - { - EventHandler[] callees = new EventHandler[handlers.Count]; - int count = 0; - count = CleanupOldHandlers(handlers, callees, count); - for (int i = 0; i < count; i++) - { - CallHandler(sender, callees[i]); - } - } - } - - private static int CleanupOldHandlers(List handlers, EventHandler[] callees, int count) - { - for (int i = handlers.Count - 1; i >= 0; i--) - { - WeakReference reference = handlers[i]; - if (reference.Target is not EventHandler target) - { - handlers.RemoveAt(i); - } - else - { - callees[count] = target; - count++; - } - } - return count; - } - - public static void RemoveWeakReferenceHandler(List handlers, EventHandler handler) - { - if (handlers != null) - { - for (int i = handlers.Count - 1; i >= 0; i--) - { - WeakReference reference = handlers[i]; - if ((reference.Target is not EventHandler target) || (target == handler)) - { - handlers.RemoveAt(i); - } - } - } - } - - private class DispatcherProxy - { - private readonly Dispatcher innerDispatcher; - - private DispatcherProxy(Dispatcher dispatcher) - { - this.innerDispatcher = dispatcher; - } - - public DispatcherOperation BeginInvoke(Delegate method, params object[] args) - { - return this.innerDispatcher.BeginInvoke(method, DispatcherPriority.Normal, args); - } - - public bool CheckAccess() - { - return this.innerDispatcher.CheckAccess(); - } - - public static DispatcherProxy CreateDispatcher() - { - if (Application.Current == null) - { - return null; - } - return new DispatcherProxy(Application.Current.Dispatcher); - } - } - } - - // This interface is taken from the Prism library by Microsoft Patterns & Practices - // License: http://compositewpf.codeplex.com/license - public interface IActiveAware - { - /// - /// Gets or sets a value indicating whether the object is active. - /// - /// if the object is active; otherwise . - bool IsActive { get; set; } - - /// - /// Notifies that the value for property has changed. - /// - event EventHandler IsActiveChanged; - } - - // This class is taken from the Prism library by Microsoft Patterns & Practices - // License: http://compositewpf.codeplex.com/license - public abstract class DelegateCommandBase : ICommand, IActiveAware - { - private List _canExecuteChangedHandlers; - private bool _isActive; - private readonly Func canExecuteMethod; - private readonly Action executeMethod; - - public event EventHandler CanExecuteChanged - { - add - { - WeakEventHandlerManager.AddWeakReferenceHandler(ref this._canExecuteChangedHandlers, value, 2); - } - remove - { - WeakEventHandlerManager.RemoveWeakReferenceHandler(this._canExecuteChangedHandlers, value); - } - } - - public event EventHandler IsActiveChanged; - - protected DelegateCommandBase(Action executeMethod, Func canExecuteMethod) - { - if ((executeMethod == null) || (canExecuteMethod == null)) - { - throw new ArgumentNullException(nameof(executeMethod), "Delegate Command Delegates Cannot Be Null"); - } - this.executeMethod = executeMethod; - this.canExecuteMethod = canExecuteMethod; - } - - protected bool CanExecute(object parameter) - { - if (this.canExecuteMethod != null) - { - return this.canExecuteMethod(parameter); - } - return true; - } - - protected void Execute(object parameter) - { - this.executeMethod(parameter); - } - - protected virtual void OnCanExecuteChanged() - { - WeakEventHandlerManager.CallWeakReferenceHandlers(this, this._canExecuteChangedHandlers); - } - - protected virtual void OnIsActiveChanged() - { - this.IsActiveChanged?.Invoke(this, EventArgs.Empty); - } - - public void RaiseCanExecuteChanged() - { - this.OnCanExecuteChanged(); - } - - bool ICommand.CanExecute(object parameter) - { - return this.CanExecute(parameter); - } - - void ICommand.Execute(object parameter) - { - this.Execute(parameter); - } - - public bool IsActive - { - get - { - return this._isActive; - } - set - { - if (this._isActive != value) - { - this._isActive = value; - this.OnIsActiveChanged(); - } - } - } - } - - // This class is taken from the Prism library by Microsoft Patterns & Practices - // License: http://compositewpf.codeplex.com/license - public class DelegateCommand : DelegateCommandBase - { - public DelegateCommand(Action executeMethod) - : this(executeMethod, () => true) - { - } - - public DelegateCommand(Action executeMethod, Func canExecuteMethod) : base(o => executeMethod(), f => canExecuteMethod()) - { - } - - public bool CanExecute() - { - return CanExecute(null); - } - - public void Execute() - { - Execute(null); - } - } - - internal class FlowDocumentScrollViewerNoMouseWheel : FlowDocumentScrollViewer - { - protected override void OnMouseWheel(MouseWheelEventArgs e) - { - } - } - - internal class ProgressUpdater - { - private readonly DateTime InitTime; - private DateTime LastUpdateTime; - private readonly UInt64 MaxValue; - private readonly Action ProgressUpdateCallback; - internal int ProgressPercentage; - - internal ProgressUpdater(UInt64 MaxValue, Action ProgressUpdateCallback) - { - InitTime = DateTime.Now; - LastUpdateTime = DateTime.Now; - this.MaxValue = MaxValue; - this.ProgressUpdateCallback = ProgressUpdateCallback; - SetProgress(0); - } - - private UInt64 _Progress; - internal UInt64 Progress - { - get - { - return _Progress; - } - } - - internal void SetProgress(UInt64 NewValue) - { - if (_Progress != NewValue) - { - int PreviousProgressPercentage = (int)((double)_Progress / MaxValue * 100); - ProgressPercentage = (int)((double)NewValue / MaxValue * 100); - - _Progress = NewValue; - - if (((DateTime.Now - LastUpdateTime) > TimeSpan.FromSeconds(0.5)) || (ProgressPercentage == 100)) - { -#if DEBUG - Console.WriteLine("Init time: " + InitTime.ToShortTimeString() + " / Now: " + DateTime.Now.ToString() + " / NewValue: " + NewValue.ToString() + " / MaxValue: " + MaxValue.ToString() + " ->> Percentage: " + ProgressPercentage.ToString() + " / Remaining: " + TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - ((double)NewValue / MaxValue)))).ToString()); -#endif - - if (((DateTime.Now - InitTime) < TimeSpan.FromSeconds(30)) && (ProgressPercentage < 15)) - { - ProgressUpdateCallback(ProgressPercentage, null); - } - else - { - ProgressUpdateCallback(ProgressPercentage, TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - ((double)NewValue / MaxValue))))); - } - - LastUpdateTime = DateTime.Now; - } - } - } - - internal void IncreaseProgress(UInt64 Progress) - { - SetProgress(_Progress + Progress); - } - } - - internal static class Compression - { - internal static Stream GetDecompressedStreamWithSeek(Stream InputStream) - { - long P = InputStream.Position; - byte[] GZipHeader = new byte[3]; - InputStream.Read(GZipHeader, 0, 3); - InputStream.Position = P; - if (StructuralComparisons.StructuralEqualityComparer.Equals(GZipHeader, new byte[] { 0x1F, 0x8B, 0x08 })) - { - return new GZipStream(InputStream, CompressionMode.Decompress, false); - } - else - { - return InputStream; - } - } - - internal static bool IsCompressedStream(Stream InputStream) - { - byte[] GZipHeader = new byte[3]; - InputStream.Read(GZipHeader, 0, 3); - return StructuralComparisons.StructuralEqualityComparer.Equals(GZipHeader, new byte[] { 0x1F, 0x8B, 0x08 }); - } - - internal static GZipStream GetDecompressedStream(Stream InputStream) - { - return new GZipStream(InputStream, CompressionMode.Decompress, false); - } - } - - internal class WPinternalsException : Exception - { - // Message and SubMessaage are always printable - internal string SubMessage = null; - - internal WPinternalsException() : base() { } - - internal WPinternalsException(string Message) : base(Message) { } - - internal WPinternalsException(string Message, Exception InnerException) : base(Message, InnerException) { } - - internal WPinternalsException(string Message, string SubMessage) : base(Message) { this.SubMessage = SubMessage; } - - internal WPinternalsException(string Message, string SubMessage, Exception InnerException) : base(Message, InnerException) { this.SubMessage = SubMessage; } - } - - // This class is written by: Eugene Beresovsky - // https://stackoverflow.com/questions/13035925/stream-wrapper-to-make-stream-seekable/28036366#28036366 - internal class ReadSeekableStream : Stream - { - private long _underlyingPosition; - private readonly byte[] _seekBackBuffer; - private int _seekBackBufferCount; - private int _seekBackBufferIndex; - private readonly Stream _underlyingStream; - - public ReadSeekableStream(Stream underlyingStream, int seekBackBufferSize) - { - if (!underlyingStream.CanRead) - { - throw new Exception("Provided stream " + underlyingStream + " is not readable"); - } - - _underlyingStream = underlyingStream; - _seekBackBuffer = new byte[seekBackBufferSize]; - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return true; } } - - public override int Read(byte[] buffer, int offset, int count) - { - int copiedFromBackBufferCount = 0; - if (_seekBackBufferIndex < _seekBackBufferCount) - { - copiedFromBackBufferCount = Math.Min(count, _seekBackBufferCount - _seekBackBufferIndex); - Buffer.BlockCopy(_seekBackBuffer, _seekBackBufferIndex, buffer, offset, copiedFromBackBufferCount); - offset += copiedFromBackBufferCount; - count -= copiedFromBackBufferCount; - _seekBackBufferIndex += copiedFromBackBufferCount; - } - int bytesReadFromUnderlying = 0; - if (count > 0) - { - bytesReadFromUnderlying = _underlyingStream.Read(buffer, offset, count); - if (bytesReadFromUnderlying > 0) - { - _underlyingPosition += bytesReadFromUnderlying; - - var copyToBufferCount = Math.Min(bytesReadFromUnderlying, _seekBackBuffer.Length); - var copyToBufferOffset = Math.Min(_seekBackBufferCount, _seekBackBuffer.Length - copyToBufferCount); - var bufferBytesToMove = Math.Min(_seekBackBufferCount - 1, copyToBufferOffset); - - if (bufferBytesToMove > 0) - { - Buffer.BlockCopy(_seekBackBuffer, _seekBackBufferCount - bufferBytesToMove, _seekBackBuffer, 0, bufferBytesToMove); - } - - Buffer.BlockCopy(buffer, offset, _seekBackBuffer, copyToBufferOffset, copyToBufferCount); - _seekBackBufferCount = Math.Min(_seekBackBuffer.Length, _seekBackBufferCount + copyToBufferCount); - _seekBackBufferIndex = _seekBackBufferCount; - } - } - return copiedFromBackBufferCount + bytesReadFromUnderlying; - } - - public override long Seek(long offset, SeekOrigin origin) - { - if (origin == SeekOrigin.End) - { - return SeekFromEnd((int)Math.Max(0, -offset)); - } - - var relativeOffset = origin == SeekOrigin.Current - ? offset - : offset - Position; - - if (relativeOffset == 0) - { - return Position; - } - else if (relativeOffset > 0) - { - return SeekForward(relativeOffset); - } - else - { - return SeekBackwards(-relativeOffset); - } - } - - private long SeekForward(long origOffset) - { - long offset = origOffset; - var seekBackBufferLength = _seekBackBuffer.Length; - - int backwardSoughtBytes = _seekBackBufferCount - _seekBackBufferIndex; - int seekForwardInBackBuffer = (int)Math.Min(offset, backwardSoughtBytes); - offset -= seekForwardInBackBuffer; - _seekBackBufferIndex += seekForwardInBackBuffer; - - if (offset > 0) - { - // first completely fill seekBackBuffer to remove special cases from while loop below - if (_seekBackBufferCount < seekBackBufferLength) - { - var maxRead = seekBackBufferLength - _seekBackBufferCount; - if (offset < maxRead) - { - maxRead = (int)offset; - } - - var bytesRead = _underlyingStream.Read(_seekBackBuffer, _seekBackBufferCount, maxRead); - _underlyingPosition += bytesRead; - _seekBackBufferCount += bytesRead; - _seekBackBufferIndex = _seekBackBufferCount; - if (bytesRead < maxRead) - { - if (_seekBackBufferCount < offset) - { - throw new NotSupportedException("Reached end of stream seeking forward " + origOffset + " bytes"); - } - - return Position; - } - offset -= bytesRead; - } - - // now alternate between filling tempBuffer and seekBackBuffer - bool fillTempBuffer = true; - var tempBuffer = new byte[seekBackBufferLength]; - while (offset > 0) - { - var maxRead = offset < seekBackBufferLength ? (int)offset : seekBackBufferLength; - var bytesRead = _underlyingStream.Read(fillTempBuffer ? tempBuffer : _seekBackBuffer, 0, maxRead); - _underlyingPosition += bytesRead; - var bytesReadDiff = maxRead - bytesRead; - offset -= bytesRead; - if (bytesReadDiff > 0 /* reached end-of-stream */ || offset == 0) - { - if (fillTempBuffer) - { - if (bytesRead > 0) - { - Buffer.BlockCopy(_seekBackBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); - Buffer.BlockCopy(tempBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); - } - } - else - { - if (bytesRead > 0) - { - Buffer.BlockCopy(_seekBackBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); - } - - Buffer.BlockCopy(tempBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); - } - if (offset > 0) - { - throw new NotSupportedException("Reached end of stream seeking forward " + origOffset + " bytes"); - } - } - fillTempBuffer = !fillTempBuffer; - } - } - return Position; - } - - private long SeekBackwards(long offset) - { - var intOffset = (int)offset; - if (offset > int.MaxValue || intOffset > _seekBackBufferIndex) - { - throw new NotSupportedException("Cannot currently seek backwards more than " + _seekBackBufferIndex + " bytes"); - } - - _seekBackBufferIndex -= intOffset; - return Position; - } - - private long SeekFromEnd(long offset) - { - var intOffset = (int)offset; - var seekBackBufferLength = _seekBackBuffer.Length; - if (offset > int.MaxValue || intOffset > seekBackBufferLength) - { - throw new NotSupportedException("Cannot seek backwards from end more than " + seekBackBufferLength + " bytes"); - } - - // first completely fill seekBackBuffer to remove special cases from while loop below - if (_seekBackBufferCount < seekBackBufferLength) - { - var maxRead = seekBackBufferLength - _seekBackBufferCount; - var bytesRead = _underlyingStream.Read(_seekBackBuffer, _seekBackBufferCount, maxRead); - _underlyingPosition += bytesRead; - _seekBackBufferCount += bytesRead; - _seekBackBufferIndex = Math.Max(0, _seekBackBufferCount - intOffset); - if (bytesRead < maxRead) - { - if (_seekBackBufferCount < intOffset) - { - throw new NotSupportedException("Could not seek backwards from end " + intOffset + " bytes"); - } - - return Position; - } - } - else - { - _seekBackBufferIndex = _seekBackBufferCount; - } - - // now alternate between filling tempBuffer and seekBackBuffer - bool fillTempBuffer = true; - var tempBuffer = new byte[seekBackBufferLength]; - while (true) - { - var bytesRead = _underlyingStream.Read(fillTempBuffer ? tempBuffer : _seekBackBuffer, 0, seekBackBufferLength); - _underlyingPosition += bytesRead; - var bytesReadDiff = seekBackBufferLength - bytesRead; - if (bytesReadDiff > 0) // reached end-of-stream - { - if (fillTempBuffer) - { - if (bytesRead > 0) - { - Buffer.BlockCopy(_seekBackBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); - Buffer.BlockCopy(tempBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); - } - } - else - { - if (bytesRead > 0) - { - Buffer.BlockCopy(_seekBackBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); - } - - Buffer.BlockCopy(tempBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); - } - _seekBackBufferIndex -= intOffset; - return Position; - } - fillTempBuffer = !fillTempBuffer; - } - } - - public override long Position - { - get { return _underlyingPosition - (_seekBackBufferCount - _seekBackBufferIndex); } - set { Seek(value, SeekOrigin.Begin); } - } - - public override bool CanTimeout { get { return _underlyingStream.CanTimeout; } } - public override bool CanWrite { get { return _underlyingStream.CanWrite; } } - public override long Length { get { return _underlyingStream.Length; } } - public override void SetLength(long value) { _underlyingStream.SetLength(value); } - public override void Write(byte[] buffer, int offset, int count) { _underlyingStream.Write(buffer, offset, count); } - public override void Flush() { _underlyingStream.Flush(); } - public override void Close() { _underlyingStream.Close(); } - public new void Dispose() { _underlyingStream.Dispose(); } - protected override void Dispose(bool disposing) - { - if (disposing) - { - _underlyingStream.Dispose(); - } - } - } - - // For reading a compressed stream or normal stream - internal class DecompressedStream : Stream - { - private readonly Stream UnderlyingStream; - private readonly bool IsSourceCompressed; - private readonly UInt64 DecompressedLength; - private Int64 ReadPosition = 0; - - // For reading a compressed stream - internal DecompressedStream(Stream InputStream) - { - UnderlyingStream = new ReadSeekableStream(InputStream, 0x100); - - byte[] Signature = new byte["CompressedPartition".Length + 2]; - Signature[0x00] = 0xFF; - Buffer.BlockCopy(Encoding.ASCII.GetBytes("CompressedPartition"), 0, Signature, 0x01, "CompressedPartition".Length); - Signature["CompressedPartition".Length + 1] = 0x00; - - int PrimaryHeaderSize = 0x0A + "CompressedPartition".Length; - byte[] SignatureRead = new byte[Signature.Length]; - UnderlyingStream.Read(SignatureRead, 0, Signature.Length); - - IsSourceCompressed = StructuralComparisons.StructuralEqualityComparer.Equals(Signature, SignatureRead); - if (IsSourceCompressed) - { - byte[] FormatVersionBytes = new byte[4]; - UnderlyingStream.Read(FormatVersionBytes, 0, 4); - if (BitConverter.ToUInt32(FormatVersionBytes, 0) > 1) // Max supported format version = 1 - { - throw new InvalidDataException(); - } - - byte[] HeaderSizeBytes = new byte[4]; - UnderlyingStream.Read(HeaderSizeBytes, 0, 4); - UInt32 HeaderSize = BitConverter.ToUInt32(HeaderSizeBytes, 0); - - if (HeaderSize >= (Signature.Length + 0x10)) - { - byte[] DecompressedLengthBytes = new byte[8]; - UnderlyingStream.Read(DecompressedLengthBytes, 0, 8); - DecompressedLength = BitConverter.ToUInt64(DecompressedLengthBytes, 0); - } - else - { - throw new InvalidDataException(); - } - - UInt32 HeaderBytesRemaining = (UInt32)(HeaderSize - Signature.Length - 0x10); - if (HeaderBytesRemaining > 0) - { - byte[] HeaderBytes = new byte[HeaderBytesRemaining]; - UnderlyingStream.Read(HeaderBytes, 0, (int)HeaderBytesRemaining); - } - - UnderlyingStream = new GZipStream(UnderlyingStream, CompressionMode.Decompress, false); - } - else - { - UnderlyingStream.Position = 0; - } - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return false; } } - public override int Read(byte[] buffer, int offset, int count) - { - int RealCount = UnderlyingStream.Read(buffer, offset, count); - ReadPosition += RealCount; - return RealCount; - } - public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } - public override long Position - { - get { return ReadPosition; } - set { throw new NotSupportedException(); } - } - public override bool CanTimeout { get { return UnderlyingStream.CanTimeout; } } - public override bool CanWrite { get { return true; } } - public override long Length - { - get - { - if (IsSourceCompressed) - { - return (long)DecompressedLength; - } - else - { - return UnderlyingStream.Length; - } - } - } - public override void SetLength(long value) { throw new NotSupportedException(); } - public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } - public override void Flush() { UnderlyingStream.Flush(); } - public override void Close() { UnderlyingStream.Close(); } - protected override void Dispose(bool disposing) - { - if (disposing) - { - this.UnderlyingStream.Dispose(); - } - } - } - - // For writing a compressed stream - internal class CompressedStream : Stream - { - private readonly UInt32 HeaderSize; - private UInt64 WritePosition; - private readonly GZipStream UnderlyingStream; - - internal CompressedStream(Stream OutputStream, UInt64 TotalDecompressedStreamLength) - { - // Write header - HeaderSize = (UInt32)(0x12 + "CompressedPartition".Length); - OutputStream.WriteByte(0xFF); - OutputStream.Write(Encoding.ASCII.GetBytes("CompressedPartition"), 0, "CompressedPartition".Length); - OutputStream.WriteByte(0x00); - OutputStream.Write(BitConverter.GetBytes((UInt32)1), 0, 4); // Format version = 1 - OutputStream.Write(BitConverter.GetBytes(HeaderSize), 0, 4); // Headersize - OutputStream.Write(BitConverter.GetBytes(TotalDecompressedStreamLength), 0, 8); - - this.UnderlyingStream = new GZipStream(OutputStream, CompressionLevel.Optimal, false); - WritePosition = 0; - } - - public override bool CanRead { get { return false; } } - public override bool CanSeek { get { return false; } } - public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } - public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } - public override long Position - { - get { return (long)WritePosition; } - set { throw new NotSupportedException(); } - } - public override bool CanTimeout { get { return UnderlyingStream.CanTimeout; } } - public override bool CanWrite { get { return true; } } - public override long Length { get { return (long)WritePosition; } } - public override void SetLength(long value) { throw new NotSupportedException(); } - public override void Write(byte[] buffer, int offset, int count) - { - WritePosition += (UInt64)count; - UnderlyingStream.Write(buffer, offset, count); - } - public override void Flush() { UnderlyingStream.Flush(); } - public override void Close() { UnderlyingStream.Close(); } - public new void Dispose() { UnderlyingStream.Dispose(); } - protected override void Dispose(bool disposing) - { - if (disposing) - { - this.UnderlyingStream.Dispose(); - } - } - } - - internal class SeekableStream : Stream - { - private Stream UnderlyingStream; - private Int64 ReadPosition = 0; - private readonly Func StreamInitializer; - private readonly Int64 UnderlyingStreamLength; - - // For reading a compressed stream - internal SeekableStream(Func StreamInitializer, Int64? Length = null) - { - this.StreamInitializer = StreamInitializer; - UnderlyingStream = StreamInitializer(); - if (Length != null) - { - UnderlyingStreamLength = (Int64)Length; - } - else - { - try - { - UnderlyingStreamLength = UnderlyingStream.Length; - } - catch - { - throw new ArgumentException("Unknown stream length"); - } - } - } - - public override bool CanRead { get { return true; } } - public override bool CanSeek { get { return true; } } - public override int Read(byte[] buffer, int offset, int count) - { - int RealCount = UnderlyingStream.Read(buffer, offset, count); - ReadPosition += RealCount; - return RealCount; - } - public override long Seek(long offset, SeekOrigin origin) - { - if (UnderlyingStream.CanSeek) - { - ReadPosition = UnderlyingStream.Seek(offset, origin); - return ReadPosition; - } - else - { - Int64 NewPosition = 0; - switch (origin) - { - case SeekOrigin.Begin: - NewPosition = offset; - break; - case SeekOrigin.Current: - NewPosition = ReadPosition + offset; - break; - case SeekOrigin.End: - NewPosition = UnderlyingStreamLength - offset; - break; - } - if ((NewPosition < 0) || (NewPosition > UnderlyingStreamLength)) - { - throw new ArgumentOutOfRangeException(); - } - - if (NewPosition < ReadPosition) - { - UnderlyingStream.Close(); - UnderlyingStream = StreamInitializer(); - ReadPosition = 0; - } - UInt64 Remaining; - byte[] Buffer = new byte[16384]; - while (ReadPosition < NewPosition) - { - Remaining = (UInt64)(NewPosition - ReadPosition); - if (Remaining > (UInt64)Buffer.Length) - { - Remaining = (UInt64)Buffer.Length; - } - - UnderlyingStream.Read(Buffer, 0, (int)Remaining); - ReadPosition += (long)Remaining; - } - return ReadPosition; - } - } - public override long Position - { - get - { - return ReadPosition; - } - set - { - Seek(value, SeekOrigin.Begin); - } - } - public override bool CanTimeout { get { return UnderlyingStream.CanTimeout; } } - public override bool CanWrite { get { return false; } } - public override long Length - { - get - { - return UnderlyingStreamLength; - } - } - public override void SetLength(long value) { throw new NotSupportedException(); } - public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } - public override void Flush() { throw new NotSupportedException(); } - public override void Close() { UnderlyingStream.Close(); } - protected override void Dispose(bool disposing) - { - if (disposing) - { - this.UnderlyingStream.Dispose(); - } - } - } - - internal enum ResourceType - { - RT_CURSOR = 1, - RT_BITMAP = 2, - RT_ICON = 3, - RT_MENU = 4, - RT_DIALOG = 5, - RT_STRING = 6, - RT_FONTDIR = 7, - RT_FONT = 8, - RT_ACCELERATOR = 9, - RT_RCDATA = 10, - RT_MESSAGETABLE = 11, - RT_GROUP_CURSOR = RT_CURSOR + 11, - RT_GROUP_ICON = RT_ICON + 11, - RT_VERSION = 16, - RT_DLGINCLUDE = 17, - RT_PLUGPLAY = 19, - RT_VXD = 20, - RT_ANICURSOR = 21, - RT_ANIICON = 22, - RT_HTML = 23, - RT_MANIFEST = 24, - RT_DLGINIT = 240, - RT_TOOLBAR = 241 - }; - - internal static class PE - { - internal static byte[] GetResource(byte[] PEfile, int[] Index) - { - // Explanation of PE header here: - // https://msdn.microsoft.com/en-us/library/ms809762.aspx?f=255&MSPPError=-2147217396 - - UInt32 PEPointer = ByteOperations.ReadUInt32(PEfile, 0x3C); - UInt16 OptionalHeaderSize = ByteOperations.ReadUInt16(PEfile, PEPointer + 0x14); - UInt32 SectionTablePointer = PEPointer + 0x18 + OptionalHeaderSize; - UInt16 SectionCount = ByteOperations.ReadUInt16(PEfile, PEPointer + 0x06); - UInt32? ResourceSectionEntryPointer = null; - for (int i = 0; i < SectionCount; i++) - { - string SectionName = ByteOperations.ReadAsciiString(PEfile, (UInt32)(SectionTablePointer + (i * 0x28)), 8); - int e = SectionName.IndexOf('\0'); - if (e >= 0) - { - SectionName = SectionName.Substring(0, e); - } - - if (SectionName == ".rsrc") - { - ResourceSectionEntryPointer = (UInt32)(SectionTablePointer + (i * 0x28)); - break; - } - } - if (ResourceSectionEntryPointer == null) - { - throw new WPinternalsException("Resource-section not found"); - } - - UInt32 ResourceRawSize = ByteOperations.ReadUInt32(PEfile, (UInt32)ResourceSectionEntryPointer + 0x10); - UInt32 ResourceRawPointer = ByteOperations.ReadUInt32(PEfile, (UInt32)ResourceSectionEntryPointer + 0x14); - UInt32 ResourceVirtualPointer = ByteOperations.ReadUInt32(PEfile, (UInt32)ResourceSectionEntryPointer + 0x0C); - - UInt32 p = ResourceRawPointer; - for (int i = 0; i < Index.Length; i++) - { - UInt16 ResourceNamedEntryCount = ByteOperations.ReadUInt16(PEfile, p + 0x0c); - UInt16 ResourceIdEntryCount = ByteOperations.ReadUInt16(PEfile, p + 0x0e); - for (int j = ResourceNamedEntryCount; j < ResourceNamedEntryCount + ResourceIdEntryCount; j++) - { - UInt32 ResourceID = ByteOperations.ReadUInt32(PEfile, (UInt32)(p + 0x10 + (j * 8))); - UInt32 NextPointer = ByteOperations.ReadUInt32(PEfile, (UInt32)(p + 0x10 + (j * 8) + 4)); - if (ResourceID == (UInt32)Index[i]) - { - // Check high bit - if ((NextPointer & 0x80000000) == 0 != (i == (Index.Length - 1))) - { - throw new WPinternalsException("Bad resource path"); - } - - p = ResourceRawPointer + (NextPointer & 0x7fffffff); - break; - } - } - } - - UInt32 ResourceValuePointer = ByteOperations.ReadUInt32(PEfile, p) - ResourceVirtualPointer + ResourceRawPointer; - UInt32 ResourceValueSize = ByteOperations.ReadUInt32(PEfile, p + 4); - - byte[] ResourceValue = new byte[ResourceValueSize]; - Array.Copy(PEfile, ResourceValuePointer, ResourceValue, 0, ResourceValueSize); - - return ResourceValue; - } - - internal static Version GetFileVersion(byte[] PEfile) - { - byte[] version = GetResource(PEfile, [(int)ResourceType.RT_VERSION, 1, 1033]); - - // RT_VERSION format: - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx - const UInt32 FixedFileInfoPointer = 0x28; - UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0A); - UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x08); - UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0E); - UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0C); - - return new Version(Major, Minor, Build, Revision); - } - - internal static Version GetProductVersion(byte[] PEfile) - { - byte[] version = GetResource(PEfile, [(int)ResourceType.RT_VERSION, 1, 1033]); - - // RT_VERSION format: - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx - const UInt32 FixedFileInfoPointer = 0x28; - UInt16 Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x12); - UInt16 Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x10); - UInt16 Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x16); - UInt16 Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x14); - - return new Version(Major, Minor, Build, Revision); - } - } - -#if PREVIEW - internal static class Uploader - { - internal static List Uploads = []; - - internal static void Upload(string FileName, string Text) - { - byte[] byteArray = Encoding.UTF8.GetBytes(Text); - MemoryStream FileStream = new MemoryStream(byteArray); - Upload(FileName, FileStream); - } - - internal static void Upload(string FileName, byte[] Data) - { - Upload(FileName, new MemoryStream(Data)); - } - - internal static void Upload(string FileName, Stream FileStream) - { - //TODO: Fix - //Upload(new Uri(@"https://www.wpinternals.net/upload.php", UriKind.Absolute), "uploadedfile", FileName, FileStream); - } - - private static void Upload(Uri Address, string InputName, string FileName, Stream FileStream) - { - System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; - System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient(); - System.Net.Http.MultipartFormDataContent form = []; - System.Net.Http.StreamContent Content = new System.Net.Http.StreamContent(FileStream); - Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/plain"); - form.Add(Content, InputName, FileName); - Task UploadTask = httpClient.PostAsync(Address, form); - - Uploads.Add( - UploadTask.ContinueWith((t) => - { - Uploads.Remove(t); - httpClient.Dispose(); - }) - ); - } - - internal static void WaitForUploads() - { - Task.WaitAll(Uploads.ToArray()); - } - } -#endif - - internal class AsyncAutoResetEvent - { - private readonly LinkedList> waiters = - new(); - - private bool isSignaled; - - public AsyncAutoResetEvent(bool signaled) - { - this.isSignaled = signaled; - } - - public Task WaitAsync(TimeSpan timeout) - { - return this.WaitAsync(timeout, CancellationToken.None); - } - - public async Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken) - { - TaskCompletionSource tcs; - - lock (this.waiters) - { - if (this.isSignaled) - { - this.isSignaled = false; - return true; - } - else if (timeout == TimeSpan.Zero) - { - return this.isSignaled; - } - else - { - tcs = new TaskCompletionSource(); - this.waiters.AddLast(tcs); - } - } - - Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken)); - if (winner == tcs.Task) - { - // The task was signaled. - return true; - } - else - { - // We timed-out; remove our reference to the task. - // This is an O(n) operation since waiters is a LinkedList. - lock (this.waiters) - { - bool removed = this.waiters.Remove(tcs); - System.Diagnostics.Debug.Assert(removed); - return false; - } - } - } - - public void Set() - { - TaskCompletionSource toRelease = null; - - lock (this.waiters) - { - if (this.waiters.Count > 0) - { - // Signal the first task in the waiters list. - toRelease = this.waiters.First.Value; - this.waiters.RemoveFirst(); - } - else if (!this.isSignaled) - { - // No tasks are pending - this.isSignaled = true; - } - } - - toRelease?.SetResult(true); - } - } - - // This class was written by: Rolf Wessels - // https://github.com/rolfwessels/lazycowprojects/tree/master/Wpf - - /// - /// Static class used to attach to wpf control - /// - public static class GridViewColumnResize - { - #region DependencyProperties - - public static readonly DependencyProperty WidthProperty = - DependencyProperty.RegisterAttached("Width", typeof(string), typeof(GridViewColumnResize), - new PropertyMetadata(OnSetWidthCallback)); - - public static readonly DependencyProperty GridViewColumnResizeBehaviorProperty = - DependencyProperty.RegisterAttached("GridViewColumnResizeBehavior", - typeof(GridViewColumnResizeBehavior), typeof(GridViewColumnResize), - null); - - public static readonly DependencyProperty EnabledProperty = - DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(GridViewColumnResize), - new PropertyMetadata(OnSetEnabledCallback)); - - public static readonly DependencyProperty ListViewResizeBehaviorProperty = - DependencyProperty.RegisterAttached("ListViewResizeBehaviorProperty", - typeof(ListViewResizeBehavior), typeof(GridViewColumnResize), null); - - #endregion - - public static string GetWidth(DependencyObject obj) - { - return (string)obj.GetValue(WidthProperty); - } - - public static void SetWidth(DependencyObject obj, string value) - { - obj.SetValue(WidthProperty, value); - } - - public static bool GetEnabled(DependencyObject obj) - { - return (bool)obj.GetValue(EnabledProperty); - } - - public static void SetEnabled(DependencyObject obj, bool value) - { - obj.SetValue(EnabledProperty, value); - } - - #region CallBack - - private static void OnSetWidthCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - if (dependencyObject is GridViewColumn element) - { - GridViewColumnResizeBehavior behavior = GetOrCreateBehavior(element); - behavior.Width = e.NewValue as string; - } - else - { - Console.Error.WriteLine("Error: Expected type GridViewColumn but found " + - dependencyObject.GetType().Name); - } - } - - private static void OnSetEnabledCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) - { - if (dependencyObject is ListView element) - { - ListViewResizeBehavior behavior = GetOrCreateBehavior(element); - behavior.Enabled = (bool)e.NewValue; - } - else - { - Console.Error.WriteLine("Error: Expected type ListView but found " + dependencyObject.GetType().Name); - } - } - - private static ListViewResizeBehavior GetOrCreateBehavior(ListView element) - { - if (element.GetValue(GridViewColumnResizeBehaviorProperty) is not ListViewResizeBehavior behavior) - { - behavior = new ListViewResizeBehavior(element); - element.SetValue(ListViewResizeBehaviorProperty, behavior); - } - - return behavior; - } - - private static GridViewColumnResizeBehavior GetOrCreateBehavior(GridViewColumn element) - { - if (element.GetValue(GridViewColumnResizeBehaviorProperty) is not GridViewColumnResizeBehavior behavior) - { - behavior = new GridViewColumnResizeBehavior(element); - element.SetValue(GridViewColumnResizeBehaviorProperty, behavior); - } - - return behavior; - } - - #endregion - - #region Nested type: GridViewColumnResizeBehavior - - // This class was written by: Rolf Wessels - // https://github.com/rolfwessels/lazycowprojects/tree/master/Wpf - - /// - /// GridViewColumn class that gets attached to the GridViewColumn control - /// - public class GridViewColumnResizeBehavior - { - private readonly GridViewColumn _element; - - public GridViewColumnResizeBehavior(GridViewColumn element) - { - _element = element; - } - - public string Width { get; set; } - - public bool IsStatic - { - get { return StaticWidth >= 0; } - } - - public double StaticWidth - { - get - { - return double.TryParse(Width, out double result) ? result : -1; - } - } - - public double Percentage - { - get - { - if (!IsStatic) - { - return Mulitplier * 100; - } - return 0; - } - } - - public double Mulitplier - { - get - { - if (Width == "*" || Width == "1*") - { - return 1; - } - - if (Width.EndsWith("*") && double.TryParse(Width[0..^1], out double perc)) - { - return perc; - } - return 1; - } - } - - public void SetWidth(double allowedSpace, double totalPercentage) - { - if (IsStatic) - { - _element.Width = StaticWidth; - } - else - { - _element.Width = (double)Math.Max(allowedSpace * (Percentage / totalPercentage), 0); - } - } - } - - #endregion - - #region Nested type: ListViewResizeBehavior - - // This class was written by: Rolf Wessels - // https://github.com/rolfwessels/lazycowprojects/tree/master/Wpf - - /// - /// ListViewResizeBehavior class that gets attached to the ListView control - /// - public class ListViewResizeBehavior - { - private const int Margin = 25; - private const long RefreshTime = Timeout.Infinite; - private const long Delay = 500; - - private readonly ListView _element; - private readonly Timer _timer; - - public ListViewResizeBehavior(ListView element) - { - _element = element ?? throw new ArgumentNullException(nameof(element)); - element.Loaded += OnLoaded; - - // Action for resizing and re-enable the size lookup - // This stops the columns from constantly resizing to improve performance - Action resizeAndEnableSize = () => - { - Resize(); - _element.SizeChanged += OnSizeChanged; - }; - _timer = new Timer(x => Application.Current.Dispatcher.BeginInvoke(resizeAndEnableSize), null, Delay, - RefreshTime); - } - - public bool Enabled { get; set; } - - private void OnLoaded(object sender, RoutedEventArgs e) - { - _element.SizeChanged += OnSizeChanged; - } - - private void OnSizeChanged(object sender, SizeChangedEventArgs e) - { - if (e.WidthChanged) - { - _element.SizeChanged -= OnSizeChanged; - _timer.Change(Delay, RefreshTime); - } - } - - private void Resize() - { - if (Enabled) - { - double totalWidth = _element.ActualWidth; - if (_element.View is GridView gv) - { - double allowedSpace = totalWidth - GetAllocatedSpace(gv); - allowedSpace -= Margin; - double totalPercentage = GridViewColumnResizeBehaviors(gv).Sum(x => x.Percentage); - foreach (GridViewColumnResizeBehavior behavior in GridViewColumnResizeBehaviors(gv)) - { - behavior.SetWidth(allowedSpace, totalPercentage); - } - } - } - } - - private static IEnumerable GridViewColumnResizeBehaviors(GridView gv) - { - foreach (GridViewColumn t in gv.Columns) - { - if (t.GetValue(GridViewColumnResizeBehaviorProperty) is GridViewColumnResizeBehavior gridViewColumnResizeBehavior) - { - yield return gridViewColumnResizeBehavior; - } - } - } - - private static double GetAllocatedSpace(GridView gv) - { - double totalWidth = 0; - foreach (GridViewColumn t in gv.Columns) - { - if (t.GetValue(GridViewColumnResizeBehaviorProperty) is GridViewColumnResizeBehavior gridViewColumnResizeBehavior) - { - if (gridViewColumnResizeBehavior.IsStatic) - { - totalWidth += gridViewColumnResizeBehavior.StaticWidth; - } - } - else - { - totalWidth += t.ActualWidth; - } - } - return totalWidth; - } - } - - #endregion - } - - internal static class ExtensionMethods - { - // This method was written by: Lawrence Johnston - // https://stackoverflow.com/a/22078975 - public static async Task TimeoutAfter(this Task task, TimeSpan timeout) - { - using var timeoutCancellationTokenSource = new CancellationTokenSource(); - var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)); - if (completedTask == task) - { - timeoutCancellationTokenSource.Cancel(); - return await task; // Very important in order to propagate exceptions - } - else - { - throw new TimeoutException("The operation has timed out."); - } - } - } -} diff --git a/WPinternals/HelperClasses/ArrivalEventArgs.cs b/WPinternals/HelperClasses/ArrivalEventArgs.cs new file mode 100644 index 0000000..b9c5234 --- /dev/null +++ b/WPinternals/HelperClasses/ArrivalEventArgs.cs @@ -0,0 +1,40 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + internal class ArrivalEventArgs : EventArgs + { + public PhoneInterfaces NewInterface; + public IDisposable NewModel; + + public ArrivalEventArgs(PhoneInterfaces NewInterface, IDisposable NewModel) + : base() + { + this.NewInterface = NewInterface; + this.NewModel = NewModel; + } + } +} diff --git a/WPinternals/HelperClasses/AsyncAutoResetEvent.cs b/WPinternals/HelperClasses/AsyncAutoResetEvent.cs new file mode 100644 index 0000000..c2f189c --- /dev/null +++ b/WPinternals/HelperClasses/AsyncAutoResetEvent.cs @@ -0,0 +1,111 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace WPinternals.HelperClasses +{ + internal class AsyncAutoResetEvent + { + private readonly LinkedList> waiters = + new(); + + private bool isSignaled; + + public AsyncAutoResetEvent(bool signaled) + { + isSignaled = signaled; + } + + public Task WaitAsync(TimeSpan timeout) + { + return WaitAsync(timeout, CancellationToken.None); + } + + public async Task WaitAsync(TimeSpan timeout, CancellationToken cancellationToken) + { + TaskCompletionSource tcs; + + lock (waiters) + { + if (isSignaled) + { + isSignaled = false; + return true; + } + else if (timeout == TimeSpan.Zero) + { + return isSignaled; + } + else + { + tcs = new TaskCompletionSource(); + waiters.AddLast(tcs); + } + } + + Task winner = await Task.WhenAny(tcs.Task, Task.Delay(timeout, cancellationToken)); + if (winner == tcs.Task) + { + // The task was signaled. + return true; + } + else + { + // We timed-out; remove our reference to the task. + // This is an O(n) operation since waiters is a LinkedList. + lock (waiters) + { + bool removed = waiters.Remove(tcs); + System.Diagnostics.Debug.Assert(removed); + return false; + } + } + } + + public void Set() + { + TaskCompletionSource toRelease = null; + + lock (waiters) + { + if (waiters.Count > 0) + { + // Signal the first task in the waiters list. + toRelease = waiters.First.Value; + waiters.RemoveFirst(); + } + else if (!isSignaled) + { + // No tasks are pending + isSignaled = true; + } + } + + toRelease?.SetResult(true); + } + } +} diff --git a/WPinternals/HelperClasses/AsyncHelpers.cs b/WPinternals/HelperClasses/AsyncHelpers.cs new file mode 100644 index 0000000..e7c187d --- /dev/null +++ b/WPinternals/HelperClasses/AsyncHelpers.cs @@ -0,0 +1,162 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace WPinternals.HelperClasses +{ + // This class was found online. + // Original author is probably: John Melville + // https://social.msdn.microsoft.com/Forums/en-US/163ef755-ff7b-4ea5-b226-bbe8ef5f4796/is-there-a-pattern-for-calling-an-async-method-synchronously?forum=async + public static class AsyncHelpers + { + /// + /// Execute's an async Task method which has a void return value synchronously + /// + /// Task method to execute + public static void RunSync(Func task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + synch.Post(async _ => + { + try + { + await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + + SynchronizationContext.SetSynchronizationContext(oldContext); + } + + /// + /// Execute's an async Task method which has a T return type synchronously + /// + /// Return Type + /// Task method to execute + /// + public static T RunSync(Func> task) + { + var oldContext = SynchronizationContext.Current; + var synch = new ExclusiveSynchronizationContext(); + SynchronizationContext.SetSynchronizationContext(synch); + T ret = default; + synch.Post(async _ => + { + try + { + ret = await task(); + } + catch (Exception e) + { + synch.InnerException = e; + throw; + } + finally + { + synch.EndMessageLoop(); + } + }, null); + synch.BeginMessageLoop(); + SynchronizationContext.SetSynchronizationContext(oldContext); + return ret; + } + + private class ExclusiveSynchronizationContext : SynchronizationContext + { + private bool done; + public Exception InnerException + { + get; set; + } + private readonly AutoResetEvent workItemsWaiting = new(false); + private readonly Queue> items = + new(); + + public override void Send(SendOrPostCallback d, object state) + { + throw new NotSupportedException("We cannot send to our same thread"); + } + + public override void Post(SendOrPostCallback d, object state) + { + lock (items) + { + items.Enqueue(Tuple.Create(d, state)); + } + workItemsWaiting.Set(); + } + + public void EndMessageLoop() + { + Post(_ => done = true, null); + } + + public void BeginMessageLoop() + { + while (!done) + { + Tuple task = null; + lock (items) + { + if (items.Count > 0) + { + task = items.Dequeue(); + } + } + if (task != null) + { + task.Item1(task.Item2); + if (InnerException != null) // the method threw an exeption + { + throw new AggregateException("AsyncHelpers.Run method threw an exception.", InnerException); + } + } + else + { + workItemsWaiting.WaitOne(); + } + } + } + + public override SynchronizationContext CreateCopy() + { + return this; + } + } + } +} diff --git a/WPinternals/HelperClasses/BigEndian.cs b/WPinternals/HelperClasses/BigEndian.cs new file mode 100644 index 0000000..0766141 --- /dev/null +++ b/WPinternals/HelperClasses/BigEndian.cs @@ -0,0 +1,125 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + internal static class BigEndian + { + public static byte[] GetBytes(object Value) + { + byte[] Bytes; + if (Value is short) + { + Bytes = BitConverter.GetBytes((short)Value); + } + else if (Value is ushort) + { + Bytes = BitConverter.GetBytes((ushort)Value); + } + else if (Value is int) + { + Bytes = BitConverter.GetBytes((int)Value); + } + else + { + Bytes = Value is uint ? BitConverter.GetBytes((uint)Value) : throw new NotSupportedException(); + } + + byte[] Result = new byte[Bytes.Length]; + for (int i = 0; i < Bytes.Length; i++) + { + Result[i] = Bytes[Bytes.Length - 1 - i]; + } + + return Result; + } + + public static byte[] GetBytes(object Value, int Width) + { + byte[] Result; + byte[] BigEndianBytes = GetBytes(Value); + if (BigEndianBytes.Length == Width) + { + return BigEndianBytes; + } + else if (BigEndianBytes.Length > Width) + { + Result = new byte[Width]; + Buffer.BlockCopy(BigEndianBytes, BigEndianBytes.Length - Width, Result, 0, Width); + return Result; + } + else + { + Result = new byte[Width]; + Buffer.BlockCopy(BigEndianBytes, 0, Result, Width - BigEndianBytes.Length, BigEndianBytes.Length); + return Result; + } + } + + public static ushort ToUInt16(byte[] Buffer, int Offset) + { + byte[] Bytes = new byte[2]; + for (int i = 0; i < 2; i++) + { + Bytes[i] = Buffer[Offset + 1 - i]; + } + + return BitConverter.ToUInt16(Bytes, 0); + } + + public static short ToInt16(byte[] Buffer, int Offset) + { + byte[] Bytes = new byte[2]; + for (int i = 0; i < 2; i++) + { + Bytes[i] = Buffer[Offset + 1 - i]; + } + + return BitConverter.ToInt16(Bytes, 0); + } + + public static uint ToUInt32(byte[] Buffer, int Offset) + { + byte[] Bytes = new byte[4]; + for (int i = 0; i < 4; i++) + { + Bytes[i] = Buffer[Offset + 3 - i]; + } + + return BitConverter.ToUInt32(Bytes, 0); + } + + public static int ToInt32(byte[] Buffer, int Offset) + { + byte[] Bytes = new byte[4]; + for (int i = 0; i < 4; i++) + { + Bytes[i] = Buffer[Offset + 3 - i]; + } + + return BitConverter.ToInt32(Bytes, 0); + } + } +} diff --git a/WPinternals/HelperClasses/BooleanConverter.cs b/WPinternals/HelperClasses/BooleanConverter.cs new file mode 100644 index 0000000..61781a5 --- /dev/null +++ b/WPinternals/HelperClasses/BooleanConverter.cs @@ -0,0 +1,138 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace WPinternals.HelperClasses +{ + public class BooleanConverter : DependencyObject, IValueConverter + { + public static readonly DependencyProperty OnTrueProperty = + DependencyProperty.Register("OnTrue", typeof(object), typeof(BooleanConverter), + new PropertyMetadata(default(object))); + + public static readonly DependencyProperty OnFalseProperty = + DependencyProperty.Register("OnFalse", typeof(object), typeof(BooleanConverter), + new PropertyMetadata(default(object))); + + public static readonly DependencyProperty OnNullProperty = + DependencyProperty.Register("OnNull", typeof(object), typeof(BooleanConverter), + new PropertyMetadata(default(object))); + + public object OnTrue + { + get + { + return GetValue(OnTrueProperty); + } + set + { + SetValue(OnTrueProperty, value); + } + } + + public object OnFalse + { + get + { + return GetValue(OnFalseProperty); + } + set + { + SetValue(OnFalseProperty, value); + } + } + + public object OnNull + { + get + { + return GetValue(OnNullProperty); + } + set + { + SetValue(OnNullProperty, value); + } + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value == null + ? OnNull ?? Default(targetType) + : string.Equals(value.ToString(), false.ToString(), StringComparison.CurrentCultureIgnoreCase) + ? OnFalse + : OnTrue; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == OnNull) + { + return Default(targetType); + } + + if (value == OnFalse) + { + return false; + } + + if (value == OnTrue) + { + return true; + } + + if (value == null) + { + return null; + } + + if (OnNull != null && + string.Equals(value.ToString(), OnNull.ToString(), StringComparison.CurrentCultureIgnoreCase)) + { + return Default(targetType); + } + + if (OnFalse != null && + string.Equals(value.ToString(), OnFalse.ToString(), StringComparison.CurrentCultureIgnoreCase)) + { + return false; + } + + if (OnTrue != null && + string.Equals(value.ToString(), OnTrue.ToString(), StringComparison.CurrentCultureIgnoreCase)) + { + return true; + } + + return null; + } + + public static object Default(Type type) + { + return type.IsValueType ? Activator.CreateInstance(type) : null; + } + } +} diff --git a/WPinternals/HelperClasses/CollapsibleRun.cs b/WPinternals/HelperClasses/CollapsibleRun.cs new file mode 100644 index 0000000..4929081 --- /dev/null +++ b/WPinternals/HelperClasses/CollapsibleRun.cs @@ -0,0 +1,59 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Windows; +using System.Windows.Documents; + +namespace WPinternals.HelperClasses +{ + internal class CollapsibleRun : Run + { + private string CollapsibleText; + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + CollapsibleText = Text; + } + + public bool IsVisible + { + get + { + return (bool)GetValue(IsVisibleProperty); + } + set + { + SetValue(IsVisibleProperty, value); + } + } + public static readonly DependencyProperty IsVisibleProperty = DependencyProperty.Register( + "IsVisible", typeof(bool), typeof(CollapsibleRun), new PropertyMetadata(true, IsVisibleChanged)); + public static void IsVisibleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((CollapsibleRun)d).Text = (bool)e.NewValue ? ((CollapsibleRun)d).CollapsibleText : string.Empty; + } + } +} diff --git a/WPinternals/HelperClasses/CollapsibleSection.cs b/WPinternals/HelperClasses/CollapsibleSection.cs new file mode 100644 index 0000000..70920d0 --- /dev/null +++ b/WPinternals/HelperClasses/CollapsibleSection.cs @@ -0,0 +1,79 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Documents; + +namespace WPinternals.HelperClasses +{ + internal class CollapsibleSection : Section + { + public CollapsibleSection() + { + CollapsibleBlocks = []; + } + + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + foreach (Block Block in Blocks) + { + CollapsibleBlocks.Add(Block); + } + + Blocks.Clear(); + } + + public List CollapsibleBlocks + { + get; + } + + public bool IsCollapsed + { + get + { + return (bool)GetValue(IsCollapsedProperty); + } + set + { + SetValue(IsCollapsedProperty, value); + + Blocks.Clear(); + + if (IsInitialized && !value) + { + foreach (Block Block in CollapsibleBlocks) + { + Blocks.Add(Block); + } + } + } + } + public static readonly DependencyProperty IsCollapsedProperty = DependencyProperty.Register( + "IsCollapsed", typeof(bool), typeof(CollapsibleSection), new PropertyMetadata(false)); + } +} diff --git a/WPinternals/HelperClasses/CompressedStream.cs b/WPinternals/HelperClasses/CompressedStream.cs new file mode 100644 index 0000000..c91d2ff --- /dev/null +++ b/WPinternals/HelperClasses/CompressedStream.cs @@ -0,0 +1,136 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.IO; +using System.IO.Compression; +using System.Text; + +namespace WPinternals.HelperClasses +{ + // For writing a compressed stream + internal class CompressedStream : Stream + { + private readonly uint HeaderSize; + private ulong WritePosition; + private readonly GZipStream UnderlyingStream; + + internal CompressedStream(Stream OutputStream, ulong TotalDecompressedStreamLength) + { + // Write header + HeaderSize = (uint)(0x12 + "CompressedPartition".Length); + OutputStream.WriteByte(0xFF); + OutputStream.Write(Encoding.ASCII.GetBytes("CompressedPartition"), 0, "CompressedPartition".Length); + OutputStream.WriteByte(0x00); + OutputStream.Write(BitConverter.GetBytes((uint)1), 0, 4); // Format version = 1 + OutputStream.Write(BitConverter.GetBytes(HeaderSize), 0, 4); // Headersize + OutputStream.Write(BitConverter.GetBytes(TotalDecompressedStreamLength), 0, 8); + + UnderlyingStream = new GZipStream(OutputStream, CompressionLevel.Optimal, false); + WritePosition = 0; + } + + public override bool CanRead + { + get + { + return false; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + public override long Position + { + get + { + return (long)WritePosition; + } + set + { + throw new NotSupportedException(); + } + } + public override bool CanTimeout + { + get + { + return UnderlyingStream.CanTimeout; + } + } + public override bool CanWrite + { + get + { + return true; + } + } + public override long Length + { + get + { + return (long)WritePosition; + } + } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + public override void Write(byte[] buffer, int offset, int count) + { + WritePosition += (ulong)count; + UnderlyingStream.Write(buffer, offset, count); + } + public override void Flush() + { + UnderlyingStream.Flush(); + } + public override void Close() + { + UnderlyingStream.Close(); + } + public new void Dispose() + { + UnderlyingStream.Dispose(); + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + UnderlyingStream.Dispose(); + } + } + } +} diff --git a/WPinternals/HelperClasses/Compression.cs b/WPinternals/HelperClasses/Compression.cs new file mode 100644 index 0000000..03f08d2 --- /dev/null +++ b/WPinternals/HelperClasses/Compression.cs @@ -0,0 +1,60 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System.Collections; +using System.IO; +using System.IO.Compression; + +namespace WPinternals.HelperClasses +{ + internal static class Compression + { + internal static Stream GetDecompressedStreamWithSeek(Stream InputStream) + { + long P = InputStream.Position; + byte[] GZipHeader = new byte[3]; + InputStream.Read(GZipHeader, 0, 3); + InputStream.Position = P; + if (StructuralComparisons.StructuralEqualityComparer.Equals(GZipHeader, new byte[] { 0x1F, 0x8B, 0x08 })) + { + return new GZipStream(InputStream, CompressionMode.Decompress, false); + } + else + { + return InputStream; + } + } + + internal static bool IsCompressedStream(Stream InputStream) + { + byte[] GZipHeader = new byte[3]; + InputStream.Read(GZipHeader, 0, 3); + return StructuralComparisons.StructuralEqualityComparer.Equals(GZipHeader, new byte[] { 0x1F, 0x8B, 0x08 }); + } + + internal static GZipStream GetDecompressedStream(Stream InputStream) + { + return new GZipStream(InputStream, CompressionMode.Decompress, false); + } + } +} diff --git a/WPinternals/HelperClasses/Converter.cs b/WPinternals/HelperClasses/Converter.cs new file mode 100644 index 0000000..808d7f5 --- /dev/null +++ b/WPinternals/HelperClasses/Converter.cs @@ -0,0 +1,74 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Text; + +namespace WPinternals.HelperClasses +{ + public static class Converter + { + public static string ConvertHexToString(byte[] Bytes, string Separator) + { + StringBuilder s = new(1000); + for (int i = Bytes.GetLowerBound(0); i <= Bytes.GetUpperBound(0); i++) + { + if (i != Bytes.GetLowerBound(0)) + { + s.Append(Separator); + } + + s.Append(Bytes[i].ToString("X2")); + } + return s.ToString(); + } + + public static byte[] ConvertStringToHex(string HexString) + { + if (HexString.Length % 2 == 1) + { + throw new Exception("The binary key cannot have an odd number of digits"); + } + + byte[] arr = new byte[HexString.Length >> 1]; + + for (int i = 0; i < HexString.Length >> 1; ++i) + { + arr[i] = (byte)((GetHexVal(HexString[i << 1]) << 4) + GetHexVal(HexString[(i << 1) + 1])); + } + + return arr; + } + + public static int GetHexVal(char hex) + { + int val = hex; + //For uppercase A-F letters: + //return val - (val < 58 ? 48 : 55); + //For lowercase a-f letters: + //return val - (val < 58 ? 48 : 87); + //Or the two combined, but a bit slower: + return val - (val < 58 ? 48 : val < 97 ? 55 : 87); + } + } +} diff --git a/WPinternals/HelperClasses/DecompressedStream.cs b/WPinternals/HelperClasses/DecompressedStream.cs new file mode 100644 index 0000000..aad0c8b --- /dev/null +++ b/WPinternals/HelperClasses/DecompressedStream.cs @@ -0,0 +1,181 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections; +using System.IO; +using System.IO.Compression; +using System.Text; + +namespace WPinternals.HelperClasses +{ + // For reading a compressed stream or normal stream + internal class DecompressedStream : Stream + { + private readonly Stream UnderlyingStream; + private readonly bool IsSourceCompressed; + private readonly ulong DecompressedLength; + private long ReadPosition = 0; + + // For reading a compressed stream + internal DecompressedStream(Stream InputStream) + { + UnderlyingStream = new ReadSeekableStream(InputStream, 0x100); + + byte[] Signature = new byte["CompressedPartition".Length + 2]; + Signature[0x00] = 0xFF; + Buffer.BlockCopy(Encoding.ASCII.GetBytes("CompressedPartition"), 0, Signature, 0x01, "CompressedPartition".Length); + Signature["CompressedPartition".Length + 1] = 0x00; + + int PrimaryHeaderSize = 0x0A + "CompressedPartition".Length; + byte[] SignatureRead = new byte[Signature.Length]; + UnderlyingStream.Read(SignatureRead, 0, Signature.Length); + + IsSourceCompressed = StructuralComparisons.StructuralEqualityComparer.Equals(Signature, SignatureRead); + if (IsSourceCompressed) + { + byte[] FormatVersionBytes = new byte[4]; + UnderlyingStream.Read(FormatVersionBytes, 0, 4); + if (BitConverter.ToUInt32(FormatVersionBytes, 0) > 1) // Max supported format version = 1 + { + throw new InvalidDataException(); + } + + byte[] HeaderSizeBytes = new byte[4]; + UnderlyingStream.Read(HeaderSizeBytes, 0, 4); + uint HeaderSize = BitConverter.ToUInt32(HeaderSizeBytes, 0); + + if (HeaderSize >= Signature.Length + 0x10) + { + byte[] DecompressedLengthBytes = new byte[8]; + UnderlyingStream.Read(DecompressedLengthBytes, 0, 8); + DecompressedLength = BitConverter.ToUInt64(DecompressedLengthBytes, 0); + } + else + { + throw new InvalidDataException(); + } + + uint HeaderBytesRemaining = (uint)(HeaderSize - Signature.Length - 0x10); + if (HeaderBytesRemaining > 0) + { + byte[] HeaderBytes = new byte[HeaderBytesRemaining]; + UnderlyingStream.Read(HeaderBytes, 0, (int)HeaderBytesRemaining); + } + + UnderlyingStream = new GZipStream(UnderlyingStream, CompressionMode.Decompress, false); + } + else + { + UnderlyingStream.Position = 0; + } + } + + public override bool CanRead + { + get + { + return true; + } + } + public override bool CanSeek + { + get + { + return false; + } + } + public override int Read(byte[] buffer, int offset, int count) + { + int RealCount = UnderlyingStream.Read(buffer, offset, count); + ReadPosition += RealCount; + return RealCount; + } + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotSupportedException(); + } + public override long Position + { + get + { + return ReadPosition; + } + set + { + throw new NotSupportedException(); + } + } + public override bool CanTimeout + { + get + { + return UnderlyingStream.CanTimeout; + } + } + public override bool CanWrite + { + get + { + return true; + } + } + public override long Length + { + get + { + if (IsSourceCompressed) + { + return (long)DecompressedLength; + } + else + { + return UnderlyingStream.Length; + } + } + } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + public override void Flush() + { + UnderlyingStream.Flush(); + } + public override void Close() + { + UnderlyingStream.Close(); + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + UnderlyingStream.Dispose(); + } + } + } +} diff --git a/WPinternals/HelperClasses/DelegateCommand.cs b/WPinternals/HelperClasses/DelegateCommand.cs new file mode 100644 index 0000000..8751c01 --- /dev/null +++ b/WPinternals/HelperClasses/DelegateCommand.cs @@ -0,0 +1,51 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + // This class is taken from the Prism library by Microsoft Patterns & Practices + // License: http://compositewpf.codeplex.com/license + public class DelegateCommand : DelegateCommandBase + { + public DelegateCommand(Action executeMethod) + : this(executeMethod, () => true) + { + } + + public DelegateCommand(Action executeMethod, Func canExecuteMethod) : base(o => executeMethod(), f => canExecuteMethod()) + { + } + + public bool CanExecute() + { + return CanExecute(null); + } + + public void Execute() + { + Execute(null); + } + } +} diff --git a/WPinternals/HelperClasses/DelegateCommandBase.cs b/WPinternals/HelperClasses/DelegateCommandBase.cs new file mode 100644 index 0000000..aca27bd --- /dev/null +++ b/WPinternals/HelperClasses/DelegateCommandBase.cs @@ -0,0 +1,118 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.Windows.Input; + +namespace WPinternals.HelperClasses +{ + // This class is taken from the Prism library by Microsoft Patterns & Practices + // License: http://compositewpf.codeplex.com/license + public abstract class DelegateCommandBase : ICommand, IActiveAware + { + private List _canExecuteChangedHandlers; + private bool _isActive; + private readonly Func canExecuteMethod; + private readonly Action executeMethod; + + public event EventHandler CanExecuteChanged + { + add + { + WeakEventHandlerManager.AddWeakReferenceHandler(ref _canExecuteChangedHandlers, value, 2); + } + remove + { + WeakEventHandlerManager.RemoveWeakReferenceHandler(_canExecuteChangedHandlers, value); + } + } + + public event EventHandler IsActiveChanged; + + protected DelegateCommandBase(Action executeMethod, Func canExecuteMethod) + { + if (executeMethod == null || canExecuteMethod == null) + { + throw new ArgumentNullException(nameof(executeMethod), "Delegate Command Delegates Cannot Be Null"); + } + this.executeMethod = executeMethod; + this.canExecuteMethod = canExecuteMethod; + } + + protected bool CanExecute(object parameter) + { + if (canExecuteMethod != null) + { + return canExecuteMethod(parameter); + } + return true; + } + + protected void Execute(object parameter) + { + executeMethod(parameter); + } + + protected virtual void OnCanExecuteChanged() + { + WeakEventHandlerManager.CallWeakReferenceHandlers(this, _canExecuteChangedHandlers); + } + + protected virtual void OnIsActiveChanged() + { + IsActiveChanged?.Invoke(this, EventArgs.Empty); + } + + public void RaiseCanExecuteChanged() + { + OnCanExecuteChanged(); + } + + bool ICommand.CanExecute(object parameter) + { + return CanExecute(parameter); + } + + void ICommand.Execute(object parameter) + { + Execute(parameter); + } + + public bool IsActive + { + get + { + return _isActive; + } + set + { + if (_isActive != value) + { + _isActive = value; + OnIsActiveChanged(); + } + } + } + } +} diff --git a/WPinternals/HelperClasses/ExtensionMethods.cs b/WPinternals/HelperClasses/ExtensionMethods.cs new file mode 100644 index 0000000..85c69f1 --- /dev/null +++ b/WPinternals/HelperClasses/ExtensionMethods.cs @@ -0,0 +1,49 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace WPinternals.HelperClasses +{ + internal static class ExtensionMethods + { + // This method was written by: Lawrence Johnston + // https://stackoverflow.com/a/22078975 + public static async Task TimeoutAfter(this Task task, TimeSpan timeout) + { + using var timeoutCancellationTokenSource = new CancellationTokenSource(); + var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)); + if (completedTask == task) + { + timeoutCancellationTokenSource.Cancel(); + return await task; // Very important in order to propagate exceptions + } + else + { + throw new TimeoutException("The operation has timed out."); + } + } + } +} diff --git a/WPinternals/HelperClasses/FlowDocumentScrollViewerNoMouseWheel.cs b/WPinternals/HelperClasses/FlowDocumentScrollViewerNoMouseWheel.cs new file mode 100644 index 0000000..493d077 --- /dev/null +++ b/WPinternals/HelperClasses/FlowDocumentScrollViewerNoMouseWheel.cs @@ -0,0 +1,35 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System.Windows.Controls; +using System.Windows.Input; + +namespace WPinternals.HelperClasses +{ + internal class FlowDocumentScrollViewerNoMouseWheel : FlowDocumentScrollViewer + { + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + } + } +} diff --git a/WPinternals/HelperClasses/GifImage.cs b/WPinternals/HelperClasses/GifImage.cs new file mode 100644 index 0000000..9f643d5 --- /dev/null +++ b/WPinternals/HelperClasses/GifImage.cs @@ -0,0 +1,150 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; + +namespace WPinternals.HelperClasses +{ + // This class was found online. + // Original author is probably: mdm20 + // https://stackoverflow.com/questions/5566330/get-gif-to-play-in-wpf-with-gifimage-class/5568703#5568703 + internal class GifImage : Image + { + private bool _isInitialized; + private GifBitmapDecoder _gifDecoder; + private Int32Animation _animation; + + public int FrameIndex + { + get + { + return (int)GetValue(FrameIndexProperty); + } + set + { + SetValue(FrameIndexProperty, value); + } + } + + private void Initialize() + { + _gifDecoder = new GifBitmapDecoder(new Uri("pack://application:,,," + GifSource), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); + _animation = new Int32Animation(0, _gifDecoder.Frames.Count - 1, new Duration(new TimeSpan(0, 0, 0, _gifDecoder.Frames.Count / 10, (int)((_gifDecoder.Frames.Count / 10.0 - _gifDecoder.Frames.Count / 10) * 1000)))) + { + RepeatBehavior = RepeatBehavior.Forever + }; + Source = _gifDecoder.Frames[0]; + + _isInitialized = true; + } + + static GifImage() + { + VisibilityProperty.OverrideMetadata(typeof(GifImage), + new FrameworkPropertyMetadata(VisibilityPropertyChanged)); + } + + private static void VisibilityPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if ((Visibility)e.NewValue == Visibility.Visible) + { + ((GifImage)sender).StartAnimation(); + } + else + { + ((GifImage)sender).StopAnimation(); + } + } + + public static readonly DependencyProperty FrameIndexProperty = + DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new UIPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex))); + + private static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev) + { + var gifImage = obj as GifImage; + gifImage.Source = gifImage._gifDecoder.Frames[(int)ev.NewValue]; + } + + public bool AutoStart + { + get + { + return (bool)GetValue(AutoStartProperty); + } + set + { + SetValue(AutoStartProperty, value); + } + } + + public static readonly DependencyProperty AutoStartProperty = + DependencyProperty.Register("AutoStart", typeof(bool), typeof(GifImage), new UIPropertyMetadata(false, AutoStartPropertyChanged)); + + private static void AutoStartPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + if ((bool)e.NewValue) + { + (sender as GifImage)?.StartAnimation(); + } + } + + public string GifSource + { + get + { + return (string)GetValue(GifSourceProperty); + } + set + { + SetValue(GifSourceProperty, value); + } + } + + public static readonly DependencyProperty GifSourceProperty = + DependencyProperty.Register("GifSource", typeof(string), typeof(GifImage), new UIPropertyMetadata(string.Empty, GifSourcePropertyChanged)); + + private static void GifSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + (sender as GifImage)?.Initialize(); + } + + public void StartAnimation() + { + if (!_isInitialized) + { + Initialize(); + } + + BeginAnimation(FrameIndexProperty, _animation); + } + + public void StopAnimation() + { + BeginAnimation(FrameIndexProperty, null); + } + } +} diff --git a/WPinternals/HelperClasses/GridViewColumnResize.cs b/WPinternals/HelperClasses/GridViewColumnResize.cs new file mode 100644 index 0000000..df17c2e --- /dev/null +++ b/WPinternals/HelperClasses/GridViewColumnResize.cs @@ -0,0 +1,321 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Windows; +using System.Windows.Controls; + +namespace WPinternals.HelperClasses +{ + // This class was written by: Rolf Wessels + // https://github.com/rolfwessels/lazycowprojects/tree/master/Wpf + + /// + /// Static class used to attach to wpf control + /// + public static class GridViewColumnResize + { + #region DependencyProperties + + public static readonly DependencyProperty WidthProperty = + DependencyProperty.RegisterAttached("Width", typeof(string), typeof(GridViewColumnResize), + new PropertyMetadata(OnSetWidthCallback)); + + public static readonly DependencyProperty GridViewColumnResizeBehaviorProperty = + DependencyProperty.RegisterAttached("GridViewColumnResizeBehavior", + typeof(GridViewColumnResizeBehavior), typeof(GridViewColumnResize), + null); + + public static readonly DependencyProperty EnabledProperty = + DependencyProperty.RegisterAttached("Enabled", typeof(bool), typeof(GridViewColumnResize), + new PropertyMetadata(OnSetEnabledCallback)); + + public static readonly DependencyProperty ListViewResizeBehaviorProperty = + DependencyProperty.RegisterAttached("ListViewResizeBehaviorProperty", + typeof(ListViewResizeBehavior), typeof(GridViewColumnResize), null); + + #endregion + + public static string GetWidth(DependencyObject obj) + { + return (string)obj.GetValue(WidthProperty); + } + + public static void SetWidth(DependencyObject obj, string value) + { + obj.SetValue(WidthProperty, value); + } + + public static bool GetEnabled(DependencyObject obj) + { + return (bool)obj.GetValue(EnabledProperty); + } + + public static void SetEnabled(DependencyObject obj, bool value) + { + obj.SetValue(EnabledProperty, value); + } + + #region CallBack + + private static void OnSetWidthCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + if (dependencyObject is GridViewColumn element) + { + GridViewColumnResizeBehavior behavior = GetOrCreateBehavior(element); + behavior.Width = e.NewValue as string; + } + else + { + Console.Error.WriteLine("Error: Expected type GridViewColumn but found " + + dependencyObject.GetType().Name); + } + } + + private static void OnSetEnabledCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e) + { + if (dependencyObject is ListView element) + { + ListViewResizeBehavior behavior = GetOrCreateBehavior(element); + behavior.Enabled = (bool)e.NewValue; + } + else + { + Console.Error.WriteLine("Error: Expected type ListView but found " + dependencyObject.GetType().Name); + } + } + + private static ListViewResizeBehavior GetOrCreateBehavior(ListView element) + { + if (element.GetValue(GridViewColumnResizeBehaviorProperty) is not ListViewResizeBehavior behavior) + { + behavior = new ListViewResizeBehavior(element); + element.SetValue(ListViewResizeBehaviorProperty, behavior); + } + + return behavior; + } + + private static GridViewColumnResizeBehavior GetOrCreateBehavior(GridViewColumn element) + { + if (element.GetValue(GridViewColumnResizeBehaviorProperty) is not GridViewColumnResizeBehavior behavior) + { + behavior = new GridViewColumnResizeBehavior(element); + element.SetValue(GridViewColumnResizeBehaviorProperty, behavior); + } + + return behavior; + } + + #endregion + + #region Nested type: GridViewColumnResizeBehavior + + // This class was written by: Rolf Wessels + // https://github.com/rolfwessels/lazycowprojects/tree/master/Wpf + + /// + /// GridViewColumn class that gets attached to the GridViewColumn control + /// + public class GridViewColumnResizeBehavior + { + private readonly GridViewColumn _element; + + public GridViewColumnResizeBehavior(GridViewColumn element) + { + _element = element; + } + + public string Width + { + get; set; + } + + public bool IsStatic + { + get + { + return StaticWidth >= 0; + } + } + + public double StaticWidth + { + get + { + return double.TryParse(Width, out double result) ? result : -1; + } + } + + public double Percentage + { + get + { + if (!IsStatic) + { + return Mulitplier * 100; + } + return 0; + } + } + + public double Mulitplier + { + get + { + if (Width == "*" || Width == "1*") + { + return 1; + } + + if (Width.EndsWith("*") && double.TryParse(Width[0..^1], out double perc)) + { + return perc; + } + return 1; + } + } + + public void SetWidth(double allowedSpace, double totalPercentage) + { + if (IsStatic) + { + _element.Width = StaticWidth; + } + else + { + _element.Width = (double)Math.Max(allowedSpace * (Percentage / totalPercentage), 0); + } + } + } + + #endregion + + #region Nested type: ListViewResizeBehavior + + // This class was written by: Rolf Wessels + // https://github.com/rolfwessels/lazycowprojects/tree/master/Wpf + + /// + /// ListViewResizeBehavior class that gets attached to the ListView control + /// + public class ListViewResizeBehavior + { + private const int Margin = 25; + private const long RefreshTime = Timeout.Infinite; + private const long Delay = 500; + + private readonly ListView _element; + private readonly Timer _timer; + + public ListViewResizeBehavior(ListView element) + { + _element = element ?? throw new ArgumentNullException(nameof(element)); + element.Loaded += OnLoaded; + + // Action for resizing and re-enable the size lookup + // This stops the columns from constantly resizing to improve performance + Action resizeAndEnableSize = () => + { + Resize(); + _element.SizeChanged += OnSizeChanged; + }; + _timer = new Timer(x => Application.Current.Dispatcher.BeginInvoke(resizeAndEnableSize), null, Delay, + RefreshTime); + } + + public bool Enabled + { + get; set; + } + + private void OnLoaded(object sender, RoutedEventArgs e) + { + _element.SizeChanged += OnSizeChanged; + } + + private void OnSizeChanged(object sender, SizeChangedEventArgs e) + { + if (e.WidthChanged) + { + _element.SizeChanged -= OnSizeChanged; + _timer.Change(Delay, RefreshTime); + } + } + + private void Resize() + { + if (Enabled) + { + double totalWidth = _element.ActualWidth; + if (_element.View is GridView gv) + { + double allowedSpace = totalWidth - GetAllocatedSpace(gv); + allowedSpace -= Margin; + double totalPercentage = GridViewColumnResizeBehaviors(gv).Sum(x => x.Percentage); + foreach (GridViewColumnResizeBehavior behavior in GridViewColumnResizeBehaviors(gv)) + { + behavior.SetWidth(allowedSpace, totalPercentage); + } + } + } + } + + private static IEnumerable GridViewColumnResizeBehaviors(GridView gv) + { + foreach (GridViewColumn t in gv.Columns) + { + if (t.GetValue(GridViewColumnResizeBehaviorProperty) is GridViewColumnResizeBehavior gridViewColumnResizeBehavior) + { + yield return gridViewColumnResizeBehavior; + } + } + } + + private static double GetAllocatedSpace(GridView gv) + { + double totalWidth = 0; + foreach (GridViewColumn t in gv.Columns) + { + if (t.GetValue(GridViewColumnResizeBehaviorProperty) is GridViewColumnResizeBehavior gridViewColumnResizeBehavior) + { + if (gridViewColumnResizeBehavior.IsStatic) + { + totalWidth += gridViewColumnResizeBehavior.StaticWidth; + } + } + else + { + totalWidth += t.ActualWidth; + } + } + return totalWidth; + } + } + + #endregion + } +} diff --git a/WPinternals/HelperClasses/HelperClasses.cs b/WPinternals/HelperClasses/HelperClasses.cs new file mode 100644 index 0000000..43c0af5 --- /dev/null +++ b/WPinternals/HelperClasses/HelperClasses.cs @@ -0,0 +1,30 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +namespace WPinternals.HelperClasses +{ + internal delegate void SetWorkingStatus(string Message, string SubMessage = null, ulong? MaxProgressValue = null, bool ShowAnimation = true, WPinternalsStatus Status = WPinternalsStatus.Undefined); + internal delegate void UpdateWorkingStatus(string Message, string SubMessage = null, ulong? CurrentProgressValue = null, WPinternalsStatus Status = WPinternalsStatus.Undefined); + internal delegate void ExitSuccess(string Message, string SubMessage = null); + internal delegate void ExitFailure(string Message, string SubMessage = null); +} diff --git a/WPinternals/HelperClasses/HexConverter.cs b/WPinternals/HelperClasses/HexConverter.cs new file mode 100644 index 0000000..f3e8b39 --- /dev/null +++ b/WPinternals/HelperClasses/HexConverter.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Globalization; +using System.Text; +using System.Windows; +using System.Windows.Data; + +namespace WPinternals.HelperClasses +{ + public class HexConverter : DependencyObject, IValueConverter + { + public static readonly DependencyProperty SeparatorProperty = + DependencyProperty.Register("OnTrue", typeof(object), typeof(HexConverter), + new PropertyMetadata(" ")); + + public object Separator + { + get + { + return GetValue(SeparatorProperty); + } + set + { + SetValue(SeparatorProperty, value); + } + } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value is byte[] bytes) + { + StringBuilder s = new(1000); + for (int i = bytes.GetLowerBound(0); i <= bytes.GetUpperBound(0); i++) + { + if (i != bytes.GetLowerBound(0)) + { + s.Append(Separator); + } + + s.Append(bytes[i].ToString("X2")); + } + return s.ToString(); + } + else + { + return ""; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public static object Default(Type type) + { + return type.IsValueType ? Activator.CreateInstance(type) : null; + } + } +} diff --git a/WPinternals/HelperClasses/IActiveAware.cs b/WPinternals/HelperClasses/IActiveAware.cs new file mode 100644 index 0000000..a57b22d --- /dev/null +++ b/WPinternals/HelperClasses/IActiveAware.cs @@ -0,0 +1,46 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + // This interface is taken from the Prism library by Microsoft Patterns & Practices + // License: http://compositewpf.codeplex.com/license + public interface IActiveAware + { + /// + /// Gets or sets a value indicating whether the object is active. + /// + /// if the object is active; otherwise . + bool IsActive + { + get; set; + } + + /// + /// Notifies that the value for property has changed. + /// + event EventHandler IsActiveChanged; + } +} diff --git a/WPinternals/HelperClasses/InverseObjectToVisibilityConverter.cs b/WPinternals/HelperClasses/InverseObjectToVisibilityConverter.cs new file mode 100644 index 0000000..94ebc5f --- /dev/null +++ b/WPinternals/HelperClasses/InverseObjectToVisibilityConverter.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace WPinternals.HelperClasses +{ + public class InverseObjectToVisibilityConverter : DependencyObject, IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + { + return "Visible"; + } + else + { + return "Collapsed"; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public static object Default(Type type) + { + return type.IsValueType ? Activator.CreateInstance(type) : null; + } + } +} diff --git a/WPinternals/HelperClasses/LogFile.cs b/WPinternals/HelperClasses/LogFile.cs new file mode 100644 index 0000000..a3e3cac --- /dev/null +++ b/WPinternals/HelperClasses/LogFile.cs @@ -0,0 +1,202 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Globalization; +using System.IO; +using System.Reflection; +using System.Text; + +namespace WPinternals.HelperClasses +{ + internal static class LogFile + { + private static readonly StreamWriter w = null; + private static readonly object lockobject = new(); +#if PREVIEW + private static string LogAction = null; + private static StringBuilder LogBuilder; +#endif + + static LogFile() + { + try + { + if (!Directory.Exists(Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals"))) + { + Directory.CreateDirectory(Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals")); + } + + w = File.AppendText(Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%\\WPInternals\\WPInternals.log")); + } + catch { } + } + + public static void Log(string logMessage, LogType Type = LogType.FileOnly) + { + if (w == null) + { + return; + } + + lock (lockobject) + { + if (Type == LogType.FileOnly || Type == LogType.FileAndConsole) + { + DateTime Now = DateTime.Now; + string Text = Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + ": " + logMessage; + w.WriteLine(Text); + w.Flush(); + +#if PREVIEW + if (LogAction != null) + LogBuilder.AppendLine(Text); +#endif + } + + if (CommandLine.IsConsoleVisible && (Type == LogType.ConsoleOnly || Type == LogType.FileAndConsole)) + { + Console.WriteLine(logMessage); + } + } + } + + public static void LogException(Exception Ex, LogType Type = LogType.FileAndConsole, string AdditionalInfo = null) + { + string Indent = ""; + Exception CurrentEx = Ex; + while (CurrentEx != null) + { + Log(Indent + "Error: " + RemoveBadChars(CurrentEx.Message).Replace("of type '.' ", "") + (AdditionalInfo == null ? "" : " - " + AdditionalInfo), Type); + AdditionalInfo = null; + if (CurrentEx is WPinternalsException) + { + Log(Indent + ((WPinternalsException)CurrentEx).SubMessage, Type); + } +#if DEBUG + if (CurrentEx.StackTrace != null) + { + Log(Indent + CurrentEx.StackTrace, LogType.FileOnly); + } +#endif + Indent += " "; + CurrentEx = CurrentEx.InnerException; + } + } + + private static string RemoveBadChars(string Text) + { + return System.Text.RegularExpressions.Regex.Replace(Text, @"[^\u0020-\u007E]+", string.Empty); + } + + public static void DumpLog(StreamReader r) + { + string line; + while ((line = r.ReadLine()) != null) + { + Console.WriteLine(line); + } + } + + public static void LogApplicationVersion() + { + Log("Windows Phone Internals version " + + Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Build.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString(), LogType.FileAndConsole); + Log("Copyright Heathcliff74", LogType.FileAndConsole); + } + + internal static void BeginAction(string Action) + { +#if PREVIEW + if (LogAction == null) + { + LogAction = Action; + LogBuilder = new StringBuilder(); + LogBuilder.AppendLine("Windows Phone Internals version " + + Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Build.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString()); + LogBuilder.AppendLine("Copyright Heathcliff74"); + LogBuilder.AppendLine("Action: " + Action); + if (App.Config.RegistrationName != null) + LogBuilder.AppendLine("Name: " + App.Config.RegistrationName); + if (App.Config.RegistrationEmail != null) + LogBuilder.AppendLine("Mail: " + App.Config.RegistrationEmail); + if (App.Config.RegistrationSkypeID != null) + LogBuilder.AppendLine("Skype: " + App.Config.RegistrationSkypeID); + if (App.Config.RegistrationTelegramID != null) + LogBuilder.AppendLine("Telegram: " + App.Config.RegistrationTelegramID); + if (Environment.MachineName != null) + LogBuilder.AppendLine("Machine: " + Environment.MachineName); + } +#endif + } + + internal static void EndAction() + { + EndAction(null); + } + + internal static void EndAction(string Action) + { +#if PREVIEW + if (LogAction != null && (Action == null || LogAction == Action)) + { + Action = LogAction; + LogAction = null; + string FileName = ""; + if (App.Config.RegistrationName != null) + FileName += App.Config.RegistrationName + " - "; + FileName += DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + " - " + Action + " - " + + Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Build.ToString() + "." + + Assembly.GetExecutingAssembly().GetName().Version.Revision.ToString() + ".log"; + + // Normalize filename + try + { + FileName = Encoding.ASCII.GetString(Encoding.GetEncoding("ISO-8859-8").GetBytes(FileName)); + } + catch { } + FileName = FileName.Replace("?", ""); + + if (Action.ToLower() == "registration") + Uploader.Upload(FileName, LogBuilder.ToString()); + else + { + try + { + Uploader.Upload(FileName, LogBuilder.ToString()); + } + catch { } + } + } +#endif + } + } +} diff --git a/WPinternals/HelperClasses/LogType.cs b/WPinternals/HelperClasses/LogType.cs new file mode 100644 index 0000000..5442401 --- /dev/null +++ b/WPinternals/HelperClasses/LogType.cs @@ -0,0 +1,32 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +namespace WPinternals.HelperClasses +{ + internal enum LogType + { + FileOnly, + FileAndConsole, + ConsoleOnly + }; +} diff --git a/WPinternals/HelperClasses/ObjectToVisibilityConverter.cs b/WPinternals/HelperClasses/ObjectToVisibilityConverter.cs new file mode 100644 index 0000000..0f89fe9 --- /dev/null +++ b/WPinternals/HelperClasses/ObjectToVisibilityConverter.cs @@ -0,0 +1,55 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Data; + +namespace WPinternals.HelperClasses +{ + public class ObjectToVisibilityConverter : DependencyObject, IValueConverter + { + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + if (value == null) + { + return "Collapsed"; + } + else + { + return "Visible"; + } + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + + public static object Default(Type type) + { + return type.IsValueType ? Activator.CreateInstance(type) : null; + } + } +} diff --git a/WPinternals/HelperClasses/PE.cs b/WPinternals/HelperClasses/PE.cs new file mode 100644 index 0000000..f2f68a1 --- /dev/null +++ b/WPinternals/HelperClasses/PE.cs @@ -0,0 +1,128 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + internal static class PE + { + internal static byte[] GetResource(byte[] PEfile, int[] Index) + { + // Explanation of PE header here: + // https://msdn.microsoft.com/en-us/library/ms809762.aspx?f=255&MSPPError=-2147217396 + + uint PEPointer = ByteOperations.ReadUInt32(PEfile, 0x3C); + ushort OptionalHeaderSize = ByteOperations.ReadUInt16(PEfile, PEPointer + 0x14); + uint SectionTablePointer = PEPointer + 0x18 + OptionalHeaderSize; + ushort SectionCount = ByteOperations.ReadUInt16(PEfile, PEPointer + 0x06); + uint? ResourceSectionEntryPointer = null; + for (int i = 0; i < SectionCount; i++) + { + string SectionName = ByteOperations.ReadAsciiString(PEfile, (uint)(SectionTablePointer + i * 0x28), 8); + int e = SectionName.IndexOf('\0'); + if (e >= 0) + { + SectionName = SectionName.Substring(0, e); + } + + if (SectionName == ".rsrc") + { + ResourceSectionEntryPointer = (uint)(SectionTablePointer + i * 0x28); + break; + } + } + if (ResourceSectionEntryPointer == null) + { + throw new WPinternalsException("Resource-section not found"); + } + + uint ResourceRawSize = ByteOperations.ReadUInt32(PEfile, (uint)ResourceSectionEntryPointer + 0x10); + uint ResourceRawPointer = ByteOperations.ReadUInt32(PEfile, (uint)ResourceSectionEntryPointer + 0x14); + uint ResourceVirtualPointer = ByteOperations.ReadUInt32(PEfile, (uint)ResourceSectionEntryPointer + 0x0C); + + uint p = ResourceRawPointer; + for (int i = 0; i < Index.Length; i++) + { + ushort ResourceNamedEntryCount = ByteOperations.ReadUInt16(PEfile, p + 0x0c); + ushort ResourceIdEntryCount = ByteOperations.ReadUInt16(PEfile, p + 0x0e); + for (int j = ResourceNamedEntryCount; j < ResourceNamedEntryCount + ResourceIdEntryCount; j++) + { + uint ResourceID = ByteOperations.ReadUInt32(PEfile, (uint)(p + 0x10 + j * 8)); + uint NextPointer = ByteOperations.ReadUInt32(PEfile, (uint)(p + 0x10 + j * 8 + 4)); + if (ResourceID == (uint)Index[i]) + { + // Check high bit + if ((NextPointer & 0x80000000) == 0 != (i == Index.Length - 1)) + { + throw new WPinternalsException("Bad resource path"); + } + + p = ResourceRawPointer + (NextPointer & 0x7fffffff); + break; + } + } + } + + uint ResourceValuePointer = ByteOperations.ReadUInt32(PEfile, p) - ResourceVirtualPointer + ResourceRawPointer; + uint ResourceValueSize = ByteOperations.ReadUInt32(PEfile, p + 4); + + byte[] ResourceValue = new byte[ResourceValueSize]; + Array.Copy(PEfile, ResourceValuePointer, ResourceValue, 0, ResourceValueSize); + + return ResourceValue; + } + + internal static Version GetFileVersion(byte[] PEfile) + { + byte[] version = GetResource(PEfile, [(int)ResourceType.RT_VERSION, 1, 1033]); + + // RT_VERSION format: + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx + const uint FixedFileInfoPointer = 0x28; + ushort Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0A); + ushort Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x08); + ushort Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0E); + ushort Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x0C); + + return new Version(Major, Minor, Build, Revision); + } + + internal static Version GetProductVersion(byte[] PEfile) + { + byte[] version = GetResource(PEfile, [(int)ResourceType.RT_VERSION, 1, 1033]); + + // RT_VERSION format: + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms647001(v=vs.85).aspx + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms646997(v=vs.85).aspx + const uint FixedFileInfoPointer = 0x28; + ushort Major = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x12); + ushort Minor = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x10); + ushort Build = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x16); + ushort Revision = ByteOperations.ReadUInt16(version, FixedFileInfoPointer + 0x14); + + return new Version(Major, Minor, Build, Revision); + } + } +} diff --git a/WPinternals/HelperClasses/Paragraph.cs b/WPinternals/HelperClasses/Paragraph.cs new file mode 100644 index 0000000..f47cbd0 --- /dev/null +++ b/WPinternals/HelperClasses/Paragraph.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Linq; +using System.Windows.Documents; + +namespace WPinternals.HelperClasses +{ + // Overloaded Paragraph class to remove empty Run-elements, caused by auto-formatting new-lines in the XAML + // Use helpers:Paragraph in a FlowDocument + // This correction only works at run-time + public class Paragraph : System.Windows.Documents.Paragraph + { + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + int inlinesCount = Inlines.Count; + for (int i = 0; i < inlinesCount; i++) + { + Inline inline = Inlines.ElementAt(i); + if (inline is Run run) + { + if (run.Text == Convert.ToChar(32).ToString()) //ACSII 32 is the white space + { + run.Text = string.Empty; + } + } + } + } + } +} diff --git a/WPinternals/HelperClasses/ProgressUpdater.cs b/WPinternals/HelperClasses/ProgressUpdater.cs new file mode 100644 index 0000000..0b31fb0 --- /dev/null +++ b/WPinternals/HelperClasses/ProgressUpdater.cs @@ -0,0 +1,88 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + internal class ProgressUpdater + { + private readonly DateTime InitTime; + private DateTime LastUpdateTime; + private readonly ulong MaxValue; + private readonly Action ProgressUpdateCallback; + internal int ProgressPercentage; + + internal ProgressUpdater(ulong MaxValue, Action ProgressUpdateCallback) + { + InitTime = DateTime.Now; + LastUpdateTime = DateTime.Now; + this.MaxValue = MaxValue; + this.ProgressUpdateCallback = ProgressUpdateCallback; + SetProgress(0); + } + + private ulong _Progress; + internal ulong Progress + { + get + { + return _Progress; + } + } + + internal void SetProgress(ulong NewValue) + { + if (_Progress != NewValue) + { + int PreviousProgressPercentage = (int)((double)_Progress / MaxValue * 100); + ProgressPercentage = (int)((double)NewValue / MaxValue * 100); + + _Progress = NewValue; + + if (DateTime.Now - LastUpdateTime > TimeSpan.FromSeconds(0.5) || ProgressPercentage == 100) + { +#if DEBUG + Console.WriteLine("Init time: " + InitTime.ToShortTimeString() + " / Now: " + DateTime.Now.ToString() + " / NewValue: " + NewValue.ToString() + " / MaxValue: " + MaxValue.ToString() + " ->> Percentage: " + ProgressPercentage.ToString() + " / Remaining: " + TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - (double)NewValue / MaxValue))).ToString()); +#endif + + if (DateTime.Now - InitTime < TimeSpan.FromSeconds(30) && ProgressPercentage < 15) + { + ProgressUpdateCallback(ProgressPercentage, null); + } + else + { + ProgressUpdateCallback(ProgressPercentage, TimeSpan.FromTicks((long)((DateTime.Now - InitTime).Ticks / ((double)NewValue / MaxValue) * (1 - (double)NewValue / MaxValue)))); + } + + LastUpdateTime = DateTime.Now; + } + } + } + + internal void IncreaseProgress(ulong Progress) + { + SetProgress(_Progress + Progress); + } + } +} diff --git a/WPinternals/HelperClasses/ReadSeekableStream.cs b/WPinternals/HelperClasses/ReadSeekableStream.cs new file mode 100644 index 0000000..3f1c431 --- /dev/null +++ b/WPinternals/HelperClasses/ReadSeekableStream.cs @@ -0,0 +1,342 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.IO; + +namespace WPinternals.HelperClasses +{ + // This class is written by: Eugene Beresovsky + // https://stackoverflow.com/questions/13035925/stream-wrapper-to-make-stream-seekable/28036366#28036366 + internal class ReadSeekableStream : Stream + { + private long _underlyingPosition; + private readonly byte[] _seekBackBuffer; + private int _seekBackBufferCount; + private int _seekBackBufferIndex; + private readonly Stream _underlyingStream; + + public ReadSeekableStream(Stream underlyingStream, int seekBackBufferSize) + { + if (!underlyingStream.CanRead) + { + throw new Exception("Provided stream " + underlyingStream + " is not readable"); + } + + _underlyingStream = underlyingStream; + _seekBackBuffer = new byte[seekBackBufferSize]; + } + + public override bool CanRead + { + get + { + return true; + } + } + public override bool CanSeek + { + get + { + return true; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int copiedFromBackBufferCount = 0; + if (_seekBackBufferIndex < _seekBackBufferCount) + { + copiedFromBackBufferCount = Math.Min(count, _seekBackBufferCount - _seekBackBufferIndex); + Buffer.BlockCopy(_seekBackBuffer, _seekBackBufferIndex, buffer, offset, copiedFromBackBufferCount); + offset += copiedFromBackBufferCount; + count -= copiedFromBackBufferCount; + _seekBackBufferIndex += copiedFromBackBufferCount; + } + int bytesReadFromUnderlying = 0; + if (count > 0) + { + bytesReadFromUnderlying = _underlyingStream.Read(buffer, offset, count); + if (bytesReadFromUnderlying > 0) + { + _underlyingPosition += bytesReadFromUnderlying; + + var copyToBufferCount = Math.Min(bytesReadFromUnderlying, _seekBackBuffer.Length); + var copyToBufferOffset = Math.Min(_seekBackBufferCount, _seekBackBuffer.Length - copyToBufferCount); + var bufferBytesToMove = Math.Min(_seekBackBufferCount - 1, copyToBufferOffset); + + if (bufferBytesToMove > 0) + { + Buffer.BlockCopy(_seekBackBuffer, _seekBackBufferCount - bufferBytesToMove, _seekBackBuffer, 0, bufferBytesToMove); + } + + Buffer.BlockCopy(buffer, offset, _seekBackBuffer, copyToBufferOffset, copyToBufferCount); + _seekBackBufferCount = Math.Min(_seekBackBuffer.Length, _seekBackBufferCount + copyToBufferCount); + _seekBackBufferIndex = _seekBackBufferCount; + } + } + return copiedFromBackBufferCount + bytesReadFromUnderlying; + } + + public override long Seek(long offset, SeekOrigin origin) + { + if (origin == SeekOrigin.End) + { + return SeekFromEnd((int)Math.Max(0, -offset)); + } + + var relativeOffset = origin == SeekOrigin.Current + ? offset + : offset - Position; + + if (relativeOffset == 0) + { + return Position; + } + else if (relativeOffset > 0) + { + return SeekForward(relativeOffset); + } + else + { + return SeekBackwards(-relativeOffset); + } + } + + private long SeekForward(long origOffset) + { + long offset = origOffset; + var seekBackBufferLength = _seekBackBuffer.Length; + + int backwardSoughtBytes = _seekBackBufferCount - _seekBackBufferIndex; + int seekForwardInBackBuffer = (int)Math.Min(offset, backwardSoughtBytes); + offset -= seekForwardInBackBuffer; + _seekBackBufferIndex += seekForwardInBackBuffer; + + if (offset > 0) + { + // first completely fill seekBackBuffer to remove special cases from while loop below + if (_seekBackBufferCount < seekBackBufferLength) + { + var maxRead = seekBackBufferLength - _seekBackBufferCount; + if (offset < maxRead) + { + maxRead = (int)offset; + } + + var bytesRead = _underlyingStream.Read(_seekBackBuffer, _seekBackBufferCount, maxRead); + _underlyingPosition += bytesRead; + _seekBackBufferCount += bytesRead; + _seekBackBufferIndex = _seekBackBufferCount; + if (bytesRead < maxRead) + { + if (_seekBackBufferCount < offset) + { + throw new NotSupportedException("Reached end of stream seeking forward " + origOffset + " bytes"); + } + + return Position; + } + offset -= bytesRead; + } + + // now alternate between filling tempBuffer and seekBackBuffer + bool fillTempBuffer = true; + var tempBuffer = new byte[seekBackBufferLength]; + while (offset > 0) + { + var maxRead = offset < seekBackBufferLength ? (int)offset : seekBackBufferLength; + var bytesRead = _underlyingStream.Read(fillTempBuffer ? tempBuffer : _seekBackBuffer, 0, maxRead); + _underlyingPosition += bytesRead; + var bytesReadDiff = maxRead - bytesRead; + offset -= bytesRead; + if (bytesReadDiff > 0 /* reached end-of-stream */ || offset == 0) + { + if (fillTempBuffer) + { + if (bytesRead > 0) + { + Buffer.BlockCopy(_seekBackBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); + Buffer.BlockCopy(tempBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); + } + } + else + { + if (bytesRead > 0) + { + Buffer.BlockCopy(_seekBackBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); + } + + Buffer.BlockCopy(tempBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); + } + if (offset > 0) + { + throw new NotSupportedException("Reached end of stream seeking forward " + origOffset + " bytes"); + } + } + fillTempBuffer = !fillTempBuffer; + } + } + return Position; + } + + private long SeekBackwards(long offset) + { + var intOffset = (int)offset; + if (offset > int.MaxValue || intOffset > _seekBackBufferIndex) + { + throw new NotSupportedException("Cannot currently seek backwards more than " + _seekBackBufferIndex + " bytes"); + } + + _seekBackBufferIndex -= intOffset; + return Position; + } + + private long SeekFromEnd(long offset) + { + var intOffset = (int)offset; + var seekBackBufferLength = _seekBackBuffer.Length; + if (offset > int.MaxValue || intOffset > seekBackBufferLength) + { + throw new NotSupportedException("Cannot seek backwards from end more than " + seekBackBufferLength + " bytes"); + } + + // first completely fill seekBackBuffer to remove special cases from while loop below + if (_seekBackBufferCount < seekBackBufferLength) + { + var maxRead = seekBackBufferLength - _seekBackBufferCount; + var bytesRead = _underlyingStream.Read(_seekBackBuffer, _seekBackBufferCount, maxRead); + _underlyingPosition += bytesRead; + _seekBackBufferCount += bytesRead; + _seekBackBufferIndex = Math.Max(0, _seekBackBufferCount - intOffset); + if (bytesRead < maxRead) + { + if (_seekBackBufferCount < intOffset) + { + throw new NotSupportedException("Could not seek backwards from end " + intOffset + " bytes"); + } + + return Position; + } + } + else + { + _seekBackBufferIndex = _seekBackBufferCount; + } + + // now alternate between filling tempBuffer and seekBackBuffer + bool fillTempBuffer = true; + var tempBuffer = new byte[seekBackBufferLength]; + while (true) + { + var bytesRead = _underlyingStream.Read(fillTempBuffer ? tempBuffer : _seekBackBuffer, 0, seekBackBufferLength); + _underlyingPosition += bytesRead; + var bytesReadDiff = seekBackBufferLength - bytesRead; + if (bytesReadDiff > 0) // reached end-of-stream + { + if (fillTempBuffer) + { + if (bytesRead > 0) + { + Buffer.BlockCopy(_seekBackBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); + Buffer.BlockCopy(tempBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); + } + } + else + { + if (bytesRead > 0) + { + Buffer.BlockCopy(_seekBackBuffer, 0, _seekBackBuffer, bytesReadDiff, bytesRead); + } + + Buffer.BlockCopy(tempBuffer, bytesRead, _seekBackBuffer, 0, bytesReadDiff); + } + _seekBackBufferIndex -= intOffset; + return Position; + } + fillTempBuffer = !fillTempBuffer; + } + } + + public override long Position + { + get + { + return _underlyingPosition - (_seekBackBufferCount - _seekBackBufferIndex); + } + set + { + Seek(value, SeekOrigin.Begin); + } + } + + public override bool CanTimeout + { + get + { + return _underlyingStream.CanTimeout; + } + } + public override bool CanWrite + { + get + { + return _underlyingStream.CanWrite; + } + } + public override long Length + { + get + { + return _underlyingStream.Length; + } + } + public override void SetLength(long value) + { + _underlyingStream.SetLength(value); + } + public override void Write(byte[] buffer, int offset, int count) + { + _underlyingStream.Write(buffer, offset, count); + } + public override void Flush() + { + _underlyingStream.Flush(); + } + public override void Close() + { + _underlyingStream.Close(); + } + public new void Dispose() + { + _underlyingStream.Dispose(); + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + _underlyingStream.Dispose(); + } + } + } +} diff --git a/WPinternals/HelperClasses/ResourceType.cs b/WPinternals/HelperClasses/ResourceType.cs new file mode 100644 index 0000000..db3bbba --- /dev/null +++ b/WPinternals/HelperClasses/ResourceType.cs @@ -0,0 +1,52 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +namespace WPinternals.HelperClasses +{ + internal enum ResourceType + { + RT_CURSOR = 1, + RT_BITMAP = 2, + RT_ICON = 3, + RT_MENU = 4, + RT_DIALOG = 5, + RT_STRING = 6, + RT_FONTDIR = 7, + RT_FONT = 8, + RT_ACCELERATOR = 9, + RT_RCDATA = 10, + RT_MESSAGETABLE = 11, + RT_GROUP_CURSOR = RT_CURSOR + 11, + RT_GROUP_ICON = RT_ICON + 11, + RT_VERSION = 16, + RT_DLGINCLUDE = 17, + RT_PLUGPLAY = 19, + RT_VXD = 20, + RT_ANICURSOR = 21, + RT_ANIICON = 22, + RT_HTML = 23, + RT_MANIFEST = 24, + RT_DLGINIT = 240, + RT_TOOLBAR = 241 + }; +} diff --git a/WPinternals/HelperClasses/SeekableStream.cs b/WPinternals/HelperClasses/SeekableStream.cs new file mode 100644 index 0000000..a405a06 --- /dev/null +++ b/WPinternals/HelperClasses/SeekableStream.cs @@ -0,0 +1,183 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.IO; + +namespace WPinternals.HelperClasses +{ + internal class SeekableStream : Stream + { + private Stream UnderlyingStream; + private long ReadPosition = 0; + private readonly Func StreamInitializer; + private readonly long UnderlyingStreamLength; + + // For reading a compressed stream + internal SeekableStream(Func StreamInitializer, long? Length = null) + { + this.StreamInitializer = StreamInitializer; + UnderlyingStream = StreamInitializer(); + if (Length != null) + { + UnderlyingStreamLength = (long)Length; + } + else + { + try + { + UnderlyingStreamLength = UnderlyingStream.Length; + } + catch + { + throw new ArgumentException("Unknown stream length"); + } + } + } + + public override bool CanRead + { + get + { + return true; + } + } + public override bool CanSeek + { + get + { + return true; + } + } + public override int Read(byte[] buffer, int offset, int count) + { + int RealCount = UnderlyingStream.Read(buffer, offset, count); + ReadPosition += RealCount; + return RealCount; + } + public override long Seek(long offset, SeekOrigin origin) + { + if (UnderlyingStream.CanSeek) + { + ReadPosition = UnderlyingStream.Seek(offset, origin); + return ReadPosition; + } + else + { + long NewPosition = 0; + switch (origin) + { + case SeekOrigin.Begin: + NewPosition = offset; + break; + case SeekOrigin.Current: + NewPosition = ReadPosition + offset; + break; + case SeekOrigin.End: + NewPosition = UnderlyingStreamLength - offset; + break; + } + if (NewPosition < 0 || NewPosition > UnderlyingStreamLength) + { + throw new ArgumentOutOfRangeException(nameof(offset)); + } + + if (NewPosition < ReadPosition) + { + UnderlyingStream.Close(); + UnderlyingStream = StreamInitializer(); + ReadPosition = 0; + } + ulong Remaining; + byte[] Buffer = new byte[16384]; + while (ReadPosition < NewPosition) + { + Remaining = (ulong)(NewPosition - ReadPosition); + if (Remaining > (ulong)Buffer.Length) + { + Remaining = (ulong)Buffer.Length; + } + + UnderlyingStream.Read(Buffer, 0, (int)Remaining); + ReadPosition += (long)Remaining; + } + return ReadPosition; + } + } + public override long Position + { + get + { + return ReadPosition; + } + set + { + Seek(value, SeekOrigin.Begin); + } + } + public override bool CanTimeout + { + get + { + return UnderlyingStream.CanTimeout; + } + } + public override bool CanWrite + { + get + { + return false; + } + } + public override long Length + { + get + { + return UnderlyingStreamLength; + } + } + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + public override void Flush() + { + throw new NotSupportedException(); + } + public override void Close() + { + UnderlyingStream.Close(); + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + UnderlyingStream.Dispose(); + } + } + } +} diff --git a/WPinternals/HelperClasses/Uploader.cs b/WPinternals/HelperClasses/Uploader.cs new file mode 100644 index 0000000..e157bb7 --- /dev/null +++ b/WPinternals/HelperClasses/Uploader.cs @@ -0,0 +1,81 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Text; +using System.Threading.Tasks; + +namespace WPinternals.HelperClasses +{ +#if PREVIEW + internal static class Uploader + { + internal static List Uploads = []; + + internal static void Upload(string FileName, string Text) + { + byte[] byteArray = Encoding.UTF8.GetBytes(Text); + MemoryStream FileStream = new(byteArray); + Upload(FileName, FileStream); + } + + internal static void Upload(string FileName, byte[] Data) + { + Upload(FileName, new MemoryStream(Data)); + } + + internal static void Upload(string FileName, Stream FileStream) + { + //TODO: Fix + //Upload(new Uri(@"https://www.wpinternals.net/upload.php", UriKind.Absolute), "uploadedfile", FileName, FileStream); + } + + private static void Upload(Uri Address, string InputName, string FileName, Stream FileStream) + { + ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; + System.Net.Http.HttpClient httpClient = new(); + System.Net.Http.MultipartFormDataContent form = []; + System.Net.Http.StreamContent Content = new(FileStream); + Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/plain"); + form.Add(Content, InputName, FileName); + Task UploadTask = httpClient.PostAsync(Address, form); + + Uploads.Add( + UploadTask.ContinueWith((t) => + { + Uploads.Remove(t); + httpClient.Dispose(); + }) + ); + } + + internal static void WaitForUploads() + { + Task.WaitAll([.. Uploads]); + } + } +#endif +} diff --git a/WPinternals/HelperClasses/WPinternalsException.cs b/WPinternals/HelperClasses/WPinternalsException.cs new file mode 100644 index 0000000..5e0be32 --- /dev/null +++ b/WPinternals/HelperClasses/WPinternalsException.cs @@ -0,0 +1,43 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; + +namespace WPinternals.HelperClasses +{ + internal class WPinternalsException : Exception + { + // Message and SubMessaage are always printable + internal string SubMessage = null; + + internal WPinternalsException() : base() { } + + internal WPinternalsException(string Message) : base(Message) { } + + internal WPinternalsException(string Message, Exception InnerException) : base(Message, InnerException) { } + + internal WPinternalsException(string Message, string SubMessage) : base(Message) { this.SubMessage = SubMessage; } + + internal WPinternalsException(string Message, string SubMessage, Exception InnerException) : base(Message, InnerException) { this.SubMessage = SubMessage; } + } +} diff --git a/WPinternals/HelperClasses/WPinternalsStatus.cs b/WPinternals/HelperClasses/WPinternalsStatus.cs new file mode 100644 index 0000000..5ac780c --- /dev/null +++ b/WPinternals/HelperClasses/WPinternalsStatus.cs @@ -0,0 +1,36 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +namespace WPinternals.HelperClasses +{ + internal enum WPinternalsStatus + { + Undefined, + Scanning, + Flashing, + Patching, + WaitingForManualReset, + SwitchingMode, + Initializing + }; +} diff --git a/WPinternals/HelperClasses/WeakEventHandlerManager.cs b/WPinternals/HelperClasses/WeakEventHandlerManager.cs new file mode 100644 index 0000000..e20de60 --- /dev/null +++ b/WPinternals/HelperClasses/WeakEventHandlerManager.cs @@ -0,0 +1,132 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. +// +// Some of the classes and functions in this file were found online. +// Where possible the original authors are referenced. + +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Threading; + +namespace WPinternals.HelperClasses +{ + // This class is taken from the Prism library by Microsoft Patterns & Practices + // License: http://compositewpf.codeplex.com/license + internal static class WeakEventHandlerManager + { + public static void AddWeakReferenceHandler(ref List handlers, EventHandler handler, int defaultListSize) + { + (handlers ??= defaultListSize > 0 ? new List(defaultListSize) : []).Add(new WeakReference(handler)); + } + + private static void CallHandler(object sender, EventHandler eventHandler) + { + DispatcherProxy proxy = DispatcherProxy.CreateDispatcher(); + if (eventHandler != null) + { + if (proxy?.CheckAccess() == false) + { + proxy.BeginInvoke(new Action(CallHandler), [sender, eventHandler]); + } + else + { + eventHandler(sender, EventArgs.Empty); + } + } + } + + public static void CallWeakReferenceHandlers(object sender, List handlers) + { + if (handlers != null) + { + EventHandler[] callees = new EventHandler[handlers.Count]; + int count = 0; + count = CleanupOldHandlers(handlers, callees, count); + for (int i = 0; i < count; i++) + { + CallHandler(sender, callees[i]); + } + } + } + + private static int CleanupOldHandlers(List handlers, EventHandler[] callees, int count) + { + for (int i = handlers.Count - 1; i >= 0; i--) + { + WeakReference reference = handlers[i]; + if (reference.Target is not EventHandler target) + { + handlers.RemoveAt(i); + } + else + { + callees[count] = target; + count++; + } + } + return count; + } + + public static void RemoveWeakReferenceHandler(List handlers, EventHandler handler) + { + if (handlers != null) + { + for (int i = handlers.Count - 1; i >= 0; i--) + { + WeakReference reference = handlers[i]; + if (reference.Target is not EventHandler target || target == handler) + { + handlers.RemoveAt(i); + } + } + } + } + + private class DispatcherProxy + { + private readonly Dispatcher innerDispatcher; + + private DispatcherProxy(Dispatcher dispatcher) + { + innerDispatcher = dispatcher; + } + + public DispatcherOperation BeginInvoke(Delegate method, params object[] args) + { + return innerDispatcher.BeginInvoke(method, DispatcherPriority.Normal, args); + } + + public bool CheckAccess() + { + return innerDispatcher.CheckAccess(); + } + + public static DispatcherProxy CreateDispatcher() + { + if (Application.Current == null) + { + return null; + } + return new DispatcherProxy(Application.Current.Dispatcher); + } + } + } +} diff --git a/WPinternals/Models/FFU.cs b/WPinternals/Models/FFU.cs index f1b59e0..2aec0a9 100644 --- a/WPinternals/Models/FFU.cs +++ b/WPinternals/Models/FFU.cs @@ -20,6 +20,7 @@ using System; using System.IO; +using WPinternals.HelperClasses; namespace WPinternals { @@ -288,7 +289,7 @@ internal byte[] GetPartition(string Name) Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase)); if (Target == null) { - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(Name)); } return GetSectors((int)Target.FirstSector, (int)(Target.LastSector - Target.FirstSector + 1)); @@ -314,7 +315,7 @@ private void WritePartition(string Name, string FilePath, Action Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase)); if (Target == null) { - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(Name)); } int FirstChunk = GetChunkIndexFromSectorIndex((int)Target.FirstSector); diff --git a/WPinternals/Models/GPT.cs b/WPinternals/Models/GPT.cs index 9ece00d..edf5b64 100644 --- a/WPinternals/Models/GPT.cs +++ b/WPinternals/Models/GPT.cs @@ -24,6 +24,7 @@ using System.IO.Compression; using System.Linq; using System.Xml.Serialization; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/LumiaDownloadModel.cs b/WPinternals/Models/Lumia/LumiaDownloadModel.cs similarity index 85% rename from WPinternals/Models/LumiaDownloadModel.cs rename to WPinternals/Models/Lumia/LumiaDownloadModel.cs index e9c6377..dfc4cba 100644 --- a/WPinternals/Models/LumiaDownloadModel.cs +++ b/WPinternals/Models/Lumia/LumiaDownloadModel.cs @@ -31,8 +31,9 @@ using System.Threading.Tasks; using System.Xml; using System.Xml.Serialization; +using WPinternals.HelperClasses; -namespace WPinternals +namespace WPinternals.Models.Lumia { internal static class LumiaDownloadModel { @@ -321,7 +322,7 @@ internal static string[] SearchEmergencyFiles(string ProductType) LogFile.Log("Getting Emergency files for: " + ProductType, LogType.FileAndConsole); - if ((ProductType == "RM-1072") || (ProductType == "RM-1073")) + if (ProductType == "RM-1072" || ProductType == "RM-1073") { LogFile.Log("Due to mix-up in online-repository, redirecting to emergency files of RM-1113", LogType.FileAndConsole); ProductType = "RM-1113"; @@ -486,20 +487,20 @@ public DiscoveryParameters() : this(DiscoveryCondition.Default) public DiscoveryParameters(DiscoveryCondition Condition) { - this.apiVersion = "1"; - this.query = new DiscoveryQueryParameters(); - this.condition = []; + apiVersion = "1"; + query = new DiscoveryQueryParameters(); + condition = []; if (Condition == DiscoveryCondition.All) { - this.condition.Add("all"); + condition.Add("all"); return; } if (Condition == DiscoveryCondition.Latest) { - this.condition.Add("latest"); + condition.Add("latest"); return; } - this.condition.Add("default"); + condition.Add("default"); } } @@ -517,18 +518,18 @@ public class ExtendedAttributes : ISerializable public ExtendedAttributes() { - this.Dictionary = []; + Dictionary = []; } protected ExtendedAttributes(SerializationInfo info, StreamingContext context) { if (info != null) { - this.Dictionary = []; + Dictionary = []; SerializationInfoEnumerator Enumerator = info.GetEnumerator(); while (Enumerator.MoveNext()) { - this.Dictionary.Add(Enumerator.Current.Name, (string)Enumerator.Current.Value); + Dictionary.Add(Enumerator.Current.Name, (string)Enumerator.Current.Value); } } } @@ -537,9 +538,9 @@ public virtual void GetObjectData(SerializationInfo info, StreamingContext conte { if (info != null) { - foreach (string Current in this.Dictionary.Keys) + foreach (string Current in Dictionary.Keys) { - info.AddValue(Current, this.Dictionary[Current]); + info.AddValue(Current, Dictionary[Current]); } } } @@ -651,209 +652,350 @@ public static class DPL public class BasicProductCodes { [XmlElement(ElementName = "BasicProductCode")] - public List BasicProductCode { get; set; } + public List BasicProductCode + { + get; set; + } } [XmlRoot(ElementName = "Identification")] public class Identification { [XmlElement(ElementName = "TypeDesignator")] - public string TypeDesignator { get; set; } + public string TypeDesignator + { + get; set; + } [XmlElement(ElementName = "BasicProductCodes")] - public BasicProductCodes BasicProductCodes { get; set; } + public BasicProductCodes BasicProductCodes + { + get; set; + } [XmlElement(ElementName = "Purpose")] - public string Purpose { get; set; } + public string Purpose + { + get; set; + } } [XmlRoot(ElementName = "Extensions")] public class Extensions { [XmlElement(ElementName = "PackageType")] - public string PackageType { get; set; } + public string PackageType + { + get; set; + } [XmlElement(ElementName = "Identification")] - public Identification Identification { get; set; } + public Identification Identification + { + get; set; + } [XmlElement(ElementName = "FileType")] - public string FileType { get; set; } + public string FileType + { + get; set; + } [XmlElement(ElementName = "MmosWimFile")] - public MmosWimFile MmosWimFile { get; set; } + public MmosWimFile MmosWimFile + { + get; set; + } } [XmlRoot(ElementName = "PackageDescription")] public class PackageDescription { [XmlElement(ElementName = "Identifier")] - public string Identifier { get; set; } + public string Identifier + { + get; set; + } [XmlElement(ElementName = "Revision")] - public string Revision { get; set; } + public string Revision + { + get; set; + } [XmlElement(ElementName = "Extensions")] - public Extensions Extensions { get; set; } + public Extensions Extensions + { + get; set; + } } [XmlRoot(ElementName = "Digest")] public class Digest { [XmlAttribute(AttributeName = "method")] - public string Method { get; set; } + public string Method + { + get; set; + } [XmlAttribute(AttributeName = "encoding")] - public string Encoding { get; set; } + public string Encoding + { + get; set; + } [XmlText] - public string Text { get; set; } + public string Text + { + get; set; + } } [XmlRoot(ElementName = "Digests")] public class Digests { [XmlElement(ElementName = "Digest")] - public List Digest { get; set; } + public List Digest + { + get; set; + } } [XmlRoot(ElementName = "Range")] public class Range { [XmlAttribute(AttributeName = "from")] - public string From { get; set; } + public string From + { + get; set; + } [XmlAttribute(AttributeName = "to")] - public string To { get; set; } + public string To + { + get; set; + } } [XmlRoot(ElementName = "Compatibility")] public class Compatibility { [XmlElement(ElementName = "Range")] - public Range Range { get; set; } + public Range Range + { + get; set; + } [XmlAttribute(AttributeName = "useCase")] - public string UseCase { get; set; } + public string UseCase + { + get; set; + } } [XmlRoot(ElementName = "UseCaseCompatibilities")] public class UseCaseCompatibilities { [XmlElement(ElementName = "Compatibility")] - public List Compatibility { get; set; } + public List Compatibility + { + get; set; + } } [XmlRoot(ElementName = "MmosWimFile")] public class MmosWimFile { [XmlElement(ElementName = "UseCaseCompatibilities")] - public UseCaseCompatibilities UseCaseCompatibilities { get; set; } + public UseCaseCompatibilities UseCaseCompatibilities + { + get; set; + } } [XmlRoot(ElementName = "File")] public class File { [XmlElement(ElementName = "Name")] - public string Name { get; set; } + public string Name + { + get; set; + } [XmlElement(ElementName = "Digests")] - public Digests Digests { get; set; } + public Digests Digests + { + get; set; + } [XmlElement(ElementName = "Revision")] - public string Revision { get; set; } + public string Revision + { + get; set; + } [XmlElement(ElementName = "Extensions")] - public Extensions Extensions { get; set; } + public Extensions Extensions + { + get; set; + } } [XmlRoot(ElementName = "Files")] public class Files { [XmlElement(ElementName = "File")] - public List File { get; set; } + public List File + { + get; set; + } } [XmlRoot(ElementName = "Content")] public class Content { [XmlElement(ElementName = "PackageDescription")] - public PackageDescription PackageDescription { get; set; } + public PackageDescription PackageDescription + { + get; set; + } [XmlElement(ElementName = "Files")] - public Files Files { get; set; } + public Files Files + { + get; set; + } } [XmlRoot(ElementName = "CanonicalizationMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class CanonicalizationMethod { [XmlAttribute(AttributeName = "Algorithm")] - public string Algorithm { get; set; } + public string Algorithm + { + get; set; + } } [XmlRoot(ElementName = "SignatureMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class SignatureMethod { [XmlAttribute(AttributeName = "Algorithm")] - public string Algorithm { get; set; } + public string Algorithm + { + get; set; + } } [XmlRoot(ElementName = "Transform", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class Transform { [XmlAttribute(AttributeName = "Algorithm")] - public string Algorithm { get; set; } + public string Algorithm + { + get; set; + } } [XmlRoot(ElementName = "Transforms", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class Transforms { [XmlElement(ElementName = "Transform", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public Transform Transform { get; set; } + public Transform Transform + { + get; set; + } } [XmlRoot(ElementName = "DigestMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class DigestMethod { [XmlAttribute(AttributeName = "Algorithm")] - public string Algorithm { get; set; } + public string Algorithm + { + get; set; + } } [XmlRoot(ElementName = "Reference", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class Reference { [XmlElement(ElementName = "Transforms", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public Transforms Transforms { get; set; } + public Transforms Transforms + { + get; set; + } [XmlElement(ElementName = "DigestMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public DigestMethod DigestMethod { get; set; } + public DigestMethod DigestMethod + { + get; set; + } [XmlElement(ElementName = "DigestValue", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public string DigestValue { get; set; } + public string DigestValue + { + get; set; + } [XmlAttribute(AttributeName = "URI")] - public string URI { get; set; } + public string URI + { + get; set; + } } [XmlRoot(ElementName = "SignedInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class SignedInfo { [XmlElement(ElementName = "CanonicalizationMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public CanonicalizationMethod CanonicalizationMethod { get; set; } + public CanonicalizationMethod CanonicalizationMethod + { + get; set; + } [XmlElement(ElementName = "SignatureMethod", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public SignatureMethod SignatureMethod { get; set; } + public SignatureMethod SignatureMethod + { + get; set; + } [XmlElement(ElementName = "Reference", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public Reference Reference { get; set; } + public Reference Reference + { + get; set; + } } [XmlRoot(ElementName = "KeyInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class KeyInfo { [XmlElement(ElementName = "KeyName", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public string KeyName { get; set; } + public string KeyName + { + get; set; + } } [XmlRoot(ElementName = "Signature", Namespace = "http://www.w3.org/2000/09/xmldsig#")] public class Signature { [XmlElement(ElementName = "SignedInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public SignedInfo SignedInfo { get; set; } + public SignedInfo SignedInfo + { + get; set; + } [XmlElement(ElementName = "SignatureValue", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public string SignatureValue { get; set; } + public string SignatureValue + { + get; set; + } [XmlElement(ElementName = "KeyInfo", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public KeyInfo KeyInfo { get; set; } + public KeyInfo KeyInfo + { + get; set; + } [XmlAttribute(AttributeName = "xmlns")] - public string Xmlns { get; set; } + public string Xmlns + { + get; set; + } } [XmlRoot(ElementName = "Package")] public class Package { [XmlElement(ElementName = "Content")] - public Content Content { get; set; } + public Content Content + { + get; set; + } [XmlElement(ElementName = "Signature", Namespace = "http://www.w3.org/2000/09/xmldsig#")] - public Signature Signature { get; set; } + public Signature Signature + { + get; set; + } } } } diff --git a/WPinternals/Models/NokiaPhoneModel.cs b/WPinternals/Models/Lumia/NokiaPhoneModel.NCSd.cs similarity index 71% rename from WPinternals/Models/NokiaPhoneModel.cs rename to WPinternals/Models/Lumia/NokiaPhoneModel.NCSd.cs index 35af4b5..03aa9bd 100644 --- a/WPinternals/Models/NokiaPhoneModel.cs +++ b/WPinternals/Models/Lumia/NokiaPhoneModel.NCSd.cs @@ -18,34 +18,15 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -using MadWizard.WinUSBNet; using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; -namespace WPinternals +namespace WPinternals.Models.Lumia { - internal class NokiaPhoneModel : IDisposable + internal partial class NokiaPhoneModel { - protected bool Disposed = false; - private readonly USBDevice Device = null; - private int MessageId = 0; - private readonly object UsbLock = new(); - - public NokiaPhoneModel(string DevicePath) - { - // Mass Storage device is not WinUSB - try - { - Device = new USBDevice(DevicePath); - } - catch (Exception ex) - { - LogFile.LogException(ex, LogType.FileOnly); - } - } - private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary Params, string ResultElement) { byte[] Buffer; @@ -72,7 +53,13 @@ public NokiaPhoneModel(string DevicePath) } } @params.Add("MessageVersion", 0); - string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params }); + string Request = JsonSerializer.Serialize(new + { + jsonrpc, + id, + method, + @params + }); Device.OutputPipe.Write(System.Text.Encoding.ASCII.GetBytes(Request)); Buffer = new byte[0x10000]; @@ -84,7 +71,7 @@ public NokiaPhoneModel(string DevicePath) try { JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result"); - if ((ResultToken == null) || (ResultElement == null)) + if (ResultToken == null || ResultElement == null) { return null; } @@ -207,7 +194,13 @@ public void ExecuteJsonMethodAsync(string JsonMethod, Dictionary } } @params.Add("MessageVersion", 0); - string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params }); + string Request = JsonSerializer.Serialize(new + { + jsonrpc, + id, + method, + @params + }); byte[] OutBuffer = System.Text.Encoding.ASCII.GetBytes(Request); Device.OutputPipe.BeginWrite(OutBuffer, 0, OutBuffer.Length, (AsyncResultWrite) => Device.OutputPipe.EndWrite(AsyncResultWrite), null); @@ -295,132 +288,40 @@ public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, Dictionary - { - Device.OutputPipe.EndWrite(AsyncResultWrite); - Buffer = new byte[0x10000]; - Device.InputPipe.BeginRead(Buffer, 0, 0x10000, (AsyncResultRead) => - { - Length = Device.InputPipe.EndRead(AsyncResultRead); - - JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length)); - - JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result"); - if ((ResultToken == null) || (ResultElement == null)) - { - Callback(AsyncResultRead.AsyncState, null); - } - - Callback(AsyncResultRead.AsyncState, ResultToken.Value.GetProperty(ResultElement)); - }, AsyncResultWrite.AsyncState); - }, State); - } - } - - public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackToken Callback) - { - ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, Callback); - } - - public byte[] ExecuteRawMethod(byte[] RawMethod) - { - return ExecuteRawMethod(RawMethod, RawMethod.Length); - } - - public byte[] ExecuteRawMethod(byte[] RawMethod, int Length) - { - byte[] Buffer = new byte[0x8000]; // Should be at least 0x4408 for receiving the GPT packet. - byte[] Result = null; - lock (UsbLock) - { - Device.OutputPipe.Write(RawMethod, 0, Length); - try - { - int OutputLength = Device.InputPipe.Read(Buffer); - Result = new byte[OutputLength]; - System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength); - } - catch (Exception ex) // Reboot command looses connection { - LogFile.LogException(ex, LogType.FileOnly); - } - } - return Result; - } + Device.OutputPipe.EndWrite(AsyncResultWrite); + Buffer = new byte[0x10000]; + Device.InputPipe.BeginRead(Buffer, 0, 0x10000, (AsyncResultRead) => + { + Length = Device.InputPipe.EndRead(AsyncResultRead); - public void ExecuteRawVoidMethod(byte[] RawMethod) - { - ExecuteRawVoidMethod(RawMethod, RawMethod.Length); - } + JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length)); - public void ExecuteRawVoidMethod(byte[] RawMethod, int Length) - { - lock (UsbLock) - { - Device.OutputPipe.Write(RawMethod, 0, Length); - } - } + JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result"); + if (ResultToken == null || ResultElement == null) + { + Callback(AsyncResultRead.AsyncState, null); + } - public void ResetDevice() - { - try - { - foreach (var pipe in Device.Pipes) - { - pipe.Abort(); - pipe.Reset(); - } - } - catch (Exception ex) - { - LogFile.LogException(ex, LogType.FileOnly); + Callback(AsyncResultRead.AsyncState, ResultToken.Value.GetProperty(ResultElement)); + }, AsyncResultWrite.AsyncState); + }, State); } } - /// - /// Disposes the UsbDevice including all unmanaged WinUSB handles. This function - /// should be called when the UsbDevice object is no longer in use, otherwise - /// unmanaged handles will remain open until the garbage collector finalizes the - /// object. - /// - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - /// - /// Finalizer for the UsbDevice. Disposes all unmanaged handles. - /// - ~NokiaPhoneModel() - { - Dispose(false); - } - - /// - /// Disposes the object - /// - /// Indicates wether Dispose was called manually (true) or by - /// the garbage collector (false) via the destructor. - protected virtual void Dispose(bool disposing) + public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackToken Callback) { - if (Disposed) - { - return; - } - - if (disposing) - { - Device?.Dispose(); - } - - // Clean unmanaged resources here. - // (none currently) - - Disposed = true; + ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, Callback); } } } diff --git a/WPinternals/Models/Lumia/NokiaPhoneModel.UEFI.cs b/WPinternals/Models/Lumia/NokiaPhoneModel.UEFI.cs new file mode 100644 index 0000000..5776c3a --- /dev/null +++ b/WPinternals/Models/Lumia/NokiaPhoneModel.UEFI.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System; +using WPinternals.HelperClasses; + +namespace WPinternals.Models.Lumia +{ + internal partial class NokiaPhoneModel + { + public byte[] ExecuteRawMethod(byte[] RawMethod) + { + return ExecuteRawMethod(RawMethod, RawMethod.Length); + } + + public byte[] ExecuteRawMethod(byte[] RawMethod, int Length) + { + byte[] Buffer = new byte[0x8000]; // Should be at least 0x4408 for receiving the GPT packet. + byte[] Result = null; + lock (UsbLock) + { + Device.OutputPipe.Write(RawMethod, 0, Length); + try + { + int OutputLength = Device.InputPipe.Read(Buffer); + Result = new byte[OutputLength]; + System.Buffer.BlockCopy(Buffer, 0, Result, 0, OutputLength); + } + catch (Exception ex) // Reboot command looses connection + { + LogFile.LogException(ex, LogType.FileOnly); + } + } + return Result; + } + + public void ExecuteRawVoidMethod(byte[] RawMethod) + { + ExecuteRawVoidMethod(RawMethod, RawMethod.Length); + } + + public void ExecuteRawVoidMethod(byte[] RawMethod, int Length) + { + lock (UsbLock) + { + Device.OutputPipe.Write(RawMethod, 0, Length); + } + } + } +} diff --git a/WPinternals/Models/Lumia/NokiaPhoneModel.cs b/WPinternals/Models/Lumia/NokiaPhoneModel.cs new file mode 100644 index 0000000..94984b0 --- /dev/null +++ b/WPinternals/Models/Lumia/NokiaPhoneModel.cs @@ -0,0 +1,106 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using MadWizard.WinUSBNet; +using System; +using WPinternals.HelperClasses; + +namespace WPinternals.Models.Lumia +{ + internal partial class NokiaPhoneModel : IDisposable + { + protected bool Disposed = false; + private readonly USBDevice Device = null; + private int MessageId = 0; + private readonly object UsbLock = new(); + + public NokiaPhoneModel(string DevicePath) + { + // Mass Storage device is not WinUSB + try + { + Device = new USBDevice(DevicePath); + } + catch (Exception ex) + { + LogFile.LogException(ex, LogType.FileOnly); + } + } + + public void ResetDevice() + { + try + { + foreach (var pipe in Device.Pipes) + { + pipe.Abort(); + pipe.Reset(); + } + } + catch (Exception ex) + { + LogFile.LogException(ex, LogType.FileOnly); + } + } + + /// + /// Disposes the UsbDevice including all unmanaged WinUSB handles. This function + /// should be called when the UsbDevice object is no longer in use, otherwise + /// unmanaged handles will remain open until the garbage collector finalizes the + /// object. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Finalizer for the UsbDevice. Disposes all unmanaged handles. + /// + ~NokiaPhoneModel() + { + Dispose(false); + } + + /// + /// Disposes the object + /// + /// Indicates wether Dispose was called manually (true) or by + /// the garbage collector (false) via the destructor. + protected virtual void Dispose(bool disposing) + { + if (Disposed) + { + return; + } + + if (disposing) + { + Device?.Dispose(); + } + + // Clean unmanaged resources here. + // (none currently) + + Disposed = true; + } + } +} diff --git a/WPinternals/Models/UEFIApps/LumiaBootManagerAppModel.cs b/WPinternals/Models/Lumia/UEFI/BootMgr/LumiaBootManagerAppModel.cs similarity index 96% rename from WPinternals/Models/UEFIApps/LumiaBootManagerAppModel.cs rename to WPinternals/Models/Lumia/UEFI/BootMgr/LumiaBootManagerAppModel.cs index a831575..737a9fd 100644 --- a/WPinternals/Models/UEFIApps/LumiaBootManagerAppModel.cs +++ b/WPinternals/Models/Lumia/UEFI/BootMgr/LumiaBootManagerAppModel.cs @@ -19,8 +19,10 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; -namespace WPinternals +namespace WPinternals.Models.UEFIApps.BootMgr { internal class LumiaBootManagerAppModel : NokiaUEFIModel { @@ -132,7 +134,7 @@ internal LumiaBootManagerPhoneInfo ReadPhoneInfoBootManager() byte[] Request = new byte[4]; ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature); byte[] Response = ExecuteRawMethod(Request); - if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU")) + if (Response != null && ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU") { Result.App = (FlashAppType)Response[5]; @@ -155,9 +157,8 @@ internal LumiaBootManagerPhoneInfo ReadPhoneInfoBootManager() LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}"); - UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01); + ushort SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01); int SubblockPayloadOffset = SubblockOffset + 3; - byte SubblockVersion; switch (SubblockID) { case 0x01: @@ -200,12 +201,12 @@ internal GPT ReadGPT() System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); byte[] Buffer = ExecuteRawMethod(Request); - if ((Buffer == null) || (Buffer.Length < 0x4408)) + if (Buffer == null || Buffer.Length < 0x4408) { throw new InvalidOperationException("Unable to read GPT!"); } - UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]); + ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]); if (Error > 0) { throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4")); @@ -217,7 +218,7 @@ internal GPT ReadGPT() return new GPT(GPTBuffer); // NOKT message header and MBR are ignored } - internal byte[] GetGptChunk(UInt32 Size) // TODO! + internal byte[] GetGptChunk(uint Size) // TODO! { // This function is also used to generate a dummy chunk to flash for testing. // The dummy chunk will contain the GPT, so it can be flashed to the first sectors for testing. @@ -229,12 +230,12 @@ internal byte[] GetGptChunk(UInt32 Size) // TODO! System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); byte[] Buffer = ExecuteRawMethod(Request); - if ((Buffer == null) || (Buffer.Length < 0x4408)) + if (Buffer == null || Buffer.Length < 0x4408) { throw new InvalidOperationException("Unable to read GPT!"); } - UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]); + ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]); if (Error > 0) { throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4")); @@ -252,7 +253,7 @@ internal byte[] GetGptChunk(UInt32 Size) // TODO! Request[6] = 0; // Options Request[7] = (byte)KeyType; byte[] Response = ExecuteRawMethod(Request); - UInt32 Status = ByteOperations.ReadUInt32(Response, 6); + uint Status = ByteOperations.ReadUInt32(Response, 6); if (Status != 0) { ThrowFlashError((int)Status); diff --git a/WPinternals/Models/PhoneInfo/LumiaBootManagerPhoneInfo.cs b/WPinternals/Models/Lumia/UEFI/BootMgr/LumiaBootManagerPhoneInfo.cs similarity index 94% rename from WPinternals/Models/PhoneInfo/LumiaBootManagerPhoneInfo.cs rename to WPinternals/Models/Lumia/UEFI/BootMgr/LumiaBootManagerPhoneInfo.cs index bacfa2f..0e8dbb3 100644 --- a/WPinternals/Models/PhoneInfo/LumiaBootManagerPhoneInfo.cs +++ b/WPinternals/Models/Lumia/UEFI/BootMgr/LumiaBootManagerPhoneInfo.cs @@ -19,8 +19,10 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; -namespace WPinternals +namespace WPinternals.Models.UEFIApps.BootMgr { internal class LumiaBootManagerPhoneInfo { @@ -38,7 +40,7 @@ internal class LumiaBootManagerPhoneInfo public byte BootManagerProtocolVersionMajor; public byte BootManagerProtocolVersionMinor; - public UInt32 TransferSize; + public uint TransferSize; public bool MmosOverUsbSupported; internal void Log(LogType Type) diff --git a/WPinternals/Models/Lumia/UEFI/CommonPhoneInfo.cs b/WPinternals/Models/Lumia/UEFI/CommonPhoneInfo.cs new file mode 100644 index 0000000..5fd9a72 --- /dev/null +++ b/WPinternals/Models/Lumia/UEFI/CommonPhoneInfo.cs @@ -0,0 +1,64 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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 (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; + +namespace WPinternals.Models.UEFIApps +{ + internal class CommonPhoneInfo + { + public PhoneInfoState State = PhoneInfoState.Empty; + + public FlashAppType App; + + public byte VersionMajor; + public byte VersionMinor; + public byte ProtocolVersionMajor; + public byte ProtocolVersionMinor; + + internal void Log(LogType Type) + { + LogFile.Log($"App: {VersionMajor}.{VersionMinor}", Type); + LogFile.Log($"Protocol: {ProtocolVersionMajor}.{ProtocolVersionMinor}", Type); + } + } +} diff --git a/WPinternals/Models/Lumia/UEFI/Flash/FfuProtocol.cs b/WPinternals/Models/Lumia/UEFI/Flash/FfuProtocol.cs new file mode 100644 index 0000000..9ea3751 --- /dev/null +++ b/WPinternals/Models/Lumia/UEFI/Flash/FfuProtocol.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +namespace WPinternals.Models.UEFIApps.Flash +{ + internal enum FfuProtocol + { + ProtocolSyncV1 = 1, + ProtocolAsyncV1 = 2, + ProtocolSyncV2 = 4, + ProtocolAsyncV2 = 8, + ProtocolAsyncV3 = 16 + } +} diff --git a/WPinternals/Models/Lumia/UEFI/Flash/FlashOptions.cs b/WPinternals/Models/Lumia/UEFI/Flash/FlashOptions.cs new file mode 100644 index 0000000..b131b74 --- /dev/null +++ b/WPinternals/Models/Lumia/UEFI/Flash/FlashOptions.cs @@ -0,0 +1,33 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System; + +namespace WPinternals.Models.UEFIApps.Flash +{ + [Flags] + internal enum FlashOptions : byte + { + SkipWrite = 1, + SkipHashCheck = 2, + SkipIdCheck = 4, + SkipSignatureCheck = 8 + } +} \ No newline at end of file diff --git a/WPinternals/Models/Lumia/UEFI/Flash/Fuse.cs b/WPinternals/Models/Lumia/UEFI/Flash/Fuse.cs new file mode 100644 index 0000000..5e3fc8e --- /dev/null +++ b/WPinternals/Models/Lumia/UEFI/Flash/Fuse.cs @@ -0,0 +1,44 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System; + +namespace WPinternals.Models.UEFIApps.Flash +{ + [Flags] + internal enum Fuse + { + SecureBoot = 1, + FfuVerify = 2, + Jtag = 4, + Shk = 8, + Simlock = 16, + ProductionDone = 32, + Rkh = 64, + PublicId = 128, + Dak = 256, + SecGen = 512, + OemId = 1024, + FastBoot = 2048, + SpdmSecMode = 4096, + RpmWdog = 8192, + Ssm = 16384 + } +} \ No newline at end of file diff --git a/WPinternals/Models/UEFIApps/LumiaFlashAppModel.cs b/WPinternals/Models/Lumia/UEFI/Flash/LumiaFlashAppModel.cs similarity index 91% rename from WPinternals/Models/UEFIApps/LumiaFlashAppModel.cs rename to WPinternals/Models/Lumia/UEFI/Flash/LumiaFlashAppModel.cs index 7db7d3c..e8d5c90 100644 --- a/WPinternals/Models/UEFIApps/LumiaFlashAppModel.cs +++ b/WPinternals/Models/Lumia/UEFI/Flash/LumiaFlashAppModel.cs @@ -21,53 +21,12 @@ using System; using System.IO; using System.Linq; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; +using WPinternals.Terminal; -namespace WPinternals +namespace WPinternals.Models.UEFIApps.Flash { - internal enum SecureBootKeyType : byte - { - Retail = 0, - Engineering = 1 - } - - [Flags] - internal enum Fuse - { - SecureBoot = 1, - FfuVerify = 2, - Jtag = 4, - Shk = 8, - Simlock = 16, - ProductionDone = 32, - Rkh = 64, - PublicId = 128, - Dak = 256, - SecGen = 512, - OemId = 1024, - FastBoot = 2048, - SpdmSecMode = 4096, - RpmWdog = 8192, - Ssm = 16384 - } - - internal enum FfuProtocol - { - ProtocolSyncV1 = 1, - ProtocolAsyncV1 = 2, - ProtocolSyncV2 = 4, - ProtocolAsyncV2 = 8, - ProtocolAsyncV3 = 16 - } - - [Flags] - internal enum FlashOptions : byte - { - SkipWrite = 1, - SkipHashCheck = 2, - SkipIdCheck = 4, - SkipSignatureCheck = 8 - } - internal class LumiaFlashAppModel : NokiaUEFIModel { internal readonly LumiaFlashAppPhoneInfo FlashAppInfo = new(); @@ -167,7 +126,7 @@ internal LumiaFlashAppPhoneInfo ReadPhoneInfo(bool ExtendedInfo = true) LumiaFlashAppPhoneInfo Result = FlashAppInfo; - if (ExtendedInfo && (Result.State == PhoneInfoState.Basic)) + if (ExtendedInfo && Result.State == PhoneInfoState.Basic) { if (Result.App == FlashAppType.FlashApp) { @@ -198,7 +157,7 @@ internal LumiaFlashAppPhoneInfo ReadPhoneInfoFlashApp() byte[] Request = new byte[4]; ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature); byte[] Response = ExecuteRawMethod(Request); - if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU")) + if (Response != null && ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU") { Result.App = (FlashAppType)Response[5]; @@ -221,7 +180,7 @@ internal LumiaFlashAppPhoneInfo ReadPhoneInfoFlashApp() LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}"); - UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01); + ushort SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01); int SubblockPayloadOffset = SubblockOffset + 3; byte SubblockVersion; switch (SubblockID) @@ -250,7 +209,7 @@ internal LumiaFlashAppPhoneInfo ReadPhoneInfoFlashApp() Result.SecureFfuEnabled = Response[SubblockPayloadOffset + 0x02] == 0x01; Result.JtagDisabled = Response[SubblockPayloadOffset + 0x03] == 0x01; Result.RdcPresent = Response[SubblockPayloadOffset + 0x04] == 0x01; - Result.Authenticated = (Response[SubblockPayloadOffset + 0x05] == 0x01) || (Response[SubblockPayloadOffset + 0x05] == 0x02); + Result.Authenticated = Response[SubblockPayloadOffset + 0x05] == 0x01 || Response[SubblockPayloadOffset + 0x05] == 0x02; Result.UefiSecureBootEnabled = Response[SubblockPayloadOffset + 0x06] == 0x01; Result.SecondaryHardwareKeyPresent = Response[SubblockPayloadOffset + 0x07] == 0x01; break; @@ -299,12 +258,12 @@ internal GPT ReadGPT() System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); byte[] Buffer = ExecuteRawMethod(Request); - if ((Buffer == null) || (Buffer.Length < 0x4408)) + if (Buffer == null || Buffer.Length < 0x4408) { throw new InvalidOperationException("Unable to read GPT!"); } - UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]); + ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]); if (Error > 0) { throw new NotSupportedException("ReadGPT: Error 0x" + Error.ToString("X4")); @@ -316,7 +275,7 @@ internal GPT ReadGPT() return new GPT(GPTBuffer); // NOKT message header and MBR are ignored } - internal byte[] GetGptChunk(UInt32 Size) // TODO! + internal byte[] GetGptChunk(uint Size) // TODO! { // This function is also used to generate a dummy chunk to flash for testing. // The dummy chunk will contain the GPT, so it can be flashed to the first sectors for testing. @@ -336,12 +295,12 @@ internal byte[] GetGptChunk(UInt32 Size) // TODO! System.Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Header), 0, Request, 0, Header.Length); byte[] Buffer = ExecuteRawMethod(Request); - if ((Buffer == null) || (Buffer.Length < 0x4408)) + if (Buffer == null || Buffer.Length < 0x4408) { throw new InvalidOperationException("Unable to read GPT!"); } - UInt16 Error = (UInt16)((Buffer[6] << 8) + Buffer[7]); + ushort Error = (ushort)((Buffer[6] << 8) + Buffer[7]); if (Error > 0) { ThrowFlashError(Error); @@ -362,7 +321,7 @@ public byte[] ReadParam(string Param) Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(Param), 0, Request, 7, Param.Length); byte[] Response = ExecuteRawMethod(Request); - if ((Response == null) || (Response.Length < 0x10)) + if (Response == null || Response.Length < 0x10) { return null; } @@ -386,37 +345,37 @@ public string ReadStringParam(string Param) public uint? ReadSecurityFlags() { byte[] Response = ReadParam("FCS"); - if ((Response == null) || (Response.Length != 4)) + if (Response == null || Response.Length != 4) { return null; } // This value is in big endian - return (UInt32)((Response[0] << 24) | (Response[1] << 16) | (Response[2] << 8) | Response[3]); + return (uint)(Response[0] << 24 | Response[1] << 16 | Response[2] << 8 | Response[3]); } public uint? ReadCurrentChargeLevel() { byte[] Response = ReadParam("CS"); - if ((Response == null) || (Response.Length != 8)) + if (Response == null || Response.Length != 8) { return null; } // This value is in big endian - return (UInt32)((Response[0] << 24) | (Response[1] << 16) | (Response[2] << 8) | Response[3]) + 1; + return (uint)(Response[0] << 24 | Response[1] << 16 | Response[2] << 8 | Response[3]) + 1; } public int? ReadCurrentChargeCurrent() { byte[] Response = ReadParam("CS"); - if ((Response == null) || (Response.Length != 8)) + if (Response == null || Response.Length != 8) { return null; } // This value is in big endian and needs to be XOR'd with 0xFFFFFFFF - return (Int32)(((Response[4] << 24) | (Response[5] << 16) | (Response[6] << 8) | Response[7]) ^ 0xFFFFFFFF) + 1; + return (int)((Response[4] << 24 | Response[5] << 16 | Response[6] << 8 | Response[7]) ^ 0xFFFFFFFF) + 1; } public UefiSecurityStatusResponse ReadSecurityStatus() @@ -451,7 +410,7 @@ public UefiSecurityStatusResponse ReadSecurityStatus() public FlashVersion GetFlashVersion() { byte[] Response = ReadParam("FAI"); - if ((Response == null) || (Response.Length < 6)) + if (Response == null || Response.Length < 6) { return null; } @@ -466,7 +425,7 @@ public FlashVersion GetFlashVersion() return Result; } - internal UInt16 ReadSecureFfuSupportedProtocolMask() + internal ushort ReadSecureFfuSupportedProtocolMask() { return BigEndian.ToUInt16(ReadParam("SFPI"), 0); } @@ -483,10 +442,10 @@ public TerminalResponse GetTerminalResponse() Buffer.BlockCopy(BigEndian.GetBytes(0x00, 4), 0, Request, 0x10, 4); // AsicIndex = 0x00 Buffer.BlockCopy(AsskMask, 0, Request, 0x14, 0x10); byte[] TerminalResponse = ExecuteRawMethod(Request); - if ((TerminalResponse?.Length > 0x20) && (BigEndian.ToUInt32(TerminalResponse, 0x14) == (TerminalResponse.Length - 0x18)) && (BitConverter.ToUInt32(TerminalResponse, 0x1C) == (TerminalResponse.Length - 0x20))) + if (TerminalResponse?.Length > 0x20 && BigEndian.ToUInt32(TerminalResponse, 0x14) == TerminalResponse.Length - 0x18 && BitConverter.ToUInt32(TerminalResponse, 0x1C) == TerminalResponse.Length - 0x20) { // Parse Terminal Response from offset 0x18 - return Terminal.Parse(TerminalResponse, 0x18); + return Terminal.Terminal.Parse(TerminalResponse, 0x18); } else { @@ -524,7 +483,7 @@ public void SendFfuHeaderV1(byte[] FfuHeader, byte Options = 0) } } - public void SendFfuHeaderV2(UInt32 TotalHeaderLength, UInt32 OffsetForThisPart, byte[] FfuHeader, byte Options = 0) + public void SendFfuHeaderV2(uint TotalHeaderLength, uint OffsetForThisPart, byte[] FfuHeader, byte Options = 0) { byte[] Request = new byte[FfuHeader.Length + 0x3C]; @@ -627,7 +586,7 @@ public void SendFfuPayloadV2(byte[] FfuChunk, int Progress = 0, byte Options = 0 } } - public void SendFfuPayloadV3(byte[] FfuChunk, UInt32 WriteDescriptorIndex, UInt32 CRC, int Progress = 0, byte Options = 0) + public void SendFfuPayloadV3(byte[] FfuChunk, uint WriteDescriptorIndex, uint CRC, int Progress = 0, byte Options = 0) { byte[] Request = new byte[FfuChunk.Length + 0x20]; @@ -691,7 +650,7 @@ public void BackupPartitionToRam(string PartitionName) } } - public void LoadMmosBinary(UInt32 TotalLength, UInt32 Offset, bool SkipMmosSupportCheck, byte[] MmosPart) + public void LoadMmosBinary(uint TotalLength, uint Offset, bool SkipMmosSupportCheck, byte[] MmosPart) { byte[] Request = new byte[MmosPart.Length + 0x20]; const string Header = LoadSignature; @@ -763,7 +722,7 @@ internal void EndAsyncFlash() Request[6] = 0; // Options Request[7] = (byte)KeyType; byte[] Response = ExecuteRawMethod(Request); - UInt32 Status = ByteOperations.ReadUInt32(Response, 6); + uint Status = ByteOperations.ReadUInt32(Response, 6); if (Status != 0) { ThrowFlashError((int)Status); @@ -842,7 +801,7 @@ private void ThrowFlashError(int ErrorCode) return null; } - public void FlashSectors(UInt32 StartSector, byte[] Data, int Progress = 0) + public void FlashSectors(uint StartSector, byte[] Data, int Progress = 0) { // Start sector is in UInt32, so max size of eMMC is 2 TB. @@ -903,7 +862,7 @@ internal void WriteGPT(GPT NewGPT) byte[] Buffer = NewGPT.Rebuild(); - UInt32? HeaderOffset = ByteOperations.FindAscii(Buffer, "EFI PART"); + uint? HeaderOffset = ByteOperations.FindAscii(Buffer, "EFI PART"); if (HeaderOffset != 0) { throw new BadImageFormatException(); @@ -984,14 +943,14 @@ public void FlashFFU(FFU FFU, ProgressUpdater UpdaterPerChunk, bool ResetAfterwa throw new WPinternalsException("Flash failed!", "Protocols not supported. The device reports that both Protocol Sync v1 and Protocol Sync v2 are not supported for FFU flashing. Is this an old device?"); } - UInt64 CombinedFFUHeaderSize = FFU.HeaderSize; + ulong CombinedFFUHeaderSize = FFU.HeaderSize; byte[] FfuHeader = new byte[CombinedFFUHeaderSize]; using (FileStream FfuFile = new(FFU.Path, FileMode.Open, FileAccess.Read)) { FfuFile.Read(FfuHeader, 0, (int)CombinedFFUHeaderSize); SendFfuHeaderV1(FfuHeader, Options); - UInt64 Position = CombinedFFUHeaderSize; + ulong Position = CombinedFFUHeaderSize; byte[] Payload; int ChunkCount = 0; @@ -1000,7 +959,7 @@ public void FlashFFU(FFU FFU, ProgressUpdater UpdaterPerChunk, bool ResetAfterwa // Protocol v1 Payload = new byte[FFU.ChunkSize]; - while (Position < (UInt64)FfuFile.Length) + while (Position < (ulong)FfuFile.Length) { FfuFile.Read(Payload, 0, Payload.Length); ChunkCount++; @@ -1015,12 +974,12 @@ public void FlashFFU(FFU FFU, ProgressUpdater UpdaterPerChunk, bool ResetAfterwa // Protocol v2 Payload = new byte[Info.WriteBufferSize]; - while (Position < (UInt64)FfuFile.Length) + while (Position < (ulong)FfuFile.Length) { - UInt32 PayloadSize = Info.WriteBufferSize; - if (((UInt64)FfuFile.Length - Position) < PayloadSize) + uint PayloadSize = Info.WriteBufferSize; + if ((ulong)FfuFile.Length - Position < PayloadSize) { - PayloadSize = (UInt32)((UInt64)FfuFile.Length - Position); + PayloadSize = (uint)((ulong)FfuFile.Length - Position); Payload = new byte[PayloadSize]; } @@ -1124,25 +1083,25 @@ private void FlashRawPartition(GPT GPT, string Path, Stream Stream, string Parti { using (InputStream) { - UInt64? InputStreamLength = null; + ulong? InputStreamLength = null; try { - InputStreamLength = (UInt64)InputStream.Length; + InputStreamLength = (ulong)InputStream.Length; } catch (Exception ex) { LogFile.LogException(ex, LogType.FileOnly); } - if ((InputStreamLength != null) && ((UInt64)InputStream.Length > PartitionSize)) + if (InputStreamLength != null && (ulong)InputStream.Length > PartitionSize) { throw new InvalidOperationException("Partition can not be flashed, because its size is too big!"); } ProgressUpdater Progress = UpdaterPerSector; - if ((Progress == null) && (ProgressUpdateCallback != null) && (InputStreamLength != null)) + if (Progress == null && ProgressUpdateCallback != null && InputStreamLength != null) { - Progress = new ProgressUpdater((UInt64)(InputStreamLength / 0x200), ProgressUpdateCallback); + Progress = new ProgressUpdater((ulong)(InputStreamLength / 0x200), ProgressUpdateCallback); } int ProgressPercentage = 0; @@ -1150,7 +1109,7 @@ private void FlashRawPartition(GPT GPT, string Path, Stream Stream, string Parti const int FlashBufferSize = 0x200000; // Flash 8 GB phone -> buffersize 0x200000 = 11:45 min, buffersize 0x20000 = 12:30 min byte[] FlashBuffer = new byte[FlashBufferSize]; int BytesRead; - UInt64 i = 0; + ulong i = 0; do { BytesRead = InputStream.Read(FlashBuffer, 0, FlashBufferSize); @@ -1168,12 +1127,12 @@ private void FlashRawPartition(GPT GPT, string Path, Stream Stream, string Parti Buffer.BlockCopy(FlashBuffer, 0, FlashBufferFinalSize, 0, BytesRead); } - FlashSectors((UInt32)(Partition.FirstSector + (i / 0x200)), FlashBufferFinalSize, ProgressPercentage); + FlashSectors((uint)(Partition.FirstSector + i / 0x200), FlashBufferFinalSize, ProgressPercentage); } if (Progress != null) { - Progress.IncreaseProgress((UInt64)FlashBuffer.Length / 0x200); + Progress.IncreaseProgress((ulong)FlashBuffer.Length / 0x200); ProgressPercentage = Progress.ProgressPercentage; } diff --git a/WPinternals/Models/PhoneInfo/LumiaFlashAppPhoneInfo.cs b/WPinternals/Models/Lumia/UEFI/Flash/LumiaFlashAppPhoneInfo.cs similarity index 81% rename from WPinternals/Models/PhoneInfo/LumiaFlashAppPhoneInfo.cs rename to WPinternals/Models/Lumia/UEFI/Flash/LumiaFlashAppPhoneInfo.cs index d72f427..c3466d5 100644 --- a/WPinternals/Models/PhoneInfo/LumiaFlashAppPhoneInfo.cs +++ b/WPinternals/Models/Lumia/UEFI/Flash/LumiaFlashAppPhoneInfo.cs @@ -19,8 +19,10 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; -namespace WPinternals +namespace WPinternals.Models.UEFIApps.Flash { internal class LumiaFlashAppPhoneInfo { @@ -36,13 +38,13 @@ internal class LumiaFlashAppPhoneInfo public byte FlashAppProtocolVersionMajor; public byte FlashAppProtocolVersionMinor; - public UInt32 TransferSize; + public uint TransferSize; public bool MmosOverUsbSupported; - public UInt32 SdCardSizeInSectors; - public UInt32 WriteBufferSize; - public UInt32 EmmcSizeInSectors; + public uint SdCardSizeInSectors; + public uint WriteBufferSize; + public uint EmmcSizeInSectors; public string PlatformID; - public UInt16 SecureFfuSupportedProtocolMask; + public ushort SecureFfuSupportedProtocolMask; public bool AsyncSupport; public bool PlatformSecureBootEnabled; @@ -78,14 +80,14 @@ internal void Log(LogType Type) break; } - LogFile.Log($"SecureBoot: {((!PlatformSecureBootEnabled || !UefiSecureBootEnabled) ? "Disabled" : "Enabled")} (Platform Secure Boot: {(PlatformSecureBootEnabled ? "Enabled" : "Disabled")}, UEFI Secure Boot: {(UefiSecureBootEnabled ? "Enabled" : "Disabled")})", Type); + LogFile.Log($"SecureBoot: {(!PlatformSecureBootEnabled || !UefiSecureBootEnabled ? "Disabled" : "Enabled")} (Platform Secure Boot: {(PlatformSecureBootEnabled ? "Enabled" : "Disabled")}, UEFI Secure Boot: {(UefiSecureBootEnabled ? "Enabled" : "Disabled")})", Type); - if ((Type == LogType.ConsoleOnly) || (Type == LogType.FileAndConsole)) + if (Type == LogType.ConsoleOnly || Type == LogType.FileAndConsole) { LogFile.Log($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")}", LogType.ConsoleOnly); } - if ((Type == LogType.FileOnly) || (Type == LogType.FileAndConsole)) + if (Type == LogType.FileOnly || Type == LogType.FileAndConsole) { LogFile.Log($"Flash app security: {(!IsBootloaderSecure ? "Disabled" : "Enabled")} (FFU security: {(SecureFfuEnabled ? "Enabled" : "Disabled")}, RDC: {(RdcPresent ? "Present" : "Not found")}, Authenticated: {(Authenticated ? "True" : "False")})", LogType.FileOnly); } diff --git a/WPinternals/Models/Lumia/UEFI/Flash/SecureBootKeyType.cs b/WPinternals/Models/Lumia/UEFI/Flash/SecureBootKeyType.cs new file mode 100644 index 0000000..27e2c12 --- /dev/null +++ b/WPinternals/Models/Lumia/UEFI/Flash/SecureBootKeyType.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +namespace WPinternals.Models.UEFIApps.Flash +{ + internal enum SecureBootKeyType : byte + { + Retail = 0, + Engineering = 1 + } +} \ No newline at end of file diff --git a/WPinternals/Models/FlashAppType.cs b/WPinternals/Models/Lumia/UEFI/FlashAppType.cs similarity index 96% rename from WPinternals/Models/FlashAppType.cs rename to WPinternals/Models/Lumia/UEFI/FlashAppType.cs index 5ed09a7..2607fc3 100644 --- a/WPinternals/Models/FlashAppType.cs +++ b/WPinternals/Models/Lumia/UEFI/FlashAppType.cs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace WPinternals +namespace WPinternals.Models.Lumia.UEFI { internal enum FlashAppType { diff --git a/WPinternals/Models/FlashVersion.cs b/WPinternals/Models/Lumia/UEFI/FlashVersion.cs similarity index 97% rename from WPinternals/Models/FlashVersion.cs rename to WPinternals/Models/Lumia/UEFI/FlashVersion.cs index 58494e8..9615deb 100644 --- a/WPinternals/Models/FlashVersion.cs +++ b/WPinternals/Models/Lumia/UEFI/FlashVersion.cs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace WPinternals +namespace WPinternals.Models.Lumia.UEFI { internal class FlashVersion { diff --git a/WPinternals/Models/UEFIApps/NokiaUEFIModel.cs b/WPinternals/Models/Lumia/UEFI/NokiaUEFIModel.cs similarity index 98% rename from WPinternals/Models/UEFIApps/NokiaUEFIModel.cs rename to WPinternals/Models/Lumia/UEFI/NokiaUEFIModel.cs index 44bb5f7..c5d364c 100644 --- a/WPinternals/Models/UEFIApps/NokiaUEFIModel.cs +++ b/WPinternals/Models/Lumia/UEFI/NokiaUEFIModel.cs @@ -19,8 +19,11 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.Lumia.UEFI; -namespace WPinternals +namespace WPinternals.Models.UEFIApps { internal delegate void InterfaceChangedHandler(PhoneInterfaces NewInterface, string DevicePath); diff --git a/WPinternals/Models/UEFIApps/LumiaPhoneInfoAppModel.cs b/WPinternals/Models/Lumia/UEFI/PhoneInfo/LumiaPhoneInfoAppModel.cs similarity index 93% rename from WPinternals/Models/UEFIApps/LumiaPhoneInfoAppModel.cs rename to WPinternals/Models/Lumia/UEFI/PhoneInfo/LumiaPhoneInfoAppModel.cs index 430f7ca..a9b4a48 100644 --- a/WPinternals/Models/UEFIApps/LumiaPhoneInfoAppModel.cs +++ b/WPinternals/Models/Lumia/UEFI/PhoneInfo/LumiaPhoneInfoAppModel.cs @@ -20,8 +20,10 @@ using System; using System.Collections.Generic; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; -namespace WPinternals +namespace WPinternals.Models.UEFIApps.PhoneInfo { internal class LumiaPhoneInfoAppModel : NokiaUEFIModel { @@ -82,12 +84,12 @@ internal string GetPhoneInfo() byte[] Request = new byte[4]; ByteOperations.WriteAsciiString(Request, 0, GetPhoneInfoSignature); byte[] Response = ExecuteRawMethod(Request); - if ((Response == null) || (ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU")) + if (Response == null || ByteOperations.ReadAsciiString(Response, 0, 4) == "NOKU") { throw new NotSupportedException(); } - UInt16 Length = BigEndian.ToUInt16(Response, 0x04); + ushort Length = BigEndian.ToUInt16(Response, 0x04); string PhoneInfoData = ByteOperations.ReadAsciiString(Response, 0x8, Length); @@ -104,7 +106,7 @@ internal LumiaPhoneInfoAppPhoneInfo ReadPhoneInfo(bool ExtendedInfo = true) LumiaPhoneInfoAppPhoneInfo Result = PhoneInfoAppInfo; - if (ExtendedInfo && (Result.State == PhoneInfoState.Basic)) + if (ExtendedInfo && Result.State == PhoneInfoState.Basic) { try { @@ -175,7 +177,7 @@ internal LumiaPhoneInfoAppPhoneInfo ReadPhoneInfoPhoneInfoApp() byte[] Request = new byte[4]; ByteOperations.WriteAsciiString(Request, 0, InfoQuerySignature); byte[] Response = ExecuteRawMethod(Request); - if ((Response != null) && (ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU")) + if (Response != null && ByteOperations.ReadAsciiString(Response, 0, 4) != "NOKU") { Result.App = (FlashAppType)Response[5]; @@ -198,9 +200,8 @@ internal LumiaPhoneInfoAppPhoneInfo ReadPhoneInfoPhoneInfoApp() LogFile.Log($"{Result.App} SubblockID: 0x{SubblockID:X}"); - UInt16 SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01); + ushort SubblockLength = BigEndian.ToUInt16(Response, SubblockOffset + 0x01); int SubblockPayloadOffset = SubblockOffset + 3; - byte SubblockVersion; switch (SubblockID) { case 0x20: @@ -224,7 +225,7 @@ internal string ReadPhoneInfoVariable(string VariableName) byte[] Request = new byte[16]; ByteOperations.WriteAsciiString(Request, 0, GetVariableSignature + VariableName + "\0"); // BTR or CTR, CTR is public ProductCode byte[] Response = ExecuteRawMethod(Request); - UInt16 Length = BigEndian.ToUInt16(Response, 6); + ushort Length = BigEndian.ToUInt16(Response, 6); return ByteOperations.ReadAsciiString(Response, 8, Length).Trim([' ', '\0']); } diff --git a/WPinternals/Models/PhoneInfo/LumiaPhoneInfoAppPhoneInfo.cs b/WPinternals/Models/Lumia/UEFI/PhoneInfo/LumiaPhoneInfoAppPhoneInfo.cs similarity index 66% rename from WPinternals/Models/PhoneInfo/LumiaPhoneInfoAppPhoneInfo.cs rename to WPinternals/Models/Lumia/UEFI/PhoneInfo/LumiaPhoneInfoAppPhoneInfo.cs index 1efe750..1027a8f 100644 --- a/WPinternals/Models/PhoneInfo/LumiaPhoneInfoAppPhoneInfo.cs +++ b/WPinternals/Models/Lumia/UEFI/PhoneInfo/LumiaPhoneInfoAppPhoneInfo.cs @@ -18,7 +18,31 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace WPinternals + +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; + +namespace WPinternals.Models.UEFIApps.PhoneInfo { internal class LumiaPhoneInfoAppPhoneInfo { @@ -49,7 +73,7 @@ internal void Log(LogType Type) LogFile.Log($"Product code: {ProductCode}", Type); } - if (Type != LogType.ConsoleOnly && (Imei != null)) + if (Type != LogType.ConsoleOnly && Imei != null) { LogFile.Log($"IMEI: {Imei}", LogType.FileOnly); } diff --git a/WPinternals/Models/PhoneInfoState.cs b/WPinternals/Models/Lumia/UEFI/PhoneInfoState.cs similarity index 96% rename from WPinternals/Models/PhoneInfoState.cs rename to WPinternals/Models/Lumia/UEFI/PhoneInfoState.cs index ef03d93..a5ebf2c 100644 --- a/WPinternals/Models/PhoneInfoState.cs +++ b/WPinternals/Models/Lumia/UEFI/PhoneInfoState.cs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace WPinternals +namespace WPinternals.Models.Lumia.UEFI { internal enum PhoneInfoState { diff --git a/WPinternals/Models/UefiSecurityStatusResponse.cs b/WPinternals/Models/Lumia/UEFI/UefiSecurityStatusResponse.cs similarity index 97% rename from WPinternals/Models/UefiSecurityStatusResponse.cs rename to WPinternals/Models/Lumia/UEFI/UefiSecurityStatusResponse.cs index 3c8b95a..0c4a419 100644 --- a/WPinternals/Models/UefiSecurityStatusResponse.cs +++ b/WPinternals/Models/Lumia/UEFI/UefiSecurityStatusResponse.cs @@ -18,7 +18,7 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. -namespace WPinternals +namespace WPinternals.Models.Lumia.UEFI { internal class UefiSecurityStatusResponse { diff --git a/WPinternals/Models/MassStorage.cs b/WPinternals/Models/MassStorage.cs index 077073c..a6104e6 100644 --- a/WPinternals/Models/MassStorage.cs +++ b/WPinternals/Models/MassStorage.cs @@ -23,6 +23,8 @@ using System.Linq; using System.Management; using System.Runtime.InteropServices; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; namespace WPinternals { @@ -41,14 +43,14 @@ internal MassStorage(string DevicePath) : base(DevicePath) { try { - foreach (ManagementObject logical in new ManagementObjectSearcher("select * from Win32_LogicalDisk").Get()) + foreach (ManagementObject logical in new ManagementObjectSearcher("select * from Win32_LogicalDisk").Get().Cast()) { System.Diagnostics.Debug.Print(logical["Name"].ToString()); string Label = ""; - foreach (ManagementObject partition in logical.GetRelated("Win32_DiskPartition")) + foreach (ManagementObject partition in logical.GetRelated("Win32_DiskPartition").Cast()) { - foreach (ManagementObject drive in partition.GetRelated("Win32_DiskDrive")) + foreach (ManagementObject drive in partition.GetRelated("Win32_DiskDrive").Cast()) { if (drive["PNPDeviceID"].ToString().Contains("VEN_QUALCOMM&PROD_MMC_STORAGE", StringComparison.CurrentCulture) || drive["PNPDeviceID"].ToString().Contains("VEN_MSFT&PROD_PHONE_MMC_STOR", StringComparison.CurrentCulture)) diff --git a/WPinternals/Models/PatchEngine.cs b/WPinternals/Models/PatchEngine.cs index bb2d892..93af1da 100644 --- a/WPinternals/Models/PatchEngine.cs +++ b/WPinternals/Models/PatchEngine.cs @@ -28,6 +28,7 @@ using System.Security.Principal; using System.Xml; using System.Xml.Serialization; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/QualcommFirehose.cs b/WPinternals/Models/QualcommFirehose.cs index 28844d1..195aae2 100644 --- a/WPinternals/Models/QualcommFirehose.cs +++ b/WPinternals/Models/QualcommFirehose.cs @@ -25,6 +25,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/QualcommFlasher.cs b/WPinternals/Models/QualcommFlasher.cs index 5324cec..e2f1283 100644 --- a/WPinternals/Models/QualcommFlasher.cs +++ b/WPinternals/Models/QualcommFlasher.cs @@ -20,6 +20,7 @@ using System; using System.IO; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/QualcommLoader.cs b/WPinternals/Models/QualcommLoader.cs index a935ba1..2a0ac57 100644 --- a/WPinternals/Models/QualcommLoader.cs +++ b/WPinternals/Models/QualcommLoader.cs @@ -22,6 +22,7 @@ using System.Collections; using System.Collections.Generic; using System.IO; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/QualcommPartition.cs b/WPinternals/Models/QualcommPartition.cs index 7589ace..8edd0f3 100644 --- a/WPinternals/Models/QualcommPartition.cs +++ b/WPinternals/Models/QualcommPartition.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.IO; using System.Security.Cryptography; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/QualcommSahara.cs b/WPinternals/Models/QualcommSahara.cs index 309f8ce..fd3e0e3 100644 --- a/WPinternals/Models/QualcommSahara.cs +++ b/WPinternals/Models/QualcommSahara.cs @@ -22,6 +22,7 @@ using System.Collections.Generic; using System.IO; using System.Threading.Tasks; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/QualcommSerial.cs b/WPinternals/Models/QualcommSerial.cs index f95a5d2..10eface 100644 --- a/WPinternals/Models/QualcommSerial.cs +++ b/WPinternals/Models/QualcommSerial.cs @@ -21,6 +21,7 @@ using MadWizard.WinUSBNet; using System; using System.IO.Ports; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/SBL3.cs b/WPinternals/Models/SBL3.cs index 627086a..6334f92 100644 --- a/WPinternals/Models/SBL3.cs +++ b/WPinternals/Models/SBL3.cs @@ -20,6 +20,7 @@ using System; using System.IO; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/Models/UEFI.cs b/WPinternals/Models/UEFI.cs index 25cc6d2..284fbd6 100644 --- a/WPinternals/Models/UEFI.cs +++ b/WPinternals/Models/UEFI.cs @@ -316,7 +316,7 @@ internal void ReplaceFile(string Name, byte[] Binary) EFI File = EFIs.Find(f => string.Equals(Name, f.Name, StringComparison.CurrentCultureIgnoreCase) || string.Equals(Name, f.Guid.ToString(), StringComparison.CurrentCultureIgnoreCase)); if (File == null) { - throw new ArgumentOutOfRangeException(); + throw new ArgumentOutOfRangeException(nameof(Name)); } UInt32 OldBinarySize = File.Size; diff --git a/WPinternals/Terminal.cs b/WPinternals/Terminal/Terminal.cs similarity index 86% rename from WPinternals/Terminal.cs rename to WPinternals/Terminal/Terminal.cs index c58cf54..a5b290b 100644 --- a/WPinternals/Terminal.cs +++ b/WPinternals/Terminal/Terminal.cs @@ -19,9 +19,8 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Collections.Generic; -namespace WPinternals +namespace WPinternals.Terminal { internal static class Terminal { @@ -30,13 +29,13 @@ public static TerminalResponse Parse(byte[] Buffer, int Offset) TerminalResponse Response = new(); // Get root node - if (Buffer.Length >= (Offset + 8)) + if (Buffer.Length >= Offset + 8) { int NodeNumber = BitConverter.ToInt32(Buffer, Offset); int NodeSize = BitConverter.ToInt32(Buffer, Offset + 4); int End = NodeSize + Offset + 8; int Index = Offset + 8; - if ((NodeNumber == 0x10000) && (End <= Buffer.Length)) + if (NodeNumber == 0x10000 && End <= Buffer.Length) { // Get subnodes while (Index < End) @@ -58,11 +57,4 @@ public static TerminalResponse Parse(byte[] Buffer, int Offset) return Response; } } - - internal class TerminalResponse - { - public Dictionary RawEntries = []; - public byte[] PublicId = null; - public byte[] RootKeyHash = null; - } } diff --git a/WPinternals/Terminal/TerminalResponse.cs b/WPinternals/Terminal/TerminalResponse.cs new file mode 100644 index 0000000..77d90f6 --- /dev/null +++ b/WPinternals/Terminal/TerminalResponse.cs @@ -0,0 +1,31 @@ +// Copyright (c) 2018, Rene Lergner - @Heathcliff74xda +// +// 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. + +using System.Collections.Generic; + +namespace WPinternals.Terminal +{ + internal class TerminalResponse + { + public Dictionary RawEntries = []; + public byte[] PublicId = null; + public byte[] RootKeyHash = null; + } +} diff --git a/WPinternals/TestCode.cs b/WPinternals/TestCode.cs index 5402e22..5386810 100644 --- a/WPinternals/TestCode.cs +++ b/WPinternals/TestCode.cs @@ -23,6 +23,8 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using WPinternals.HelperClasses; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { diff --git a/WPinternals/ViewModels/BackupTargetSelectionViewModel.cs b/WPinternals/ViewModels/BackupTargetSelectionViewModel.cs index fe65957..df76fc4 100644 --- a/WPinternals/ViewModels/BackupTargetSelectionViewModel.cs +++ b/WPinternals/ViewModels/BackupTargetSelectionViewModel.cs @@ -20,6 +20,7 @@ using System; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/BackupViewModel.cs b/WPinternals/ViewModels/BackupViewModel.cs index ef6e5cd..146ee45 100644 --- a/WPinternals/ViewModels/BackupViewModel.cs +++ b/WPinternals/ViewModels/BackupViewModel.cs @@ -23,6 +23,7 @@ using System.IO.Compression; using System.Linq; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/BusyViewModel.cs b/WPinternals/ViewModels/BusyViewModel.cs index 2bae9eb..6d8b816 100644 --- a/WPinternals/ViewModels/BusyViewModel.cs +++ b/WPinternals/ViewModels/BusyViewModel.cs @@ -20,6 +20,7 @@ using System; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/ContextViewModel.cs b/WPinternals/ViewModels/ContextViewModel.cs index 493ee77..f652ee8 100644 --- a/WPinternals/ViewModels/ContextViewModel.cs +++ b/WPinternals/ViewModels/ContextViewModel.cs @@ -21,6 +21,7 @@ using System; using System.ComponentModel; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/DisclaimerAndNdaViewModel.cs b/WPinternals/ViewModels/DisclaimerAndNdaViewModel.cs index c78b0cc..cf8d09d 100644 --- a/WPinternals/ViewModels/DisclaimerAndNdaViewModel.cs +++ b/WPinternals/ViewModels/DisclaimerAndNdaViewModel.cs @@ -21,6 +21,7 @@ using Microsoft.Win32; using System; using System.Windows; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/DisclaimerViewModel.cs b/WPinternals/ViewModels/DisclaimerViewModel.cs index f460bfd..6f7c8be 100644 --- a/WPinternals/ViewModels/DisclaimerViewModel.cs +++ b/WPinternals/ViewModels/DisclaimerViewModel.cs @@ -21,6 +21,7 @@ using Microsoft.Win32; using System; using System.Windows; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/DownloadsViewModel.cs b/WPinternals/ViewModels/DownloadsViewModel.cs index f6e1eba..27cff85 100644 --- a/WPinternals/ViewModels/DownloadsViewModel.cs +++ b/WPinternals/ViewModels/DownloadsViewModel.cs @@ -30,6 +30,10 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Data; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { @@ -1082,7 +1086,7 @@ internal HttpClientDownloadProgress(long BytesReceived, long TotalBytesToReceive public static class HttpClientProgressExtensions { - public static async Task DownloadFileAsync(this HttpClient client, Uri address, string fileName, Action progress = null, Action completed = null, CancellationToken cancellationToken = default(CancellationToken)) + public static async Task DownloadFileAsync(this HttpClient client, Uri address, string fileName, Action progress = null, Action completed = null, CancellationToken cancellationToken = default) { try { @@ -1094,25 +1098,22 @@ public static class HttpClientProgressExtensions if (progress is null || !contentLength.HasValue) { await download.CopyToAsync(destination); - if (completed != null) - completed(true); + completed?.Invoke(true); return; } - Progress progressWrapper = new Progress(totalBytes => progress(new HttpClientDownloadProgress(totalBytes, contentLength.Value))); + Progress progressWrapper = new(totalBytes => progress(new HttpClientDownloadProgress(totalBytes, contentLength.Value))); await download.CopyToAsync(destination, 81920, progressWrapper, cancellationToken); - if (completed != null) - completed(true); + completed?.Invoke(true); } catch { - if (completed != null) - completed(false); + completed?.Invoke(false); } } - private static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress progress = null, CancellationToken cancellationToken = default(CancellationToken)) + private static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress progress = null, CancellationToken cancellationToken = default) { if (bufferSize < 0) throw new ArgumentOutOfRangeException(nameof(bufferSize)); @@ -1128,9 +1129,9 @@ public static class HttpClientProgressExtensions byte[] buffer = new byte[bufferSize]; long totalBytesRead = 0; int bytesRead; - while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0) + while ((bytesRead = await source.ReadAsync(buffer, cancellationToken).ConfigureAwait(false)) != 0) { - await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false); + await destination.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken).ConfigureAwait(false); totalBytesRead += bytesRead; progress?.Report(totalBytesRead); } diff --git a/WPinternals/ViewModels/DumpRomTargetSelectionViewModel.cs b/WPinternals/ViewModels/DumpRomTargetSelectionViewModel.cs index aa0a0c5..fb658af 100644 --- a/WPinternals/ViewModels/DumpRomTargetSelectionViewModel.cs +++ b/WPinternals/ViewModels/DumpRomTargetSelectionViewModel.cs @@ -20,6 +20,7 @@ using System; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/DumpRomViewModel.cs b/WPinternals/ViewModels/DumpRomViewModel.cs index 7ba6c40..1d91c02 100644 --- a/WPinternals/ViewModels/DumpRomViewModel.cs +++ b/WPinternals/ViewModels/DumpRomViewModel.cs @@ -21,6 +21,7 @@ using System; using System.Linq; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/HttpDownloader.cs b/WPinternals/ViewModels/HttpDownloader.cs index 6cc955f..937ada6 100644 --- a/WPinternals/ViewModels/HttpDownloader.cs +++ b/WPinternals/ViewModels/HttpDownloader.cs @@ -438,12 +438,12 @@ private static async ValueTask HttpDownload(string basePath, FileDownloadI //read the content //TODO: it may throw an exception (stream closed because file expired?) //In that case we would wrap into another try catch and try to read the reason behind this - while ((bytesRead = await streamToReadFrom.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0) + while ((bytesRead = await streamToReadFrom.ReadAsync(buffer, cancellationToken)) > 0) { totalBytesRead += bytesRead; //simply write to the file - await streamToWriteTo.WriteAsync(buffer, 0, bytesRead, cancellationToken); + await streamToWriteTo.WriteAsync(buffer.AsMemory(0, bytesRead), cancellationToken); //report progress downloadProgress?.Report(new FileDownloadStatus(downloadFile) @@ -593,9 +593,9 @@ public static async ValueTask ComputeHashAsyncT(HashAlgorithm hashAlgori byte[] buffer = new byte[bufSizeEffective]; using MemoryStream ms = new(buffer); using CryptoStream cs = new(ms, hashAlgorithm, CryptoStreamMode.Write); - while ((readBytes = await fileStream.ReadAsync(buffer, 0, buffer.Length, cancellationToken)) > 0) + while ((readBytes = await fileStream.ReadAsync(buffer, cancellationToken)) > 0) { - await cs.WriteAsync(buffer, 0, readBytes, cancellationToken); + await cs.WriteAsync(buffer.AsMemory(0, readBytes), cancellationToken); ms.Position = 0; totalBytesRead += readBytes; progress?.Report(totalBytesRead); diff --git a/WPinternals/ViewModels/LumiaFlashRomSourceSelectionViewModel.cs b/WPinternals/ViewModels/LumiaFlashRomSourceSelectionViewModel.cs index 4acd07f..2fb289f 100644 --- a/WPinternals/ViewModels/LumiaFlashRomSourceSelectionViewModel.cs +++ b/WPinternals/ViewModels/LumiaFlashRomSourceSelectionViewModel.cs @@ -20,6 +20,7 @@ using System; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaFlashRomViewModel.cs b/WPinternals/ViewModels/LumiaFlashRomViewModel.cs index 0b8d53c..d603014 100644 --- a/WPinternals/ViewModels/LumiaFlashRomViewModel.cs +++ b/WPinternals/ViewModels/LumiaFlashRomViewModel.cs @@ -25,6 +25,9 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using WPinternals.HelperClasses; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaInfoViewModel.cs b/WPinternals/ViewModels/LumiaInfoViewModel.cs index 9af2636..ce95dac 100644 --- a/WPinternals/ViewModels/LumiaInfoViewModel.cs +++ b/WPinternals/ViewModels/LumiaInfoViewModel.cs @@ -19,6 +19,11 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaModeViewModel.cs b/WPinternals/ViewModels/LumiaModeViewModel.cs index 38ce379..9ce1436 100644 --- a/WPinternals/ViewModels/LumiaModeViewModel.cs +++ b/WPinternals/ViewModels/LumiaModeViewModel.cs @@ -19,6 +19,11 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaUnlockBootViewModel.cs b/WPinternals/ViewModels/LumiaUnlockBootViewModel.cs index 12b230f..444aa13 100644 --- a/WPinternals/ViewModels/LumiaUnlockBootViewModel.cs +++ b/WPinternals/ViewModels/LumiaUnlockBootViewModel.cs @@ -24,6 +24,11 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using WPinternals.Config; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaUnlockBootloaderViewModel.cs b/WPinternals/ViewModels/LumiaUnlockBootloaderViewModel.cs index adbc23a..e8f9f12 100644 --- a/WPinternals/ViewModels/LumiaUnlockBootloaderViewModel.cs +++ b/WPinternals/ViewModels/LumiaUnlockBootloaderViewModel.cs @@ -26,6 +26,10 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia.UEFI; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaUnlockRootTargetSelectionViewModel.cs b/WPinternals/ViewModels/LumiaUnlockRootTargetSelectionViewModel.cs index f3fae6f..9ba2dba 100644 --- a/WPinternals/ViewModels/LumiaUnlockRootTargetSelectionViewModel.cs +++ b/WPinternals/ViewModels/LumiaUnlockRootTargetSelectionViewModel.cs @@ -20,6 +20,7 @@ using System; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaUnlockRootViewModel.cs b/WPinternals/ViewModels/LumiaUnlockRootViewModel.cs index 082d434..6fc03ab 100644 --- a/WPinternals/ViewModels/LumiaUnlockRootViewModel.cs +++ b/WPinternals/ViewModels/LumiaUnlockRootViewModel.cs @@ -21,6 +21,7 @@ using System; using System.Linq; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaV2UnlockBootViewModel.cs b/WPinternals/ViewModels/LumiaV2UnlockBootViewModel.cs index 313b528..a6bbd86 100644 --- a/WPinternals/ViewModels/LumiaV2UnlockBootViewModel.cs +++ b/WPinternals/ViewModels/LumiaV2UnlockBootViewModel.cs @@ -25,6 +25,12 @@ using System.IO.Compression; using System.Linq; using System.Threading.Tasks; +using WPinternals.Config; +using WPinternals.HelperClasses; +using WPinternals.Models.UEFIApps; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/ViewModels/LumiaV3FlashRomViewModel.cs b/WPinternals/ViewModels/LumiaV3FlashRomViewModel.cs index f7b4f2c..be2e020 100644 --- a/WPinternals/ViewModels/LumiaV3FlashRomViewModel.cs +++ b/WPinternals/ViewModels/LumiaV3FlashRomViewModel.cs @@ -5,6 +5,8 @@ using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; +using WPinternals.HelperClasses; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { @@ -428,7 +430,7 @@ .. LumiaV2UnlockBootViewModel.GetNonOptimizedPayloads(FlashParts, chunkSizes, In retstream.Seek(0, SeekOrigin.Begin); byte[] FfuHeader = new byte[retstream.Length]; - await retstream.ReadAsync(FfuHeader, 0, (Int32)retstream.Length); + await retstream.ReadAsync(FfuHeader.AsMemory(0, (Int32)retstream.Length)); retstream.Close(); Byte Options = 0; diff --git a/WPinternals/ViewModels/MainViewModel.cs b/WPinternals/ViewModels/MainViewModel.cs index 9c8c1aa..49d7e49 100644 --- a/WPinternals/ViewModels/MainViewModel.cs +++ b/WPinternals/ViewModels/MainViewModel.cs @@ -25,6 +25,9 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Input; +using WPinternals.HelperClasses; +using WPinternals.Config; +using WPinternals.Models.Lumia; namespace WPinternals { diff --git a/WPinternals/ViewModels/MessageViewModel.cs b/WPinternals/ViewModels/MessageViewModel.cs index 9ac297c..334d4bb 100644 --- a/WPinternals/ViewModels/MessageViewModel.cs +++ b/WPinternals/ViewModels/MessageViewModel.cs @@ -19,6 +19,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaBootloaderViewModel.cs b/WPinternals/ViewModels/NokiaBootloaderViewModel.cs index 44846a3..f6967f6 100644 --- a/WPinternals/ViewModels/NokiaBootloaderViewModel.cs +++ b/WPinternals/ViewModels/NokiaBootloaderViewModel.cs @@ -20,6 +20,8 @@ using System; using System.Threading; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.BootMgr; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaFlashViewModel.cs b/WPinternals/ViewModels/NokiaFlashViewModel.cs index 4959afb..e0089a5 100644 --- a/WPinternals/ViewModels/NokiaFlashViewModel.cs +++ b/WPinternals/ViewModels/NokiaFlashViewModel.cs @@ -20,6 +20,10 @@ using System; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.Lumia.UEFI; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaLabelViewModel.cs b/WPinternals/ViewModels/NokiaLabelViewModel.cs index b8e9166..5a15757 100644 --- a/WPinternals/ViewModels/NokiaLabelViewModel.cs +++ b/WPinternals/ViewModels/NokiaLabelViewModel.cs @@ -21,6 +21,9 @@ using System; using System.Collections.Generic; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Terminal; namespace WPinternals { @@ -92,7 +95,7 @@ private void StartLoadDeviceInfo() byte[] TerminalResponseBytes = CurrentModel.ExecuteJsonMethodAsBytes("TerminalChallenge", Params, "TerminalResponse"); if (TerminalResponseBytes != null) { - TerminalResponse TerminalResponse = Terminal.Parse(TerminalResponseBytes, 0); + TerminalResponse TerminalResponse = Terminal.Terminal.Parse(TerminalResponseBytes, 0); if (TerminalResponse != null) { PublicID = TerminalResponse.PublicId; diff --git a/WPinternals/ViewModels/NokiaModeBootloaderViewModel.cs b/WPinternals/ViewModels/NokiaModeBootloaderViewModel.cs index 381f958..611463a 100644 --- a/WPinternals/ViewModels/NokiaModeBootloaderViewModel.cs +++ b/WPinternals/ViewModels/NokiaModeBootloaderViewModel.cs @@ -20,6 +20,9 @@ using System; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.BootMgr; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaModeFlashViewModel.cs b/WPinternals/ViewModels/NokiaModeFlashViewModel.cs index 0afb4df..e222a4b 100644 --- a/WPinternals/ViewModels/NokiaModeFlashViewModel.cs +++ b/WPinternals/ViewModels/NokiaModeFlashViewModel.cs @@ -20,6 +20,10 @@ using System; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.Lumia.UEFI; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaModeLabelViewModel.cs b/WPinternals/ViewModels/NokiaModeLabelViewModel.cs index 0f5f41d..21c664c 100644 --- a/WPinternals/ViewModels/NokiaModeLabelViewModel.cs +++ b/WPinternals/ViewModels/NokiaModeLabelViewModel.cs @@ -19,6 +19,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.Models.Lumia; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaModeMassStorageViewModel.cs b/WPinternals/ViewModels/NokiaModeMassStorageViewModel.cs index 0721797..f692533 100644 --- a/WPinternals/ViewModels/NokiaModeMassStorageViewModel.cs +++ b/WPinternals/ViewModels/NokiaModeMassStorageViewModel.cs @@ -19,6 +19,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.Models.Lumia; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaModeNormalViewModel.cs b/WPinternals/ViewModels/NokiaModeNormalViewModel.cs index 554d6bc..cd4acc6 100644 --- a/WPinternals/ViewModels/NokiaModeNormalViewModel.cs +++ b/WPinternals/ViewModels/NokiaModeNormalViewModel.cs @@ -19,6 +19,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using WPinternals.Models.Lumia; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaModePhoneInfoViewModel.cs b/WPinternals/ViewModels/NokiaModePhoneInfoViewModel.cs index 8e2e9d7..9d98c0e 100644 --- a/WPinternals/ViewModels/NokiaModePhoneInfoViewModel.cs +++ b/WPinternals/ViewModels/NokiaModePhoneInfoViewModel.cs @@ -20,6 +20,9 @@ using System; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaNormalViewModel.cs b/WPinternals/ViewModels/NokiaNormalViewModel.cs index a6e29bb..388d42b 100644 --- a/WPinternals/ViewModels/NokiaNormalViewModel.cs +++ b/WPinternals/ViewModels/NokiaNormalViewModel.cs @@ -20,6 +20,8 @@ using System; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; namespace WPinternals { diff --git a/WPinternals/ViewModels/NokiaPhoneInfoViewModel.cs b/WPinternals/ViewModels/NokiaPhoneInfoViewModel.cs index f69010e..e906004 100644 --- a/WPinternals/ViewModels/NokiaPhoneInfoViewModel.cs +++ b/WPinternals/ViewModels/NokiaPhoneInfoViewModel.cs @@ -21,6 +21,9 @@ using System; using System.Collections.Generic; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/ViewModels/PhoneNotifierViewModel.cs b/WPinternals/ViewModels/PhoneNotifierViewModel.cs index 5a25d7f..d9ff0a2 100644 --- a/WPinternals/ViewModels/PhoneNotifierViewModel.cs +++ b/WPinternals/ViewModels/PhoneNotifierViewModel.cs @@ -23,6 +23,13 @@ using System.Diagnostics.Eventing.Reader; using System.Threading; using System.Threading.Tasks; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.Lumia.UEFI; +using WPinternals.Models.UEFIApps; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { @@ -239,7 +246,7 @@ private void LumiaNotifier_Arrival(object sender, USBEvent e) FlashAppType type = FlashAppType.FlashApp; try { - NokiaUEFIModel tmpModel = new NokiaUEFIModel(e.DevicePath); + NokiaUEFIModel tmpModel = new(e.DevicePath); type = tmpModel.GetFlashAppType(); tmpModel.Dispose(); LogFile.Log("Flash App Type: " + type.ToString(), LogType.FileOnly); diff --git a/WPinternals/ViewModels/RegistrationViewModel.cs b/WPinternals/ViewModels/RegistrationViewModel.cs index 5450fe5..cf765c4 100644 --- a/WPinternals/ViewModels/RegistrationViewModel.cs +++ b/WPinternals/ViewModels/RegistrationViewModel.cs @@ -20,6 +20,8 @@ using System; using System.Windows; +using WPinternals.Config; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/RestoreSourceSelectionViewModel.cs b/WPinternals/ViewModels/RestoreSourceSelectionViewModel.cs index 59e0c89..20924d5 100644 --- a/WPinternals/ViewModels/RestoreSourceSelectionViewModel.cs +++ b/WPinternals/ViewModels/RestoreSourceSelectionViewModel.cs @@ -20,6 +20,7 @@ using System; using System.Threading; +using WPinternals.HelperClasses; namespace WPinternals { diff --git a/WPinternals/ViewModels/RestoreViewModel.cs b/WPinternals/ViewModels/RestoreViewModel.cs index dc5013e..d0b7403 100644 --- a/WPinternals/ViewModels/RestoreViewModel.cs +++ b/WPinternals/ViewModels/RestoreViewModel.cs @@ -21,6 +21,8 @@ using System; using System.IO; using System.Threading; +using WPinternals.HelperClasses; +using WPinternals.Models.UEFIApps.Flash; namespace WPinternals { diff --git a/WPinternals/ViewModels/SwitchModeViewModel.cs b/WPinternals/ViewModels/SwitchModeViewModel.cs index 0cfd70b..d57c657 100644 --- a/WPinternals/ViewModels/SwitchModeViewModel.cs +++ b/WPinternals/ViewModels/SwitchModeViewModel.cs @@ -23,6 +23,12 @@ using System.IO; using System.Threading; using System.Threading.Tasks; +using WPinternals.HelperClasses; +using WPinternals.Models.Lumia; +using WPinternals.Models.UEFIApps; +using WPinternals.Models.UEFIApps.BootMgr; +using WPinternals.Models.UEFIApps.Flash; +using WPinternals.Models.UEFIApps.PhoneInfo; namespace WPinternals { diff --git a/WPinternals/Views/About.xaml b/WPinternals/Views/About.xaml index 9dd4ba7..9e13ce7 100644 --- a/WPinternals/Views/About.xaml +++ b/WPinternals/Views/About.xaml @@ -26,6 +26,7 @@ DEALINGS IN THE SOFTWARE. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPinternals" + xmlns:helpers="clr-namespace:WPinternals.HelperClasses" mc:Ignorable="d" d:DesignWidth="700"> @@ -39,9 +40,9 @@ DEALINGS IN THE SOFTWARE. - + - + @@ -88,9 +89,9 @@ DEALINGS IN THE SOFTWARE. license - + - + diff --git a/WPinternals/Views/BackupView.xaml b/WPinternals/Views/BackupView.xaml index fdc8bb4..ac7fbda 100644 --- a/WPinternals/Views/BackupView.xaml +++ b/WPinternals/Views/BackupView.xaml @@ -26,15 +26,16 @@ DEALINGS IN THE SOFTWARE. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPinternals" + xmlns:helpers="clr-namespace:WPinternals.HelperClasses" mc:Ignorable="d" d:DesignWidth="700"> - + - + @@ -45,7 +46,7 @@ DEALINGS IN THE SOFTWARE. - + @@ -57,12 +58,12 @@ DEALINGS IN THE SOFTWARE. - - - - + + + + - +