Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8981fd02e9 | ||
|
|
16d3f95971 | ||
|
|
293c649edb | ||
|
|
88efc77887 | ||
|
|
dc6085f185 | ||
|
|
e2cbb9c6fc | ||
|
|
4b7b9621b4 | ||
|
|
96c42a29b5 | ||
|
|
742c89b9bf | ||
|
|
dbd303fd07 | ||
|
|
8d35be447a | ||
|
|
83c09bdc81 | ||
|
|
93a5064751 | ||
|
|
ef6a962a01 | ||
|
|
d32788198d | ||
|
|
7798dd1c34 | ||
|
|
57cd052d61 | ||
|
|
5eb523530c | ||
|
|
8a17b05398 | ||
|
|
dc5ac1e7d4 | ||
|
|
1d14d79fab | ||
|
|
846ea41883 | ||
|
|
452393aaa7 | ||
|
|
17bc763761 | ||
|
|
668a9b7fe2 | ||
|
|
8293c18406 | ||
|
|
48fbfa77df | ||
|
|
709c91cec5 | ||
|
|
611ad122f9 | ||
|
|
d8fd0aa516 | ||
|
|
7f3c8b1777 | ||
|
|
087457fa0d |
@@ -0,0 +1,60 @@
|
||||
name: Bug Report
|
||||
description: Create a bug report to help improve WPinternals
|
||||
labels: [bug]
|
||||
body:
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Description
|
||||
description: A clear and concise description of what the bug is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: |
|
||||
1. Go to '....'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See the error
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected behavior
|
||||
description: A clear and concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: wpi-version
|
||||
attributes:
|
||||
label: WPinternals Version
|
||||
description: What version of WPinternals are you using?
|
||||
placeholder: v2.9.2
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Windows Version
|
||||
description: What version of Windows are you using? Press <kbd>Win</kbd> + <kbd>Pause/Break</kbd> and copy.
|
||||
placeholder: e.g. Windows 11 21H2 22000.132
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Phone model
|
||||
description: What phone model did you reproduce the bug on (if applicable)
|
||||
placeholder: e.g. Lumia 950 XL (RM-1085)
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Relevant Assets
|
||||
description: |
|
||||
A list of assets (logs, screenshots) relevant to this bug.
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
placeholder: |
|
||||
To upload the log
|
||||
- Copy the `WPinternals.log` files from `%ALLUSERSPROFILE%\WPinternals`
|
||||
- Drag and drop them into this text area.
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
architecture: [x86, x64]
|
||||
architecture: [x86, x64, arm64]
|
||||
platform: [win]
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
- name: Install .NET SDK
|
||||
uses: actions/setup-dotnet@v1
|
||||
with:
|
||||
dotnet-version: "5.0.400"
|
||||
dotnet-version: "8.0.x"
|
||||
|
||||
- name: Add MSBuild to PATH
|
||||
uses: microsoft/setup-msbuild@v1.0.2
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @Heathcliff74xda
|
||||
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
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Windows Phone Internals
|
||||
|
||||
Windows Phone Internals (WPinternals or WPI for short) is a tool designed to unlock the bootloader and/or secure boot of select Lumia devices made by Nokia and Microsoft.
|
||||
Thanks to specifically crafted exploits/techniques the tool is able to disable Bootloader Security/SecureBoot on select Lumia models.
|
||||
|
||||
After unlocking your bootloader you will be able to notably perform the following actions:
|
||||
|
||||
- Boot other Operating Systems
|
||||
- Enable Root Access (on select OS versions)
|
||||
- Flash Custom ROMs
|
||||
- Backup your current Windows Phone ROM
|
||||
- Access your phone internal storage over USB
|
||||
|
||||
## Root Access
|
||||
|
||||
Root Access is a set of patches/hacks disabling security inside Windows Phone at its root. Kernel Security, Permission checks, application container security, deployment capability security and much gets disabled as part of enabling root access.
|
||||
|
||||
## How to get started?
|
||||
|
||||
The tool contains all the documentation you need to know more about the tool, we invite you to read the getting started section of the tool to know more.
|
||||
|
||||
## Where do I download the tool?
|
||||
|
||||
Here: https://github.com/ReneLergner/WPinternals/releases/latest
|
||||
@@ -0,0 +1,8 @@
|
||||
<Application
|
||||
x:Class="RootAccessTestUWP.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:RootAccessTestUWP"
|
||||
RequestedTheme="Dark">
|
||||
|
||||
</Application>
|
||||
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
namespace RootAccessTestUWP
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
sealed partial class App : Application
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
this.Suspending += OnSuspending;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched normally by the end user. Other entry points
|
||||
/// will be used such as when the application is launched to open a specific file.
|
||||
/// </summary>
|
||||
/// <param name="e">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs e)
|
||||
{
|
||||
Frame rootFrame = Window.Current.Content as Frame;
|
||||
|
||||
// Do not repeat app initialization when the Window already has content,
|
||||
// just ensure that the window is active
|
||||
if (rootFrame == null)
|
||||
{
|
||||
// Create a Frame to act as the navigation context and navigate to the first page
|
||||
rootFrame = new Frame();
|
||||
|
||||
rootFrame.NavigationFailed += OnNavigationFailed;
|
||||
|
||||
if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
|
||||
{
|
||||
//TODO: Load state from previously suspended application
|
||||
}
|
||||
|
||||
// Place the frame in the current Window
|
||||
Window.Current.Content = rootFrame;
|
||||
}
|
||||
|
||||
if (e.PrelaunchActivated == false)
|
||||
{
|
||||
if (rootFrame.Content == null)
|
||||
{
|
||||
// When the navigation stack isn't restored navigate to the first page,
|
||||
// configuring the new page by passing required information as a navigation
|
||||
// parameter
|
||||
rootFrame.Navigate(typeof(MainPage), e.Arguments);
|
||||
}
|
||||
// Ensure the current window is active
|
||||
Window.Current.Activate();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when Navigation to a certain page fails
|
||||
/// </summary>
|
||||
/// <param name="sender">The Frame which failed navigation</param>
|
||||
/// <param name="e">Details about the navigation failure</param>
|
||||
void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
|
||||
{
|
||||
throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when application execution is being suspended. Application state is saved
|
||||
/// without knowing whether the application will be terminated or resumed with the contents
|
||||
/// of memory still intact.
|
||||
/// </summary>
|
||||
/// <param name="sender">The source of the suspend request.</param>
|
||||
/// <param name="e">Details about the suspend request.</param>
|
||||
private void OnSuspending(object sender, SuspendingEventArgs e)
|
||||
{
|
||||
var deferral = e.SuspendingOperation.GetDeferral();
|
||||
//TODO: Save application state and stop any background activity
|
||||
deferral.Complete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace RootAccessTestUWP
|
||||
{
|
||||
public static class Core
|
||||
{
|
||||
[DllImport("KERNELBASE.DLL", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int RegQueryValueEx(UIntPtr hKey, string lpValueName, int lpReserved, out Core.RegistryValueKind lpType, IntPtr lpData, ref int lpcbData);
|
||||
|
||||
[DllImport("KERNELBASE.DLL", CharSet = CharSet.Unicode)]
|
||||
private static extern int RegOpenKeyEx(UIntPtr hKey, string subKey, int ulOptions, int samDesired, out UIntPtr hkResult);
|
||||
|
||||
[DllImport("KERNELBASE.DLL", SetLastError = true)]
|
||||
private static extern int RegCloseKey(UIntPtr hKey);
|
||||
|
||||
internal static string RegReadStringValue(UIntPtr rootKey, string keyPath, string valueName)
|
||||
{
|
||||
UIntPtr hKey;
|
||||
int num = Core.RegOpenKeyEx(rootKey, keyPath, 0, Core.KEY_READ, out hKey);
|
||||
if (num != 0)
|
||||
{
|
||||
throw new COMException("Failed to open registry key", num);
|
||||
}
|
||||
int cb = 1024;
|
||||
IntPtr intPtr = Marshal.AllocHGlobal(cb);
|
||||
Core.RegistryValueKind registryValueKind;
|
||||
num = Core.RegQueryValueEx(hKey, valueName, 0, out registryValueKind, intPtr, ref cb);
|
||||
if (num != 0)
|
||||
{
|
||||
throw new COMException("Failed to read registry value", num);
|
||||
}
|
||||
if (registryValueKind != Core.RegistryValueKind.String)
|
||||
{
|
||||
throw new Exception("Wrong registry value type");
|
||||
}
|
||||
string result = Marshal.PtrToStringUni(intPtr);
|
||||
Core.RegCloseKey(hKey);
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static uint RegReadDwordValue(UIntPtr rootKey, string keyPath, string valueName)
|
||||
{
|
||||
UIntPtr hKey;
|
||||
int num = Core.RegOpenKeyEx(rootKey, keyPath, 0, Core.KEY_READ, out hKey);
|
||||
if (num != 0)
|
||||
{
|
||||
throw new COMException("Failed to open registry key", num);
|
||||
}
|
||||
int cb = 1024;
|
||||
IntPtr intPtr = Marshal.AllocHGlobal(cb);
|
||||
Core.RegistryValueKind registryValueKind;
|
||||
num = Core.RegQueryValueEx(hKey, valueName, 0, out registryValueKind, intPtr, ref cb);
|
||||
if (num != 0)
|
||||
{
|
||||
throw new COMException("Failed to read registry value", num);
|
||||
}
|
||||
if (registryValueKind != Core.RegistryValueKind.DWord)
|
||||
{
|
||||
throw new Exception("Wrong registry value type");
|
||||
}
|
||||
uint result = (uint)Marshal.ReadInt32(intPtr);
|
||||
Core.RegCloseKey(hKey);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static UIntPtr HKEY_CLASSES_ROOT = (UIntPtr)2147483648U;
|
||||
|
||||
public static UIntPtr HKEY_CURRENT_USER = (UIntPtr)2147483649U;
|
||||
|
||||
public static UIntPtr HKEY_LOCAL_MACHINE = (UIntPtr)2147483650U;
|
||||
|
||||
public static UIntPtr HKEY_USERS = (UIntPtr)2147483651U;
|
||||
|
||||
private static int KEY_READ = 131097;
|
||||
|
||||
public enum RegistryValueKind
|
||||
{
|
||||
Unknown,
|
||||
String,
|
||||
ExpandString,
|
||||
Binary,
|
||||
DWord,
|
||||
MultiString = 7,
|
||||
QWord = 11,
|
||||
None = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<Page
|
||||
x:Class="RootAccessTestUWP.MainPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:RootAccessTestUWP"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
<TextBlock x:Name="TextBlock"
|
||||
Margin="10"
|
||||
HorizontalAlignment="Stretch"
|
||||
TextWrapping="Wrap"
|
||||
Text=""
|
||||
VerticalAlignment="Stretch"
|
||||
FontFamily="Courier New" />
|
||||
</Grid>
|
||||
</Page>
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices.WindowsRuntime;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
using Windows.UI.Xaml.Input;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
||||
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
|
||||
|
||||
namespace RootAccessTestUWP
|
||||
{
|
||||
/// <summary>
|
||||
/// An empty page that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainPage : Page
|
||||
{
|
||||
public MainPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
||||
TextBlock.Text = "Reading: HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\PhoneProvisioner\\ColdBootDone" + Environment.NewLine + Environment.NewLine;
|
||||
|
||||
bool flag = false;
|
||||
try
|
||||
{
|
||||
Core.RegReadDwordValue(Core.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\PhoneProvisioner", "ColdBootDone");
|
||||
flag = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
TextBlock.Text = string.Concat(new string[]
|
||||
{
|
||||
TextBlock.Text,
|
||||
"Success!",
|
||||
Environment.NewLine,
|
||||
Environment.NewLine,
|
||||
"Root Access: Enabled"
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
TextBlock.Text = string.Concat(new string[]
|
||||
{
|
||||
TextBlock.Text,
|
||||
"Failed!",
|
||||
Environment.NewLine,
|
||||
Environment.NewLine,
|
||||
"Root Access: Disabled"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
IgnorableNamespaces="uap mp">
|
||||
|
||||
<Identity
|
||||
Name="66bf96f4-f5ba-41f1-8ceb-ac4e9065ac52"
|
||||
Publisher="CN=Rene"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<mp:PhoneIdentity PhoneProductId="66bf96f4-f5ba-41f1-8ceb-ac4e9065ac52" PhonePublisherId="00000000-0000-0000-0000-000000000000"/>
|
||||
|
||||
<Properties>
|
||||
<DisplayName>RootAccessTestUWP</DisplayName>
|
||||
<PublisherDisplayName>Rene</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="RootAccessTestUWP.App">
|
||||
<uap:VisualElements
|
||||
DisplayName="RootAccessTestUWP"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png"
|
||||
Description="RootAccessTestUWP"
|
||||
BackgroundColor="transparent">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png"/>
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<Capability Name="internetClient" />
|
||||
</Capabilities>
|
||||
</Package>
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("RootAccessTestUWP")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("RootAccessTestUWP")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2021")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
[assembly: ComVisible(false)]
|
||||
@@ -0,0 +1,31 @@
|
||||
<!--
|
||||
This file contains Runtime Directives used by .NET Native. The defaults here are suitable for most
|
||||
developers. However, you can modify these parameters to modify the behavior of the .NET Native
|
||||
optimizer.
|
||||
|
||||
Runtime Directives are documented at https://go.microsoft.com/fwlink/?LinkID=391919
|
||||
|
||||
To fully enable reflection for App1.MyClass and all of its public/private members
|
||||
<Type Name="App1.MyClass" Dynamic="Required All"/>
|
||||
|
||||
To enable dynamic creation of the specific instantiation of AppClass<T> over System.Int32
|
||||
<TypeInstantiation Name="App1.AppClass" Arguments="System.Int32" Activate="Required Public" />
|
||||
|
||||
Using the Namespace directive to apply reflection policy to all the types in a particular namespace
|
||||
<Namespace Name="DataClasses.ViewModels" Serialize="All" />
|
||||
-->
|
||||
|
||||
<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
|
||||
<Application>
|
||||
<!--
|
||||
An Assembly element with Name="*Application*" applies to all assemblies in
|
||||
the application package. The asterisks are not wildcards.
|
||||
-->
|
||||
<Assembly Name="*Application*" Dynamic="Required All" />
|
||||
|
||||
|
||||
<!-- Add your application specific runtime directives here. -->
|
||||
|
||||
|
||||
</Application>
|
||||
</Directives>
|
||||
@@ -0,0 +1,169 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProjectGuid>{8B6AADBB-C750-492E-AF60-82F6323401CC}</ProjectGuid>
|
||||
<OutputType>AppContainerExe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>RootAccessTestUWP</RootNamespace>
|
||||
<AssemblyName>RootAccessTestUWP</AssemblyName>
|
||||
<DefaultLanguage>en-US</DefaultLanguage>
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition=" '$(TargetPlatformVersion)' == '' ">10.0.22000.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion>10.0.10240.0</TargetPlatformMinVersion>
|
||||
<MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WindowsXamlEnableOverview>true</WindowsXamlEnableOverview>
|
||||
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM64'">
|
||||
<OutputPath>bin\ARM64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RestoreProjectStyle>PackageReference</RestoreProjectStyle>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Core.cs" />
|
||||
<Compile Include="MainPage.xaml.cs">
|
||||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AppxManifest Include="Package.appxmanifest">
|
||||
<SubType>Designer</SubType>
|
||||
</AppxManifest>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Page Include="MainPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform">
|
||||
<Version>6.2.13</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' < '14.0' ">
|
||||
<VisualStudioVersion>14.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
@@ -1,64 +1,64 @@
|
||||
// Common/CRC.cs
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
internal class CRC
|
||||
{
|
||||
public static readonly uint[] Table;
|
||||
|
||||
static CRC()
|
||||
{
|
||||
Table = new uint[256];
|
||||
const uint kPoly = 0xEDB88320;
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if ((r & 1) != 0)
|
||||
{
|
||||
r = (r >> 1) ^ kPoly;
|
||||
}
|
||||
else
|
||||
{
|
||||
r >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
private uint _value = 0xFFFFFFFF;
|
||||
|
||||
public void Init() { _value = 0xFFFFFFFF; }
|
||||
|
||||
public void UpdateByte(byte b)
|
||||
{
|
||||
_value = Table[((byte)_value) ^ b] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public void Update(byte[] data, uint offset, uint size)
|
||||
{
|
||||
for (uint i = 0; i < size; i++)
|
||||
{
|
||||
_value = Table[((byte)_value) ^ data[offset + i]] ^ (_value >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
|
||||
|
||||
private static uint CalculateDigest(byte[] data, uint offset, uint size)
|
||||
{
|
||||
CRC crc = new();
|
||||
// crc.Init();
|
||||
crc.Update(data, offset, size);
|
||||
return crc.GetDigest();
|
||||
}
|
||||
|
||||
private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
|
||||
{
|
||||
return CalculateDigest(data, offset, size) == digest;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Common/CRC.cs
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
internal class CRC
|
||||
{
|
||||
public static readonly uint[] Table;
|
||||
|
||||
static CRC()
|
||||
{
|
||||
Table = new uint[256];
|
||||
const uint kPoly = 0xEDB88320;
|
||||
for (uint i = 0; i < 256; i++)
|
||||
{
|
||||
uint r = i;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
if ((r & 1) != 0)
|
||||
{
|
||||
r = (r >> 1) ^ kPoly;
|
||||
}
|
||||
else
|
||||
{
|
||||
r >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
Table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
private uint _value = 0xFFFFFFFF;
|
||||
|
||||
public void Init() { _value = 0xFFFFFFFF; }
|
||||
|
||||
public void UpdateByte(byte b)
|
||||
{
|
||||
_value = Table[((byte)_value) ^ b] ^ (_value >> 8);
|
||||
}
|
||||
|
||||
public void Update(byte[] data, uint offset, uint size)
|
||||
{
|
||||
for (uint i = 0; i < size; i++)
|
||||
{
|
||||
_value = Table[((byte)_value) ^ data[offset + i]] ^ (_value >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
|
||||
|
||||
private static uint CalculateDigest(byte[] data, uint offset, uint size)
|
||||
{
|
||||
CRC crc = new();
|
||||
// crc.Init();
|
||||
crc.Update(data, offset, size);
|
||||
return crc.GetDigest();
|
||||
}
|
||||
|
||||
private static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
|
||||
{
|
||||
return CalculateDigest(data, offset, size) == digest;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,325 +1,325 @@
|
||||
// CommandLineParser.cs
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace SevenZip.CommandLineParser
|
||||
{
|
||||
public enum SwitchType
|
||||
{
|
||||
Simple,
|
||||
PostMinus,
|
||||
LimitedPostString,
|
||||
UnLimitedPostString,
|
||||
PostChar
|
||||
}
|
||||
|
||||
public class SwitchForm
|
||||
{
|
||||
public string IDString;
|
||||
public SwitchType Type;
|
||||
public bool Multi;
|
||||
public int MinLen;
|
||||
public int MaxLen;
|
||||
public string PostCharSet;
|
||||
|
||||
public SwitchForm(string idString, SwitchType type, bool multi,
|
||||
int minLen, int maxLen, string postCharSet)
|
||||
{
|
||||
IDString = idString;
|
||||
Type = type;
|
||||
Multi = multi;
|
||||
MinLen = minLen;
|
||||
MaxLen = maxLen;
|
||||
PostCharSet = postCharSet;
|
||||
}
|
||||
public SwitchForm(string idString, SwitchType type, bool multi, int minLen) :
|
||||
this(idString, type, multi, minLen, 0, "")
|
||||
{
|
||||
}
|
||||
public SwitchForm(string idString, SwitchType type, bool multi) :
|
||||
this(idString, type, multi, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchResult
|
||||
{
|
||||
public bool ThereIs;
|
||||
public bool WithMinus;
|
||||
public ArrayList PostStrings = new();
|
||||
public int PostCharIndex;
|
||||
public SwitchResult()
|
||||
{
|
||||
ThereIs = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class Parser
|
||||
{
|
||||
public ArrayList NonSwitchStrings = new();
|
||||
private readonly SwitchResult[] _switches;
|
||||
|
||||
public Parser(int numSwitches)
|
||||
{
|
||||
_switches = new SwitchResult[numSwitches];
|
||||
for (int i = 0; i < numSwitches; i++)
|
||||
{
|
||||
_switches[i] = new SwitchResult();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ParseString(string srcString, SwitchForm[] switchForms)
|
||||
{
|
||||
int len = srcString.Length;
|
||||
if (len == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
if (!IsItSwitchChar(srcString[pos]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pos < len)
|
||||
{
|
||||
if (IsItSwitchChar(srcString[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
|
||||
const int kNoLen = -1;
|
||||
int matchedSwitchIndex = 0;
|
||||
int maxLen = kNoLen;
|
||||
for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
|
||||
{
|
||||
int switchLen = switchForms[switchIndex].IDString.Length;
|
||||
if (switchLen <= maxLen || pos + switchLen > len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (String.Compare(switchForms[switchIndex].IDString, 0,
|
||||
srcString, pos, switchLen, true) == 0)
|
||||
{
|
||||
matchedSwitchIndex = switchIndex;
|
||||
maxLen = switchLen;
|
||||
}
|
||||
}
|
||||
if (maxLen == kNoLen)
|
||||
{
|
||||
throw new Exception("maxLen == kNoLen");
|
||||
}
|
||||
|
||||
SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
|
||||
SwitchForm switchForm = switchForms[matchedSwitchIndex];
|
||||
if ((!switchForm.Multi) && matchedSwitch.ThereIs)
|
||||
{
|
||||
throw new Exception("switch must be single");
|
||||
}
|
||||
|
||||
matchedSwitch.ThereIs = true;
|
||||
pos += maxLen;
|
||||
int tailSize = len - pos;
|
||||
SwitchType type = switchForm.Type;
|
||||
switch (type)
|
||||
{
|
||||
case SwitchType.PostMinus:
|
||||
{
|
||||
if (tailSize == 0)
|
||||
{
|
||||
matchedSwitch.WithMinus = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchedSwitch.WithMinus = srcString[pos] == kSwitchMinus;
|
||||
if (matchedSwitch.WithMinus)
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwitchType.PostChar:
|
||||
{
|
||||
if (tailSize < switchForm.MinLen)
|
||||
{
|
||||
throw new Exception("switch is not full");
|
||||
}
|
||||
|
||||
string charSet = switchForm.PostCharSet;
|
||||
const int kEmptyCharValue = -1;
|
||||
if (tailSize == 0)
|
||||
{
|
||||
matchedSwitch.PostCharIndex = kEmptyCharValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = charSet.IndexOf(srcString[pos]);
|
||||
if (index < 0)
|
||||
{
|
||||
matchedSwitch.PostCharIndex = kEmptyCharValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchedSwitch.PostCharIndex = index;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwitchType.LimitedPostString:
|
||||
case SwitchType.UnLimitedPostString:
|
||||
{
|
||||
int minLen = switchForm.MinLen;
|
||||
if (tailSize < minLen)
|
||||
{
|
||||
throw new Exception("switch is not full");
|
||||
}
|
||||
|
||||
if (type == SwitchType.UnLimitedPostString)
|
||||
{
|
||||
matchedSwitch.PostStrings.Add(srcString[pos..]);
|
||||
return true;
|
||||
}
|
||||
String stringSwitch = srcString.Substring(pos, minLen);
|
||||
pos += minLen;
|
||||
for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
|
||||
{
|
||||
char c = srcString[pos];
|
||||
if (IsItSwitchChar(c))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
stringSwitch += c;
|
||||
}
|
||||
matchedSwitch.PostStrings.Add(stringSwitch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
|
||||
{
|
||||
int numCommandStrings = commandStrings.Length;
|
||||
bool stopSwitch = false;
|
||||
for (int i = 0; i < numCommandStrings; i++)
|
||||
{
|
||||
string s = commandStrings[i];
|
||||
if (stopSwitch)
|
||||
{
|
||||
NonSwitchStrings.Add(s);
|
||||
}
|
||||
else
|
||||
if (s == kStopSwitchParsing)
|
||||
{
|
||||
stopSwitch = true;
|
||||
}
|
||||
else
|
||||
if (!ParseString(s, switchForms))
|
||||
{
|
||||
NonSwitchStrings.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SwitchResult this[int index] { get { return _switches[index]; } }
|
||||
|
||||
public static int ParseCommand(CommandForm[] commandForms, string commandString,
|
||||
out string postString)
|
||||
{
|
||||
for (int i = 0; i < commandForms.Length; i++)
|
||||
{
|
||||
string id = commandForms[i].IDString;
|
||||
if (commandForms[i].PostStringMode)
|
||||
{
|
||||
if (commandString.IndexOf(id) == 0)
|
||||
{
|
||||
postString = commandString[id.Length..];
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (commandString == id)
|
||||
{
|
||||
postString = "";
|
||||
return i;
|
||||
}
|
||||
}
|
||||
postString = "";
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
|
||||
string commandString, ArrayList indices)
|
||||
{
|
||||
indices.Clear();
|
||||
int numUsedChars = 0;
|
||||
for (int i = 0; i < numForms; i++)
|
||||
{
|
||||
CommandSubCharsSet charsSet = forms[i];
|
||||
int currentIndex = -1;
|
||||
int len = charsSet.Chars.Length;
|
||||
for (int j = 0; j < len; j++)
|
||||
{
|
||||
char c = charsSet.Chars[j];
|
||||
int newIndex = commandString.IndexOf(c);
|
||||
if (newIndex >= 0)
|
||||
{
|
||||
if (currentIndex >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commandString.IndexOf(c, newIndex + 1) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentIndex = j;
|
||||
numUsedChars++;
|
||||
}
|
||||
}
|
||||
if (currentIndex == -1 && !charsSet.EmptyAllowed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
indices.Add(currentIndex);
|
||||
}
|
||||
return numUsedChars == commandString.Length;
|
||||
}
|
||||
private const char kSwitchID1 = '-';
|
||||
private const char kSwitchID2 = '/';
|
||||
|
||||
private const char kSwitchMinus = '-';
|
||||
private const string kStopSwitchParsing = "--";
|
||||
|
||||
private static bool IsItSwitchChar(char c)
|
||||
{
|
||||
return c == kSwitchID1 || c == kSwitchID2;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandForm
|
||||
{
|
||||
public string IDString = "";
|
||||
public bool PostStringMode = false;
|
||||
public CommandForm(string idString, bool postStringMode)
|
||||
{
|
||||
IDString = idString;
|
||||
PostStringMode = postStringMode;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CommandSubCharsSet
|
||||
{
|
||||
public string Chars = "";
|
||||
public bool EmptyAllowed = false;
|
||||
}
|
||||
}
|
||||
// CommandLineParser.cs
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace SevenZip.CommandLineParser
|
||||
{
|
||||
public enum SwitchType
|
||||
{
|
||||
Simple,
|
||||
PostMinus,
|
||||
LimitedPostString,
|
||||
UnLimitedPostString,
|
||||
PostChar
|
||||
}
|
||||
|
||||
public class SwitchForm
|
||||
{
|
||||
public string IDString;
|
||||
public SwitchType Type;
|
||||
public bool Multi;
|
||||
public int MinLen;
|
||||
public int MaxLen;
|
||||
public string PostCharSet;
|
||||
|
||||
public SwitchForm(string idString, SwitchType type, bool multi,
|
||||
int minLen, int maxLen, string postCharSet)
|
||||
{
|
||||
IDString = idString;
|
||||
Type = type;
|
||||
Multi = multi;
|
||||
MinLen = minLen;
|
||||
MaxLen = maxLen;
|
||||
PostCharSet = postCharSet;
|
||||
}
|
||||
public SwitchForm(string idString, SwitchType type, bool multi, int minLen) :
|
||||
this(idString, type, multi, minLen, 0, "")
|
||||
{
|
||||
}
|
||||
public SwitchForm(string idString, SwitchType type, bool multi) :
|
||||
this(idString, type, multi, 0)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class SwitchResult
|
||||
{
|
||||
public bool ThereIs;
|
||||
public bool WithMinus;
|
||||
public ArrayList PostStrings = new();
|
||||
public int PostCharIndex;
|
||||
public SwitchResult()
|
||||
{
|
||||
ThereIs = false;
|
||||
}
|
||||
}
|
||||
|
||||
public class Parser
|
||||
{
|
||||
public ArrayList NonSwitchStrings = new();
|
||||
private readonly SwitchResult[] _switches;
|
||||
|
||||
public Parser(int numSwitches)
|
||||
{
|
||||
_switches = new SwitchResult[numSwitches];
|
||||
for (int i = 0; i < numSwitches; i++)
|
||||
{
|
||||
_switches[i] = new SwitchResult();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ParseString(string srcString, SwitchForm[] switchForms)
|
||||
{
|
||||
int len = srcString.Length;
|
||||
if (len == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
if (!IsItSwitchChar(srcString[pos]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pos < len)
|
||||
{
|
||||
if (IsItSwitchChar(srcString[pos]))
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
|
||||
const int kNoLen = -1;
|
||||
int matchedSwitchIndex = 0;
|
||||
int maxLen = kNoLen;
|
||||
for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
|
||||
{
|
||||
int switchLen = switchForms[switchIndex].IDString.Length;
|
||||
if (switchLen <= maxLen || pos + switchLen > len)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (String.Compare(switchForms[switchIndex].IDString, 0,
|
||||
srcString, pos, switchLen, true) == 0)
|
||||
{
|
||||
matchedSwitchIndex = switchIndex;
|
||||
maxLen = switchLen;
|
||||
}
|
||||
}
|
||||
if (maxLen == kNoLen)
|
||||
{
|
||||
throw new Exception("maxLen == kNoLen");
|
||||
}
|
||||
|
||||
SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
|
||||
SwitchForm switchForm = switchForms[matchedSwitchIndex];
|
||||
if ((!switchForm.Multi) && matchedSwitch.ThereIs)
|
||||
{
|
||||
throw new Exception("switch must be single");
|
||||
}
|
||||
|
||||
matchedSwitch.ThereIs = true;
|
||||
pos += maxLen;
|
||||
int tailSize = len - pos;
|
||||
SwitchType type = switchForm.Type;
|
||||
switch (type)
|
||||
{
|
||||
case SwitchType.PostMinus:
|
||||
{
|
||||
if (tailSize == 0)
|
||||
{
|
||||
matchedSwitch.WithMinus = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchedSwitch.WithMinus = srcString[pos] == kSwitchMinus;
|
||||
if (matchedSwitch.WithMinus)
|
||||
{
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwitchType.PostChar:
|
||||
{
|
||||
if (tailSize < switchForm.MinLen)
|
||||
{
|
||||
throw new Exception("switch is not full");
|
||||
}
|
||||
|
||||
string charSet = switchForm.PostCharSet;
|
||||
const int kEmptyCharValue = -1;
|
||||
if (tailSize == 0)
|
||||
{
|
||||
matchedSwitch.PostCharIndex = kEmptyCharValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
int index = charSet.IndexOf(srcString[pos]);
|
||||
if (index < 0)
|
||||
{
|
||||
matchedSwitch.PostCharIndex = kEmptyCharValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
matchedSwitch.PostCharIndex = index;
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SwitchType.LimitedPostString:
|
||||
case SwitchType.UnLimitedPostString:
|
||||
{
|
||||
int minLen = switchForm.MinLen;
|
||||
if (tailSize < minLen)
|
||||
{
|
||||
throw new Exception("switch is not full");
|
||||
}
|
||||
|
||||
if (type == SwitchType.UnLimitedPostString)
|
||||
{
|
||||
matchedSwitch.PostStrings.Add(srcString[pos..]);
|
||||
return true;
|
||||
}
|
||||
String stringSwitch = srcString.Substring(pos, minLen);
|
||||
pos += minLen;
|
||||
for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
|
||||
{
|
||||
char c = srcString[pos];
|
||||
if (IsItSwitchChar(c))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
stringSwitch += c;
|
||||
}
|
||||
matchedSwitch.PostStrings.Add(stringSwitch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
|
||||
{
|
||||
int numCommandStrings = commandStrings.Length;
|
||||
bool stopSwitch = false;
|
||||
for (int i = 0; i < numCommandStrings; i++)
|
||||
{
|
||||
string s = commandStrings[i];
|
||||
if (stopSwitch)
|
||||
{
|
||||
NonSwitchStrings.Add(s);
|
||||
}
|
||||
else
|
||||
if (s == kStopSwitchParsing)
|
||||
{
|
||||
stopSwitch = true;
|
||||
}
|
||||
else
|
||||
if (!ParseString(s, switchForms))
|
||||
{
|
||||
NonSwitchStrings.Add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SwitchResult this[int index] { get { return _switches[index]; } }
|
||||
|
||||
public static int ParseCommand(CommandForm[] commandForms, string commandString,
|
||||
out string postString)
|
||||
{
|
||||
for (int i = 0; i < commandForms.Length; i++)
|
||||
{
|
||||
string id = commandForms[i].IDString;
|
||||
if (commandForms[i].PostStringMode)
|
||||
{
|
||||
if (commandString.IndexOf(id) == 0)
|
||||
{
|
||||
postString = commandString[id.Length..];
|
||||
return i;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (commandString == id)
|
||||
{
|
||||
postString = "";
|
||||
return i;
|
||||
}
|
||||
}
|
||||
postString = "";
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
|
||||
string commandString, ArrayList indices)
|
||||
{
|
||||
indices.Clear();
|
||||
int numUsedChars = 0;
|
||||
for (int i = 0; i < numForms; i++)
|
||||
{
|
||||
CommandSubCharsSet charsSet = forms[i];
|
||||
int currentIndex = -1;
|
||||
int len = charsSet.Chars.Length;
|
||||
for (int j = 0; j < len; j++)
|
||||
{
|
||||
char c = charsSet.Chars[j];
|
||||
int newIndex = commandString.IndexOf(c);
|
||||
if (newIndex >= 0)
|
||||
{
|
||||
if (currentIndex >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (commandString.IndexOf(c, newIndex + 1) >= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
currentIndex = j;
|
||||
numUsedChars++;
|
||||
}
|
||||
}
|
||||
if (currentIndex == -1 && !charsSet.EmptyAllowed)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
indices.Add(currentIndex);
|
||||
}
|
||||
return numUsedChars == commandString.Length;
|
||||
}
|
||||
private const char kSwitchID1 = '-';
|
||||
private const char kSwitchID2 = '/';
|
||||
|
||||
private const char kSwitchMinus = '-';
|
||||
private const string kStopSwitchParsing = "--";
|
||||
|
||||
private static bool IsItSwitchChar(char c)
|
||||
{
|
||||
return c == kSwitchID1 || c == kSwitchID2;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandForm
|
||||
{
|
||||
public string IDString = "";
|
||||
public bool PostStringMode = false;
|
||||
public CommandForm(string idString, bool postStringMode)
|
||||
{
|
||||
IDString = idString;
|
||||
PostStringMode = postStringMode;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CommandSubCharsSet
|
||||
{
|
||||
public string Chars = "";
|
||||
public bool EmptyAllowed = false;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +1,78 @@
|
||||
// InBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class InBuffer
|
||||
{
|
||||
private readonly byte[] m_Buffer;
|
||||
private uint m_Pos;
|
||||
private uint m_Limit;
|
||||
private readonly uint m_BufferSize;
|
||||
private System.IO.Stream m_Stream;
|
||||
private bool m_StreamWasExhausted;
|
||||
private ulong m_ProcessedSize;
|
||||
|
||||
public InBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
m_ProcessedSize = 0;
|
||||
m_Limit = 0;
|
||||
m_Pos = 0;
|
||||
m_StreamWasExhausted = false;
|
||||
}
|
||||
|
||||
public bool ReadBlock()
|
||||
{
|
||||
if (m_StreamWasExhausted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ProcessedSize += m_Pos;
|
||||
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
|
||||
m_Pos = 0;
|
||||
m_Limit = (uint)aNumProcessedBytes;
|
||||
m_StreamWasExhausted = aNumProcessedBytes == 0;
|
||||
return !m_StreamWasExhausted;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// m_Stream.Close();
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
public bool ReadByte(byte b) // check it
|
||||
{
|
||||
if (m_Pos >= m_Limit && !ReadBlock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
b = m_Buffer[m_Pos++];
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
// return (byte)m_Stream.ReadByte();
|
||||
if (m_Pos >= m_Limit && !ReadBlock())
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return m_Buffer[m_Pos++];
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize()
|
||||
{
|
||||
return m_ProcessedSize + m_Pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// InBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class InBuffer
|
||||
{
|
||||
private readonly byte[] m_Buffer;
|
||||
private uint m_Pos;
|
||||
private uint m_Limit;
|
||||
private readonly uint m_BufferSize;
|
||||
private System.IO.Stream m_Stream;
|
||||
private bool m_StreamWasExhausted;
|
||||
private ulong m_ProcessedSize;
|
||||
|
||||
public InBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
m_Stream = stream;
|
||||
m_ProcessedSize = 0;
|
||||
m_Limit = 0;
|
||||
m_Pos = 0;
|
||||
m_StreamWasExhausted = false;
|
||||
}
|
||||
|
||||
public bool ReadBlock()
|
||||
{
|
||||
if (m_StreamWasExhausted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_ProcessedSize += m_Pos;
|
||||
int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
|
||||
m_Pos = 0;
|
||||
m_Limit = (uint)aNumProcessedBytes;
|
||||
m_StreamWasExhausted = aNumProcessedBytes == 0;
|
||||
return !m_StreamWasExhausted;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// m_Stream.Close();
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
public bool ReadByte(byte b) // check it
|
||||
{
|
||||
if (m_Pos >= m_Limit && !ReadBlock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
b = m_Buffer[m_Pos++];
|
||||
return true;
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
// return (byte)m_Stream.ReadByte();
|
||||
if (m_Pos >= m_Limit && !ReadBlock())
|
||||
{
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return m_Buffer[m_Pos++];
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize()
|
||||
{
|
||||
return m_ProcessedSize + m_Pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,52 +1,52 @@
|
||||
// OutBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class OutBuffer
|
||||
{
|
||||
private readonly byte[] m_Buffer;
|
||||
private uint m_Pos;
|
||||
private readonly uint m_BufferSize;
|
||||
private System.IO.Stream m_Stream;
|
||||
private ulong m_ProcessedSize;
|
||||
|
||||
public OutBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
|
||||
public void FlushStream() { m_Stream.Flush(); }
|
||||
public void CloseStream() { m_Stream.Close(); }
|
||||
public void ReleaseStream() { m_Stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_ProcessedSize = 0;
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
m_Buffer[m_Pos++] = b;
|
||||
if (m_Pos >= m_BufferSize)
|
||||
{
|
||||
FlushData();
|
||||
}
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
if (m_Pos == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Stream.Write(m_Buffer, 0, (int)m_Pos);
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
|
||||
}
|
||||
}
|
||||
// OutBuffer.cs
|
||||
|
||||
namespace SevenZip.Buffer
|
||||
{
|
||||
public class OutBuffer
|
||||
{
|
||||
private readonly byte[] m_Buffer;
|
||||
private uint m_Pos;
|
||||
private readonly uint m_BufferSize;
|
||||
private System.IO.Stream m_Stream;
|
||||
private ulong m_ProcessedSize;
|
||||
|
||||
public OutBuffer(uint bufferSize)
|
||||
{
|
||||
m_Buffer = new byte[bufferSize];
|
||||
m_BufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
|
||||
public void FlushStream() { m_Stream.Flush(); }
|
||||
public void CloseStream() { m_Stream.Close(); }
|
||||
public void ReleaseStream() { m_Stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_ProcessedSize = 0;
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public void WriteByte(byte b)
|
||||
{
|
||||
m_Buffer[m_Pos++] = b;
|
||||
if (m_Pos >= m_BufferSize)
|
||||
{
|
||||
FlushData();
|
||||
}
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
if (m_Pos == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Stream.Write(m_Buffer, 0, (int)m_Pos);
|
||||
m_Pos = 0;
|
||||
}
|
||||
|
||||
public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,24 @@
|
||||
// IMatchFinder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
internal interface IInWindowStream
|
||||
{
|
||||
void SetStream(System.IO.Stream inStream);
|
||||
void Init();
|
||||
void ReleaseStream();
|
||||
Byte GetIndexByte(Int32 index);
|
||||
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
|
||||
UInt32 GetNumAvailableBytes();
|
||||
}
|
||||
|
||||
internal interface IMatchFinder : IInWindowStream
|
||||
{
|
||||
void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
|
||||
UInt32 GetMatches(UInt32[] distances);
|
||||
void Skip(UInt32 num);
|
||||
}
|
||||
}
|
||||
// IMatchFinder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
internal interface IInWindowStream
|
||||
{
|
||||
void SetStream(System.IO.Stream inStream);
|
||||
void Init();
|
||||
void ReleaseStream();
|
||||
Byte GetIndexByte(Int32 index);
|
||||
UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
|
||||
UInt32 GetNumAvailableBytes();
|
||||
}
|
||||
|
||||
internal interface IMatchFinder : IInWindowStream
|
||||
{
|
||||
void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
|
||||
UInt32 GetMatches(UInt32[] distances);
|
||||
void Skip(UInt32 num);
|
||||
}
|
||||
}
|
||||
@@ -1,408 +1,408 @@
|
||||
// LzBinTree.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class BinTree : InWindow, IMatchFinder
|
||||
{
|
||||
private UInt32 _cyclicBufferPos;
|
||||
private UInt32 _cyclicBufferSize = 0;
|
||||
private UInt32 _matchMaxLen;
|
||||
|
||||
private UInt32[] _son;
|
||||
private UInt32[] _hash;
|
||||
|
||||
private UInt32 _cutValue = 0xFF;
|
||||
private UInt32 _hashMask;
|
||||
private UInt32 _hashSizeSum = 0;
|
||||
|
||||
private bool HASH_ARRAY = true;
|
||||
|
||||
private const UInt32 kHash2Size = 1 << 10;
|
||||
private const UInt32 kHash3Size = 1 << 16;
|
||||
private const UInt32 kBT2HashSize = 1 << 16;
|
||||
private const UInt32 kStartMaxLen = 1;
|
||||
private const UInt32 kHash3Offset = kHash2Size;
|
||||
private const UInt32 kEmptyHashValue = 0;
|
||||
private const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
|
||||
|
||||
private UInt32 kNumHashDirectBytes = 0;
|
||||
private UInt32 kMinMatchCheck = 4;
|
||||
private UInt32 kFixHashSize = kHash2Size + kHash3Size;
|
||||
|
||||
public void SetType(int numHashBytes)
|
||||
{
|
||||
HASH_ARRAY = numHashBytes > 2;
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
kNumHashDirectBytes = 0;
|
||||
kMinMatchCheck = 4;
|
||||
kFixHashSize = kHash2Size + kHash3Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNumHashDirectBytes = 2;
|
||||
kMinMatchCheck = 2 + 1;
|
||||
kFixHashSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
|
||||
public new void ReleaseStream() { base.ReleaseStream(); }
|
||||
|
||||
public new void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (UInt32 i = 0; i < _hashSizeSum; i++)
|
||||
{
|
||||
_hash[i] = kEmptyHashValue;
|
||||
}
|
||||
|
||||
_cyclicBufferPos = 0;
|
||||
ReduceOffsets(-1);
|
||||
}
|
||||
|
||||
public new void MovePos()
|
||||
{
|
||||
if (++_cyclicBufferPos >= _cyclicBufferSize)
|
||||
{
|
||||
_cyclicBufferPos = 0;
|
||||
}
|
||||
|
||||
base.MovePos();
|
||||
if (_pos == kMaxValForNormalize)
|
||||
{
|
||||
Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
|
||||
|
||||
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{ return base.GetMatchLen(index, distance, limit); }
|
||||
|
||||
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
|
||||
|
||||
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
|
||||
{
|
||||
if (historySize > kMaxValForNormalize - 256)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
_cutValue = 16 + (matchMaxLen >> 1);
|
||||
|
||||
UInt32 windowReservSize = ((historySize + keepAddBufferBefore +
|
||||
matchMaxLen + keepAddBufferAfter) / 2) + 256;
|
||||
|
||||
Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
|
||||
|
||||
_matchMaxLen = matchMaxLen;
|
||||
|
||||
UInt32 cyclicBufferSize = historySize + 1;
|
||||
if (_cyclicBufferSize != cyclicBufferSize)
|
||||
{
|
||||
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
|
||||
}
|
||||
|
||||
UInt32 hs = kBT2HashSize;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= hs >> 1;
|
||||
hs |= hs >> 2;
|
||||
hs |= hs >> 4;
|
||||
hs |= hs >> 8;
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF;
|
||||
if (hs > (1 << 24))
|
||||
{
|
||||
hs >>= 1;
|
||||
}
|
||||
|
||||
_hashMask = hs;
|
||||
hs++;
|
||||
hs += kFixHashSize;
|
||||
}
|
||||
if (hs != _hashSizeSum)
|
||||
{
|
||||
_hash = new UInt32[_hashSizeSum = hs];
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetMatches(UInt32[] distances)
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
{
|
||||
lenLimit = _matchMaxLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 offset = 0;
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
|
||||
UInt32 hashValue, hash2Value = 0, hash3Value = 0;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
hash2Value = temp & (kHash2Size - 1);
|
||||
temp ^= (UInt32)_bufferBase[cur + 2] << 8;
|
||||
hash3Value = temp & (kHash3Size - 1);
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
|
||||
}
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 curMatch2 = _hash[hash2Value];
|
||||
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
|
||||
_hash[hash2Value] = _pos;
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
if (curMatch2 > matchMinPos && _bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
|
||||
{
|
||||
distances[offset++] = maxLen = 2;
|
||||
distances[offset++] = _pos - curMatch2 - 1;
|
||||
}
|
||||
|
||||
if (curMatch3 > matchMinPos && _bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
|
||||
{
|
||||
if (curMatch3 == curMatch2)
|
||||
{
|
||||
offset -= 2;
|
||||
}
|
||||
|
||||
distances[offset++] = maxLen = 3;
|
||||
distances[offset++] = _pos - curMatch3 - 1;
|
||||
curMatch2 = curMatch3;
|
||||
}
|
||||
|
||||
if (offset != 0 && curMatch2 == curMatch)
|
||||
{
|
||||
offset -= 2;
|
||||
maxLen = kStartMaxLen;
|
||||
}
|
||||
}
|
||||
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = _cyclicBufferPos << 1;
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
if (kNumHashDirectBytes != 0 && curMatch > matchMinPos)
|
||||
{
|
||||
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
|
||||
_bufferBase[cur + kNumHashDirectBytes])
|
||||
{
|
||||
distances[offset++] = maxLen = kNumHashDirectBytes;
|
||||
distances[offset++] = _pos - curMatch - 1;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
{
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxLen < len)
|
||||
{
|
||||
distances[offset++] = maxLen = len;
|
||||
distances[offset++] = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Skip(UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
{
|
||||
lenLimit = _matchMaxLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
|
||||
UInt32 hashValue;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
UInt32 hash2Value = temp & (kHash2Size - 1);
|
||||
_hash[hash2Value] = _pos;
|
||||
temp ^= (UInt32)_bufferBase[cur + 2] << 8;
|
||||
UInt32 hash3Value = temp & (kHash3Size - 1);
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
|
||||
}
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = _cyclicBufferPos << 1;
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
{
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
|
||||
{
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
{
|
||||
value = kEmptyHashValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
value -= subValue;
|
||||
}
|
||||
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void Normalize()
|
||||
{
|
||||
UInt32 subValue = _pos - _cyclicBufferSize;
|
||||
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
|
||||
NormalizeLinks(_hash, _hashSizeSum, subValue);
|
||||
ReduceOffsets((Int32)subValue);
|
||||
}
|
||||
|
||||
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
}
|
||||
}
|
||||
// LzBinTree.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class BinTree : InWindow, IMatchFinder
|
||||
{
|
||||
private UInt32 _cyclicBufferPos;
|
||||
private UInt32 _cyclicBufferSize = 0;
|
||||
private UInt32 _matchMaxLen;
|
||||
|
||||
private UInt32[] _son;
|
||||
private UInt32[] _hash;
|
||||
|
||||
private UInt32 _cutValue = 0xFF;
|
||||
private UInt32 _hashMask;
|
||||
private UInt32 _hashSizeSum = 0;
|
||||
|
||||
private bool HASH_ARRAY = true;
|
||||
|
||||
private const UInt32 kHash2Size = 1 << 10;
|
||||
private const UInt32 kHash3Size = 1 << 16;
|
||||
private const UInt32 kBT2HashSize = 1 << 16;
|
||||
private const UInt32 kStartMaxLen = 1;
|
||||
private const UInt32 kHash3Offset = kHash2Size;
|
||||
private const UInt32 kEmptyHashValue = 0;
|
||||
private const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
|
||||
|
||||
private UInt32 kNumHashDirectBytes = 0;
|
||||
private UInt32 kMinMatchCheck = 4;
|
||||
private UInt32 kFixHashSize = kHash2Size + kHash3Size;
|
||||
|
||||
public void SetType(int numHashBytes)
|
||||
{
|
||||
HASH_ARRAY = numHashBytes > 2;
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
kNumHashDirectBytes = 0;
|
||||
kMinMatchCheck = 4;
|
||||
kFixHashSize = kHash2Size + kHash3Size;
|
||||
}
|
||||
else
|
||||
{
|
||||
kNumHashDirectBytes = 2;
|
||||
kMinMatchCheck = 2 + 1;
|
||||
kFixHashSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
|
||||
public new void ReleaseStream() { base.ReleaseStream(); }
|
||||
|
||||
public new void Init()
|
||||
{
|
||||
base.Init();
|
||||
for (UInt32 i = 0; i < _hashSizeSum; i++)
|
||||
{
|
||||
_hash[i] = kEmptyHashValue;
|
||||
}
|
||||
|
||||
_cyclicBufferPos = 0;
|
||||
ReduceOffsets(-1);
|
||||
}
|
||||
|
||||
public new void MovePos()
|
||||
{
|
||||
if (++_cyclicBufferPos >= _cyclicBufferSize)
|
||||
{
|
||||
_cyclicBufferPos = 0;
|
||||
}
|
||||
|
||||
base.MovePos();
|
||||
if (_pos == kMaxValForNormalize)
|
||||
{
|
||||
Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
|
||||
|
||||
public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{ return base.GetMatchLen(index, distance, limit); }
|
||||
|
||||
public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
|
||||
|
||||
public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
|
||||
UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
|
||||
{
|
||||
if (historySize > kMaxValForNormalize - 256)
|
||||
{
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
_cutValue = 16 + (matchMaxLen >> 1);
|
||||
|
||||
UInt32 windowReservSize = ((historySize + keepAddBufferBefore +
|
||||
matchMaxLen + keepAddBufferAfter) / 2) + 256;
|
||||
|
||||
Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
|
||||
|
||||
_matchMaxLen = matchMaxLen;
|
||||
|
||||
UInt32 cyclicBufferSize = historySize + 1;
|
||||
if (_cyclicBufferSize != cyclicBufferSize)
|
||||
{
|
||||
_son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
|
||||
}
|
||||
|
||||
UInt32 hs = kBT2HashSize;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
hs = historySize - 1;
|
||||
hs |= hs >> 1;
|
||||
hs |= hs >> 2;
|
||||
hs |= hs >> 4;
|
||||
hs |= hs >> 8;
|
||||
hs >>= 1;
|
||||
hs |= 0xFFFF;
|
||||
if (hs > (1 << 24))
|
||||
{
|
||||
hs >>= 1;
|
||||
}
|
||||
|
||||
_hashMask = hs;
|
||||
hs++;
|
||||
hs += kFixHashSize;
|
||||
}
|
||||
if (hs != _hashSizeSum)
|
||||
{
|
||||
_hash = new UInt32[_hashSizeSum = hs];
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetMatches(UInt32[] distances)
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
{
|
||||
lenLimit = _matchMaxLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 offset = 0;
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
|
||||
UInt32 hashValue, hash2Value = 0, hash3Value = 0;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
hash2Value = temp & (kHash2Size - 1);
|
||||
temp ^= (UInt32)_bufferBase[cur + 2] << 8;
|
||||
hash3Value = temp & (kHash3Size - 1);
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
|
||||
}
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 curMatch2 = _hash[hash2Value];
|
||||
UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
|
||||
_hash[hash2Value] = _pos;
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
if (curMatch2 > matchMinPos && _bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
|
||||
{
|
||||
distances[offset++] = maxLen = 2;
|
||||
distances[offset++] = _pos - curMatch2 - 1;
|
||||
}
|
||||
|
||||
if (curMatch3 > matchMinPos && _bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
|
||||
{
|
||||
if (curMatch3 == curMatch2)
|
||||
{
|
||||
offset -= 2;
|
||||
}
|
||||
|
||||
distances[offset++] = maxLen = 3;
|
||||
distances[offset++] = _pos - curMatch3 - 1;
|
||||
curMatch2 = curMatch3;
|
||||
}
|
||||
|
||||
if (offset != 0 && curMatch2 == curMatch)
|
||||
{
|
||||
offset -= 2;
|
||||
maxLen = kStartMaxLen;
|
||||
}
|
||||
}
|
||||
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = _cyclicBufferPos << 1;
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
if (kNumHashDirectBytes != 0 && curMatch > matchMinPos)
|
||||
{
|
||||
if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
|
||||
_bufferBase[cur + kNumHashDirectBytes])
|
||||
{
|
||||
distances[offset++] = maxLen = kNumHashDirectBytes;
|
||||
distances[offset++] = _pos - curMatch - 1;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
{
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxLen < len)
|
||||
{
|
||||
distances[offset++] = maxLen = len;
|
||||
distances[offset++] = delta - 1;
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
return offset;
|
||||
}
|
||||
|
||||
public void Skip(UInt32 num)
|
||||
{
|
||||
do
|
||||
{
|
||||
UInt32 lenLimit;
|
||||
if (_pos + _matchMaxLen <= _streamPos)
|
||||
{
|
||||
lenLimit = _matchMaxLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
lenLimit = _streamPos - _pos;
|
||||
if (lenLimit < kMinMatchCheck)
|
||||
{
|
||||
MovePos();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
|
||||
UInt32 cur = _bufferOffset + _pos;
|
||||
|
||||
UInt32 hashValue;
|
||||
|
||||
if (HASH_ARRAY)
|
||||
{
|
||||
UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
|
||||
UInt32 hash2Value = temp & (kHash2Size - 1);
|
||||
_hash[hash2Value] = _pos;
|
||||
temp ^= (UInt32)_bufferBase[cur + 2] << 8;
|
||||
UInt32 hash3Value = temp & (kHash3Size - 1);
|
||||
_hash[kHash3Offset + hash3Value] = _pos;
|
||||
hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
hashValue = _bufferBase[cur] ^ ((UInt32)_bufferBase[cur + 1] << 8);
|
||||
}
|
||||
|
||||
UInt32 curMatch = _hash[kFixHashSize + hashValue];
|
||||
_hash[kFixHashSize + hashValue] = _pos;
|
||||
|
||||
UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
|
||||
UInt32 ptr1 = _cyclicBufferPos << 1;
|
||||
|
||||
UInt32 len0, len1;
|
||||
len0 = len1 = kNumHashDirectBytes;
|
||||
|
||||
UInt32 count = _cutValue;
|
||||
while (true)
|
||||
{
|
||||
if (curMatch <= matchMinPos || count-- == 0)
|
||||
{
|
||||
_son[ptr0] = _son[ptr1] = kEmptyHashValue;
|
||||
break;
|
||||
}
|
||||
|
||||
UInt32 delta = _pos - curMatch;
|
||||
UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
|
||||
(_cyclicBufferPos - delta) :
|
||||
(_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
|
||||
|
||||
UInt32 pby1 = _bufferOffset + curMatch;
|
||||
UInt32 len = Math.Min(len0, len1);
|
||||
if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
|
||||
{
|
||||
while (++len != lenLimit)
|
||||
{
|
||||
if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (len == lenLimit)
|
||||
{
|
||||
_son[ptr1] = _son[cyclicPos];
|
||||
_son[ptr0] = _son[cyclicPos + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
|
||||
{
|
||||
_son[ptr1] = curMatch;
|
||||
ptr1 = cyclicPos + 1;
|
||||
curMatch = _son[ptr1];
|
||||
len1 = len;
|
||||
}
|
||||
else
|
||||
{
|
||||
_son[ptr0] = curMatch;
|
||||
ptr0 = cyclicPos;
|
||||
curMatch = _son[ptr0];
|
||||
len0 = len;
|
||||
}
|
||||
}
|
||||
MovePos();
|
||||
}
|
||||
while (--num != 0);
|
||||
}
|
||||
|
||||
private void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
|
||||
{
|
||||
for (UInt32 i = 0; i < numItems; i++)
|
||||
{
|
||||
UInt32 value = items[i];
|
||||
if (value <= subValue)
|
||||
{
|
||||
value = kEmptyHashValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
value -= subValue;
|
||||
}
|
||||
|
||||
items[i] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void Normalize()
|
||||
{
|
||||
UInt32 subValue = _pos - _cyclicBufferSize;
|
||||
NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
|
||||
NormalizeLinks(_hash, _hashSizeSum, subValue);
|
||||
ReduceOffsets((Int32)subValue);
|
||||
}
|
||||
|
||||
public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
|
||||
}
|
||||
}
|
||||
@@ -1,155 +1,155 @@
|
||||
// LzInWindow.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class InWindow
|
||||
{
|
||||
public Byte[] _bufferBase = null; // pointer to buffer with data
|
||||
private System.IO.Stream _stream;
|
||||
private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
|
||||
private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
|
||||
|
||||
private UInt32 _pointerToLastSafePosition;
|
||||
|
||||
public UInt32 _bufferOffset;
|
||||
|
||||
public UInt32 _blockSize; // Size of Allocated memory block
|
||||
public UInt32 _pos; // offset (from _buffer) of curent byte
|
||||
private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
|
||||
private UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
|
||||
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
|
||||
|
||||
public void MoveBlock()
|
||||
{
|
||||
UInt32 offset = _bufferOffset + _pos - _keepSizeBefore;
|
||||
// we need one additional byte, since MovePos moves on 1 byte.
|
||||
if (offset > 0)
|
||||
{
|
||||
offset--;
|
||||
}
|
||||
|
||||
UInt32 numBytes = _bufferOffset + _streamPos - offset;
|
||||
|
||||
// check negative offset ????
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
{
|
||||
_bufferBase[i] = _bufferBase[offset + i];
|
||||
}
|
||||
|
||||
_bufferOffset -= offset;
|
||||
}
|
||||
|
||||
public virtual void ReadBlock()
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
int size = (int)(0 - _bufferOffset + _blockSize - _streamPos);
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
_posLimit = _streamPos;
|
||||
UInt32 pointerToPostion = _bufferOffset + _posLimit;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
{
|
||||
_posLimit = _pointerToLastSafePosition - _bufferOffset;
|
||||
}
|
||||
|
||||
_streamEndWasReached = true;
|
||||
return;
|
||||
}
|
||||
_streamPos += (UInt32)numReadBytes;
|
||||
if (_streamPos >= _pos + _keepSizeAfter)
|
||||
{
|
||||
_posLimit = _streamPos - _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Free() { _bufferBase = null; }
|
||||
|
||||
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
|
||||
{
|
||||
_keepSizeBefore = keepSizeBefore;
|
||||
_keepSizeAfter = keepSizeAfter;
|
||||
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
|
||||
if (_bufferBase == null || _blockSize != blockSize)
|
||||
{
|
||||
Free();
|
||||
_blockSize = blockSize;
|
||||
_bufferBase = new Byte[_blockSize];
|
||||
}
|
||||
_pointerToLastSafePosition = _blockSize - keepSizeAfter;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { _stream = stream; }
|
||||
public void ReleaseStream() { _stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_bufferOffset = 0;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_streamEndWasReached = false;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
public void MovePos()
|
||||
{
|
||||
_pos++;
|
||||
if (_pos > _posLimit)
|
||||
{
|
||||
UInt32 pointerToPostion = _bufferOffset + _pos;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
{
|
||||
MoveBlock();
|
||||
}
|
||||
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
|
||||
|
||||
// index + limit have not to exceed _keepSizeAfter;
|
||||
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
if (_streamEndWasReached && _pos + index + limit > _streamPos)
|
||||
{
|
||||
limit = _streamPos - (UInt32)(_pos + index);
|
||||
}
|
||||
|
||||
distance++;
|
||||
// Byte *pby = _buffer + (size_t)_pos + index;
|
||||
UInt32 pby = _bufferOffset + _pos + (UInt32)index;
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++)
|
||||
{
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
|
||||
|
||||
public void ReduceOffsets(Int32 subValue)
|
||||
{
|
||||
_bufferOffset += (UInt32)subValue;
|
||||
_posLimit -= (UInt32)subValue;
|
||||
_pos -= (UInt32)subValue;
|
||||
_streamPos -= (UInt32)subValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
// LzInWindow.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class InWindow
|
||||
{
|
||||
public Byte[] _bufferBase = null; // pointer to buffer with data
|
||||
private System.IO.Stream _stream;
|
||||
private UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
|
||||
private bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
|
||||
|
||||
private UInt32 _pointerToLastSafePosition;
|
||||
|
||||
public UInt32 _bufferOffset;
|
||||
|
||||
public UInt32 _blockSize; // Size of Allocated memory block
|
||||
public UInt32 _pos; // offset (from _buffer) of curent byte
|
||||
private UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
|
||||
private UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
|
||||
public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
|
||||
|
||||
public void MoveBlock()
|
||||
{
|
||||
UInt32 offset = _bufferOffset + _pos - _keepSizeBefore;
|
||||
// we need one additional byte, since MovePos moves on 1 byte.
|
||||
if (offset > 0)
|
||||
{
|
||||
offset--;
|
||||
}
|
||||
|
||||
UInt32 numBytes = _bufferOffset + _streamPos - offset;
|
||||
|
||||
// check negative offset ????
|
||||
for (UInt32 i = 0; i < numBytes; i++)
|
||||
{
|
||||
_bufferBase[i] = _bufferBase[offset + i];
|
||||
}
|
||||
|
||||
_bufferOffset -= offset;
|
||||
}
|
||||
|
||||
public virtual void ReadBlock()
|
||||
{
|
||||
if (_streamEndWasReached)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
int size = (int)(0 - _bufferOffset + _blockSize - _streamPos);
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
_posLimit = _streamPos;
|
||||
UInt32 pointerToPostion = _bufferOffset + _posLimit;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
{
|
||||
_posLimit = _pointerToLastSafePosition - _bufferOffset;
|
||||
}
|
||||
|
||||
_streamEndWasReached = true;
|
||||
return;
|
||||
}
|
||||
_streamPos += (UInt32)numReadBytes;
|
||||
if (_streamPos >= _pos + _keepSizeAfter)
|
||||
{
|
||||
_posLimit = _streamPos - _keepSizeAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Free() { _bufferBase = null; }
|
||||
|
||||
public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
|
||||
{
|
||||
_keepSizeBefore = keepSizeBefore;
|
||||
_keepSizeAfter = keepSizeAfter;
|
||||
UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
|
||||
if (_bufferBase == null || _blockSize != blockSize)
|
||||
{
|
||||
Free();
|
||||
_blockSize = blockSize;
|
||||
_bufferBase = new Byte[_blockSize];
|
||||
}
|
||||
_pointerToLastSafePosition = _blockSize - keepSizeAfter;
|
||||
}
|
||||
|
||||
public void SetStream(System.IO.Stream stream) { _stream = stream; }
|
||||
public void ReleaseStream() { _stream = null; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
_bufferOffset = 0;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
_streamEndWasReached = false;
|
||||
ReadBlock();
|
||||
}
|
||||
|
||||
public void MovePos()
|
||||
{
|
||||
_pos++;
|
||||
if (_pos > _posLimit)
|
||||
{
|
||||
UInt32 pointerToPostion = _bufferOffset + _pos;
|
||||
if (pointerToPostion > _pointerToLastSafePosition)
|
||||
{
|
||||
MoveBlock();
|
||||
}
|
||||
|
||||
ReadBlock();
|
||||
}
|
||||
}
|
||||
|
||||
public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
|
||||
|
||||
// index + limit have not to exceed _keepSizeAfter;
|
||||
public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
|
||||
{
|
||||
if (_streamEndWasReached && _pos + index + limit > _streamPos)
|
||||
{
|
||||
limit = _streamPos - (UInt32)(_pos + index);
|
||||
}
|
||||
|
||||
distance++;
|
||||
// Byte *pby = _buffer + (size_t)_pos + index;
|
||||
UInt32 pby = _bufferOffset + _pos + (UInt32)index;
|
||||
|
||||
UInt32 i;
|
||||
for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++)
|
||||
{
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
|
||||
|
||||
public void ReduceOffsets(Int32 subValue)
|
||||
{
|
||||
_bufferOffset += (UInt32)subValue;
|
||||
_posLimit -= (UInt32)subValue;
|
||||
_pos -= (UInt32)subValue;
|
||||
_streamPos -= (UInt32)subValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,137 +1,137 @@
|
||||
// LzOutWindow.cs
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class OutWindow
|
||||
{
|
||||
private byte[] _buffer = null;
|
||||
private uint _pos;
|
||||
private uint _windowSize = 0;
|
||||
private uint _streamPos;
|
||||
private System.IO.Stream _stream;
|
||||
|
||||
public uint TrainSize = 0;
|
||||
|
||||
public void Create(uint windowSize)
|
||||
{
|
||||
if (_windowSize != windowSize)
|
||||
{
|
||||
// System.GC.Collect();
|
||||
_buffer = new byte[windowSize];
|
||||
}
|
||||
_windowSize = windowSize;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream, bool solid)
|
||||
{
|
||||
ReleaseStream();
|
||||
_stream = stream;
|
||||
if (!solid)
|
||||
{
|
||||
_streamPos = 0;
|
||||
_pos = 0;
|
||||
TrainSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
long len = stream.Length;
|
||||
uint size = (len < _windowSize) ? (uint)len : _windowSize;
|
||||
TrainSize = size;
|
||||
stream.Position = len - size;
|
||||
_streamPos = _pos = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
uint curSize = _windowSize - _pos;
|
||||
if (size < curSize)
|
||||
{
|
||||
curSize = size;
|
||||
}
|
||||
|
||||
int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size -= (uint)numReadBytes;
|
||||
_pos += (uint)numReadBytes;
|
||||
_streamPos += (uint)numReadBytes;
|
||||
if (_pos == _windowSize)
|
||||
{
|
||||
_streamPos = _pos = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Flush();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
uint size = _pos - _streamPos;
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_stream.Write(_buffer, (int)_streamPos, (int)size);
|
||||
if (_pos >= _windowSize)
|
||||
{
|
||||
_pos = 0;
|
||||
}
|
||||
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void CopyBlock(uint distance, uint len)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
{
|
||||
pos += _windowSize;
|
||||
}
|
||||
|
||||
for (; len > 0; len--)
|
||||
{
|
||||
if (pos >= _windowSize)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
_buffer[_pos++] = _buffer[pos++];
|
||||
if (_pos >= _windowSize)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PutByte(byte b)
|
||||
{
|
||||
_buffer[_pos++] = b;
|
||||
if (_pos >= _windowSize)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public byte GetByte(uint distance)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
{
|
||||
pos += _windowSize;
|
||||
}
|
||||
|
||||
return _buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
// LzOutWindow.cs
|
||||
|
||||
namespace SevenZip.Compression.LZ
|
||||
{
|
||||
public class OutWindow
|
||||
{
|
||||
private byte[] _buffer = null;
|
||||
private uint _pos;
|
||||
private uint _windowSize = 0;
|
||||
private uint _streamPos;
|
||||
private System.IO.Stream _stream;
|
||||
|
||||
public uint TrainSize = 0;
|
||||
|
||||
public void Create(uint windowSize)
|
||||
{
|
||||
if (_windowSize != windowSize)
|
||||
{
|
||||
// System.GC.Collect();
|
||||
_buffer = new byte[windowSize];
|
||||
}
|
||||
_windowSize = windowSize;
|
||||
_pos = 0;
|
||||
_streamPos = 0;
|
||||
}
|
||||
|
||||
public void Init(System.IO.Stream stream, bool solid)
|
||||
{
|
||||
ReleaseStream();
|
||||
_stream = stream;
|
||||
if (!solid)
|
||||
{
|
||||
_streamPos = 0;
|
||||
_pos = 0;
|
||||
TrainSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
long len = stream.Length;
|
||||
uint size = (len < _windowSize) ? (uint)len : _windowSize;
|
||||
TrainSize = size;
|
||||
stream.Position = len - size;
|
||||
_streamPos = _pos = 0;
|
||||
while (size > 0)
|
||||
{
|
||||
uint curSize = _windowSize - _pos;
|
||||
if (size < curSize)
|
||||
{
|
||||
curSize = size;
|
||||
}
|
||||
|
||||
int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
|
||||
if (numReadBytes == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size -= (uint)numReadBytes;
|
||||
_pos += (uint)numReadBytes;
|
||||
_streamPos += (uint)numReadBytes;
|
||||
if (_pos == _windowSize)
|
||||
{
|
||||
_streamPos = _pos = 0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Flush();
|
||||
_stream = null;
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
uint size = _pos - _streamPos;
|
||||
if (size == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_stream.Write(_buffer, (int)_streamPos, (int)size);
|
||||
if (_pos >= _windowSize)
|
||||
{
|
||||
_pos = 0;
|
||||
}
|
||||
|
||||
_streamPos = _pos;
|
||||
}
|
||||
|
||||
public void CopyBlock(uint distance, uint len)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
{
|
||||
pos += _windowSize;
|
||||
}
|
||||
|
||||
for (; len > 0; len--)
|
||||
{
|
||||
if (pos >= _windowSize)
|
||||
{
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
_buffer[_pos++] = _buffer[pos++];
|
||||
if (_pos >= _windowSize)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PutByte(byte b)
|
||||
{
|
||||
_buffer[_pos++] = b;
|
||||
if (_pos >= _windowSize)
|
||||
{
|
||||
Flush();
|
||||
}
|
||||
}
|
||||
|
||||
public byte GetByte(uint distance)
|
||||
{
|
||||
uint pos = _pos - distance - 1;
|
||||
if (pos >= _windowSize)
|
||||
{
|
||||
pos += _windowSize;
|
||||
}
|
||||
|
||||
return _buffer[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +1,88 @@
|
||||
// LzmaBase.cs
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
public const uint kNumRepDistances = 4;
|
||||
public const uint kNumStates = 12;
|
||||
|
||||
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
|
||||
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
|
||||
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
|
||||
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
|
||||
|
||||
public struct State
|
||||
{
|
||||
public uint Index;
|
||||
public void Init() { Index = 0; }
|
||||
public void UpdateChar()
|
||||
{
|
||||
if (Index < 4)
|
||||
{
|
||||
Index = 0;
|
||||
}
|
||||
else if (Index < 10)
|
||||
{
|
||||
Index -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index -= 6;
|
||||
}
|
||||
}
|
||||
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
|
||||
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
|
||||
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
|
||||
public bool IsCharState() { return Index < 7; }
|
||||
}
|
||||
|
||||
public const int kNumPosSlotBits = 6;
|
||||
public const int kDicLogSizeMin = 0;
|
||||
// public const int kDicLogSizeMax = 30;
|
||||
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
|
||||
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
|
||||
|
||||
public const uint kMatchMinLen = 2;
|
||||
|
||||
public static uint GetLenToPosState(uint len)
|
||||
{
|
||||
len -= kMatchMinLen;
|
||||
if (len < kNumLenToPosStates)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
return kNumLenToPosStates - 1;
|
||||
}
|
||||
|
||||
public const int kNumAlignBits = 4;
|
||||
public const uint kAlignTableSize = 1 << kNumAlignBits;
|
||||
public const uint kAlignMask = kAlignTableSize - 1;
|
||||
|
||||
public const uint kStartPosModelIndex = 4;
|
||||
public const uint kEndPosModelIndex = 14;
|
||||
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
|
||||
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
|
||||
|
||||
public const uint kNumLitPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumLitContextBitsMax = 8;
|
||||
|
||||
public const int kNumPosStatesBitsMax = 4;
|
||||
public const uint kNumPosStatesMax = 1 << kNumPosStatesBitsMax;
|
||||
public const int kNumPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumPosStatesEncodingMax = 1 << kNumPosStatesBitsEncodingMax;
|
||||
|
||||
public const int kNumLowLenBits = 3;
|
||||
public const int kNumMidLenBits = 3;
|
||||
public const int kNumHighLenBits = 8;
|
||||
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
|
||||
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
|
||||
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
|
||||
(1 << kNumHighLenBits);
|
||||
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
|
||||
}
|
||||
}
|
||||
// LzmaBase.cs
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
internal abstract class Base
|
||||
{
|
||||
public const uint kNumRepDistances = 4;
|
||||
public const uint kNumStates = 12;
|
||||
|
||||
// static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
|
||||
// static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
|
||||
// static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
|
||||
// static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
|
||||
|
||||
public struct State
|
||||
{
|
||||
public uint Index;
|
||||
public void Init() { Index = 0; }
|
||||
public void UpdateChar()
|
||||
{
|
||||
if (Index < 4)
|
||||
{
|
||||
Index = 0;
|
||||
}
|
||||
else if (Index < 10)
|
||||
{
|
||||
Index -= 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index -= 6;
|
||||
}
|
||||
}
|
||||
public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
|
||||
public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
|
||||
public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
|
||||
public bool IsCharState() { return Index < 7; }
|
||||
}
|
||||
|
||||
public const int kNumPosSlotBits = 6;
|
||||
public const int kDicLogSizeMin = 0;
|
||||
// public const int kDicLogSizeMax = 30;
|
||||
// public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
|
||||
|
||||
public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
|
||||
public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
|
||||
|
||||
public const uint kMatchMinLen = 2;
|
||||
|
||||
public static uint GetLenToPosState(uint len)
|
||||
{
|
||||
len -= kMatchMinLen;
|
||||
if (len < kNumLenToPosStates)
|
||||
{
|
||||
return len;
|
||||
}
|
||||
|
||||
return kNumLenToPosStates - 1;
|
||||
}
|
||||
|
||||
public const int kNumAlignBits = 4;
|
||||
public const uint kAlignTableSize = 1 << kNumAlignBits;
|
||||
public const uint kAlignMask = kAlignTableSize - 1;
|
||||
|
||||
public const uint kStartPosModelIndex = 4;
|
||||
public const uint kEndPosModelIndex = 14;
|
||||
public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
|
||||
|
||||
public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
|
||||
|
||||
public const uint kNumLitPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumLitContextBitsMax = 8;
|
||||
|
||||
public const int kNumPosStatesBitsMax = 4;
|
||||
public const uint kNumPosStatesMax = 1 << kNumPosStatesBitsMax;
|
||||
public const int kNumPosStatesBitsEncodingMax = 4;
|
||||
public const uint kNumPosStatesEncodingMax = 1 << kNumPosStatesBitsEncodingMax;
|
||||
|
||||
public const int kNumLowLenBits = 3;
|
||||
public const int kNumMidLenBits = 3;
|
||||
public const int kNumHighLenBits = 8;
|
||||
public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
|
||||
public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
|
||||
public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
|
||||
(1 << kNumHighLenBits);
|
||||
public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
|
||||
}
|
||||
}
|
||||
@@ -1,465 +1,465 @@
|
||||
// LzmaDecoder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
using RangeCoder;
|
||||
using System.Threading;
|
||||
|
||||
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
||||
{
|
||||
private class LenDecoder
|
||||
{
|
||||
private BitDecoder m_Choice = new();
|
||||
private BitDecoder m_Choice2 = new();
|
||||
private readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
private readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
private readonly BitTreeDecoder m_HighCoder = new(Base.kNumHighLenBits);
|
||||
private uint m_NumPosStates = 0;
|
||||
|
||||
public void Create(uint numPosStates)
|
||||
{
|
||||
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
|
||||
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
|
||||
}
|
||||
m_NumPosStates = numPosStates;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (uint posState = 0; posState < m_NumPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState].Init();
|
||||
m_MidCoder[posState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
|
||||
{
|
||||
if (m_Choice.Decode(rangeDecoder) == 0)
|
||||
{
|
||||
return m_LowCoder[posState].Decode(rangeDecoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint symbol = Base.kNumLowLenSymbols;
|
||||
if (m_Choice2.Decode(rangeDecoder) == 0)
|
||||
{
|
||||
symbol += m_MidCoder[posState].Decode(rangeDecoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol += Base.kNumMidLenSymbols;
|
||||
symbol += m_HighCoder.Decode(rangeDecoder);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LiteralDecoder
|
||||
{
|
||||
private struct Decoder2
|
||||
{
|
||||
private BitDecoder[] m_Decoders;
|
||||
public void Create() { m_Decoders = new BitDecoder[0x300]; }
|
||||
public void Init() { for (int i = 0; i < 0x300; i++)
|
||||
{
|
||||
m_Decoders[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
uint matchBit = (uint)(matchByte >> 7) & 1;
|
||||
matchByte <<= 1;
|
||||
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
|
||||
symbol = (symbol << 1) | bit;
|
||||
if (matchBit != bit)
|
||||
{
|
||||
while (symbol < 0x100)
|
||||
{
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
}
|
||||
|
||||
private Decoder2[] m_Coders;
|
||||
private int m_NumPrevBits;
|
||||
private int m_NumPosBits;
|
||||
private uint m_PosMask;
|
||||
|
||||
public void Create(int numPosBits, int numPrevBits)
|
||||
{
|
||||
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
|
||||
m_NumPosBits == numPosBits)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_NumPosBits = numPosBits;
|
||||
m_PosMask = ((uint)1 << numPosBits) - 1;
|
||||
m_NumPrevBits = numPrevBits;
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new Decoder2[numStates];
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
{
|
||||
m_Coders[i].Create();
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
{
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
private uint GetState(uint pos, byte prevByte)
|
||||
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
|
||||
};
|
||||
|
||||
private readonly LZ.OutWindow m_OutWindow = new();
|
||||
private readonly RangeCoder.Decoder m_RangeDecoder = new();
|
||||
|
||||
private readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
private readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
private readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
|
||||
private readonly BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
|
||||
|
||||
private readonly BitTreeDecoder m_PosAlignDecoder = new(Base.kNumAlignBits);
|
||||
|
||||
private readonly LenDecoder m_LenDecoder = new();
|
||||
private readonly LenDecoder m_RepLenDecoder = new();
|
||||
|
||||
private readonly LiteralDecoder m_LiteralDecoder = new();
|
||||
|
||||
private uint m_DictionarySize;
|
||||
private uint m_DictionarySizeCheck;
|
||||
|
||||
private uint m_PosStateMask;
|
||||
|
||||
public Decoder()
|
||||
{
|
||||
m_DictionarySize = 0xFFFFFFFF;
|
||||
for (int i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
{
|
||||
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDictionarySize(uint dictionarySize)
|
||||
{
|
||||
if (m_DictionarySize != dictionarySize)
|
||||
{
|
||||
m_DictionarySize = dictionarySize;
|
||||
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
|
||||
uint blockSize = Math.Max(m_DictionarySizeCheck, 1 << 12);
|
||||
m_OutWindow.Create(blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLiteralProperties(int lp, int lc)
|
||||
{
|
||||
if (lp > 8)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
if (lc > 8)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Create(lp, lc);
|
||||
}
|
||||
|
||||
private void SetPosBitsProperties(int pb)
|
||||
{
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
uint numPosStates = (uint)1 << pb;
|
||||
m_LenDecoder.Create(numPosStates);
|
||||
m_RepLenDecoder.Create(numPosStates);
|
||||
m_PosStateMask = numPosStates - 1;
|
||||
}
|
||||
|
||||
private bool _solid = false;
|
||||
private void Init(System.IO.Stream inStream, System.IO.Stream outStream)
|
||||
{
|
||||
m_RangeDecoder.Init(inStream);
|
||||
m_OutWindow.Init(outStream, _solid);
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < Base.kNumStates; i++)
|
||||
{
|
||||
for (uint j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
uint index = (i << Base.kNumPosStatesBitsMax) + j;
|
||||
m_IsMatchDecoders[index].Init();
|
||||
m_IsRep0LongDecoders[index].Init();
|
||||
}
|
||||
m_IsRepDecoders[i].Init();
|
||||
m_IsRepG0Decoders[i].Init();
|
||||
m_IsRepG1Decoders[i].Init();
|
||||
m_IsRepG2Decoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
for (i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
{
|
||||
m_PosSlotDecoder[i].Init();
|
||||
}
|
||||
// m_PosSpecDecoder.Init();
|
||||
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
|
||||
{
|
||||
m_PosDecoders[i].Init();
|
||||
}
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepLenDecoder.Init();
|
||||
m_PosAlignDecoder.Init();
|
||||
}
|
||||
|
||||
public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null)
|
||||
{
|
||||
Init(inStream, outStream);
|
||||
|
||||
Base.State state = new();
|
||||
state.Init();
|
||||
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
|
||||
|
||||
UInt64 nowPos64 = 0;
|
||||
UInt64 outSize64 = (UInt64)outSize;
|
||||
if (nowPos64 < outSize64)
|
||||
{
|
||||
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
|
||||
{
|
||||
throw new DataErrorException();
|
||||
}
|
||||
|
||||
state.UpdateChar();
|
||||
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
|
||||
m_OutWindow.PutByte(b);
|
||||
nowPos64++;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while (nowPos64 < outSize64)
|
||||
{
|
||||
token?.ThrowIfCancellationRequested();
|
||||
|
||||
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
|
||||
// while(nowPos64 < next)
|
||||
{
|
||||
uint posState = (uint)nowPos64 & m_PosStateMask;
|
||||
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
byte b;
|
||||
byte prevByte = m_OutWindow.GetByte(0);
|
||||
b = !state.IsCharState()
|
||||
? m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
|
||||
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0))
|
||||
: m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
|
||||
|
||||
m_OutWindow.PutByte(b);
|
||||
state.UpdateChar();
|
||||
nowPos64++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint len;
|
||||
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
|
||||
{
|
||||
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
state.UpdateShortRep();
|
||||
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
|
||||
nowPos64++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep2;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
|
||||
state.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
|
||||
state.UpdateMatch();
|
||||
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
|
||||
if (posSlot >= Base.kStartPosModelIndex)
|
||||
{
|
||||
int numDirectBits = (int)((posSlot >> 1) - 1);
|
||||
rep0 = (2 | (posSlot & 1)) << numDirectBits;
|
||||
if (posSlot < Base.kEndPosModelIndex)
|
||||
{
|
||||
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
|
||||
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep0 += m_RangeDecoder.DecodeDirectBits(
|
||||
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits;
|
||||
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rep0 = posSlot;
|
||||
}
|
||||
}
|
||||
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
|
||||
{
|
||||
if (rep0 == 0xFFFFFFFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
throw new DataErrorException();
|
||||
}
|
||||
m_OutWindow.CopyBlock(rep0, len);
|
||||
nowPos64 += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
|
||||
m_OutWindow.Flush();
|
||||
m_OutWindow.ReleaseStream();
|
||||
m_RangeDecoder.ReleaseStream();
|
||||
}
|
||||
|
||||
public void SetDecoderProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length < 5)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
int lc = properties[0] % 9;
|
||||
int remainder = properties[0] / 9;
|
||||
int lp = remainder % 5;
|
||||
int pb = remainder / 5;
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
UInt32 dictionarySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
dictionarySize += ((UInt32)properties[1 + i]) << (i * 8);
|
||||
}
|
||||
|
||||
SetDictionarySize(dictionarySize);
|
||||
SetLiteralProperties(lp, lc);
|
||||
SetPosBitsProperties(pb);
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
_solid = true;
|
||||
return m_OutWindow.Train(stream);
|
||||
}
|
||||
|
||||
/*
|
||||
public override bool CanRead { get { return true; }}
|
||||
public override bool CanWrite { get { return true; }}
|
||||
public override bool CanSeek { get { return true; }}
|
||||
public override long Length { get { return 0; }}
|
||||
public override long Position
|
||||
{
|
||||
get { return 0; }
|
||||
set { }
|
||||
}
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void SetLength(long value) {}
|
||||
*/
|
||||
}
|
||||
}
|
||||
// LzmaDecoder.cs
|
||||
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.LZMA
|
||||
{
|
||||
using RangeCoder;
|
||||
using System.Threading;
|
||||
|
||||
public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
|
||||
{
|
||||
private class LenDecoder
|
||||
{
|
||||
private BitDecoder m_Choice = new();
|
||||
private BitDecoder m_Choice2 = new();
|
||||
private readonly BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
private readonly BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
|
||||
private readonly BitTreeDecoder m_HighCoder = new(Base.kNumHighLenBits);
|
||||
private uint m_NumPosStates = 0;
|
||||
|
||||
public void Create(uint numPosStates)
|
||||
{
|
||||
for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
|
||||
m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
|
||||
}
|
||||
m_NumPosStates = numPosStates;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
m_Choice.Init();
|
||||
for (uint posState = 0; posState < m_NumPosStates; posState++)
|
||||
{
|
||||
m_LowCoder[posState].Init();
|
||||
m_MidCoder[posState].Init();
|
||||
}
|
||||
m_Choice2.Init();
|
||||
m_HighCoder.Init();
|
||||
}
|
||||
|
||||
public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
|
||||
{
|
||||
if (m_Choice.Decode(rangeDecoder) == 0)
|
||||
{
|
||||
return m_LowCoder[posState].Decode(rangeDecoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint symbol = Base.kNumLowLenSymbols;
|
||||
if (m_Choice2.Decode(rangeDecoder) == 0)
|
||||
{
|
||||
symbol += m_MidCoder[posState].Decode(rangeDecoder);
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol += Base.kNumMidLenSymbols;
|
||||
symbol += m_HighCoder.Decode(rangeDecoder);
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class LiteralDecoder
|
||||
{
|
||||
private struct Decoder2
|
||||
{
|
||||
private BitDecoder[] m_Decoders;
|
||||
public void Create() { m_Decoders = new BitDecoder[0x300]; }
|
||||
public void Init() { for (int i = 0; i < 0x300; i++)
|
||||
{
|
||||
m_Decoders[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
|
||||
{
|
||||
uint symbol = 1;
|
||||
do
|
||||
{
|
||||
uint matchBit = (uint)(matchByte >> 7) & 1;
|
||||
matchByte <<= 1;
|
||||
uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
|
||||
symbol = (symbol << 1) | bit;
|
||||
if (matchBit != bit)
|
||||
{
|
||||
while (symbol < 0x100)
|
||||
{
|
||||
symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (symbol < 0x100);
|
||||
return (byte)symbol;
|
||||
}
|
||||
}
|
||||
|
||||
private Decoder2[] m_Coders;
|
||||
private int m_NumPrevBits;
|
||||
private int m_NumPosBits;
|
||||
private uint m_PosMask;
|
||||
|
||||
public void Create(int numPosBits, int numPrevBits)
|
||||
{
|
||||
if (m_Coders != null && m_NumPrevBits == numPrevBits &&
|
||||
m_NumPosBits == numPosBits)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_NumPosBits = numPosBits;
|
||||
m_PosMask = ((uint)1 << numPosBits) - 1;
|
||||
m_NumPrevBits = numPrevBits;
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
m_Coders = new Decoder2[numStates];
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
{
|
||||
m_Coders[i].Create();
|
||||
}
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
|
||||
for (uint i = 0; i < numStates; i++)
|
||||
{
|
||||
m_Coders[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
private uint GetState(uint pos, byte prevByte)
|
||||
{ return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
|
||||
|
||||
public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
|
||||
|
||||
public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
|
||||
{ return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
|
||||
};
|
||||
|
||||
private readonly LZ.OutWindow m_OutWindow = new();
|
||||
private readonly RangeCoder.Decoder m_RangeDecoder = new();
|
||||
|
||||
private readonly BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
private readonly BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
|
||||
private readonly BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
|
||||
|
||||
private readonly BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
|
||||
private readonly BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
|
||||
|
||||
private readonly BitTreeDecoder m_PosAlignDecoder = new(Base.kNumAlignBits);
|
||||
|
||||
private readonly LenDecoder m_LenDecoder = new();
|
||||
private readonly LenDecoder m_RepLenDecoder = new();
|
||||
|
||||
private readonly LiteralDecoder m_LiteralDecoder = new();
|
||||
|
||||
private uint m_DictionarySize;
|
||||
private uint m_DictionarySizeCheck;
|
||||
|
||||
private uint m_PosStateMask;
|
||||
|
||||
public Decoder()
|
||||
{
|
||||
m_DictionarySize = 0xFFFFFFFF;
|
||||
for (int i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
{
|
||||
m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetDictionarySize(uint dictionarySize)
|
||||
{
|
||||
if (m_DictionarySize != dictionarySize)
|
||||
{
|
||||
m_DictionarySize = dictionarySize;
|
||||
m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
|
||||
uint blockSize = Math.Max(m_DictionarySizeCheck, 1 << 12);
|
||||
m_OutWindow.Create(blockSize);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetLiteralProperties(int lp, int lc)
|
||||
{
|
||||
if (lp > 8)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
if (lc > 8)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Create(lp, lc);
|
||||
}
|
||||
|
||||
private void SetPosBitsProperties(int pb)
|
||||
{
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
uint numPosStates = (uint)1 << pb;
|
||||
m_LenDecoder.Create(numPosStates);
|
||||
m_RepLenDecoder.Create(numPosStates);
|
||||
m_PosStateMask = numPosStates - 1;
|
||||
}
|
||||
|
||||
private bool _solid = false;
|
||||
private void Init(System.IO.Stream inStream, System.IO.Stream outStream)
|
||||
{
|
||||
m_RangeDecoder.Init(inStream);
|
||||
m_OutWindow.Init(outStream, _solid);
|
||||
|
||||
uint i;
|
||||
for (i = 0; i < Base.kNumStates; i++)
|
||||
{
|
||||
for (uint j = 0; j <= m_PosStateMask; j++)
|
||||
{
|
||||
uint index = (i << Base.kNumPosStatesBitsMax) + j;
|
||||
m_IsMatchDecoders[index].Init();
|
||||
m_IsRep0LongDecoders[index].Init();
|
||||
}
|
||||
m_IsRepDecoders[i].Init();
|
||||
m_IsRepG0Decoders[i].Init();
|
||||
m_IsRepG1Decoders[i].Init();
|
||||
m_IsRepG2Decoders[i].Init();
|
||||
}
|
||||
|
||||
m_LiteralDecoder.Init();
|
||||
for (i = 0; i < Base.kNumLenToPosStates; i++)
|
||||
{
|
||||
m_PosSlotDecoder[i].Init();
|
||||
}
|
||||
// m_PosSpecDecoder.Init();
|
||||
for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
|
||||
{
|
||||
m_PosDecoders[i].Init();
|
||||
}
|
||||
|
||||
m_LenDecoder.Init();
|
||||
m_RepLenDecoder.Init();
|
||||
m_PosAlignDecoder.Init();
|
||||
}
|
||||
|
||||
public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null)
|
||||
{
|
||||
Init(inStream, outStream);
|
||||
|
||||
Base.State state = new();
|
||||
state.Init();
|
||||
uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
|
||||
|
||||
UInt64 nowPos64 = 0;
|
||||
UInt64 outSize64 = (UInt64)outSize;
|
||||
if (nowPos64 < outSize64)
|
||||
{
|
||||
if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
|
||||
{
|
||||
throw new DataErrorException();
|
||||
}
|
||||
|
||||
state.UpdateChar();
|
||||
byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
|
||||
m_OutWindow.PutByte(b);
|
||||
nowPos64++;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
while (nowPos64 < outSize64)
|
||||
{
|
||||
token?.ThrowIfCancellationRequested();
|
||||
|
||||
// UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
|
||||
// while(nowPos64 < next)
|
||||
{
|
||||
uint posState = (uint)nowPos64 & m_PosStateMask;
|
||||
if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
byte b;
|
||||
byte prevByte = m_OutWindow.GetByte(0);
|
||||
b = !state.IsCharState()
|
||||
? m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
|
||||
(uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0))
|
||||
: m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
|
||||
|
||||
m_OutWindow.PutByte(b);
|
||||
state.UpdateChar();
|
||||
nowPos64++;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint len;
|
||||
if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
|
||||
{
|
||||
if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
state.UpdateShortRep();
|
||||
m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
|
||||
nowPos64++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt32 distance;
|
||||
if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
|
||||
{
|
||||
distance = rep2;
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = rep3;
|
||||
rep3 = rep2;
|
||||
}
|
||||
rep2 = rep1;
|
||||
}
|
||||
rep1 = rep0;
|
||||
rep0 = distance;
|
||||
}
|
||||
len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
|
||||
state.UpdateRep();
|
||||
}
|
||||
else
|
||||
{
|
||||
rep3 = rep2;
|
||||
rep2 = rep1;
|
||||
rep1 = rep0;
|
||||
len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
|
||||
state.UpdateMatch();
|
||||
uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
|
||||
if (posSlot >= Base.kStartPosModelIndex)
|
||||
{
|
||||
int numDirectBits = (int)((posSlot >> 1) - 1);
|
||||
rep0 = (2 | (posSlot & 1)) << numDirectBits;
|
||||
if (posSlot < Base.kEndPosModelIndex)
|
||||
{
|
||||
rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
|
||||
rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
|
||||
}
|
||||
else
|
||||
{
|
||||
rep0 += m_RangeDecoder.DecodeDirectBits(
|
||||
numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits;
|
||||
rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rep0 = posSlot;
|
||||
}
|
||||
}
|
||||
if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
|
||||
{
|
||||
if (rep0 == 0xFFFFFFFF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
throw new DataErrorException();
|
||||
}
|
||||
m_OutWindow.CopyBlock(rep0, len);
|
||||
nowPos64 += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
|
||||
m_OutWindow.Flush();
|
||||
m_OutWindow.ReleaseStream();
|
||||
m_RangeDecoder.ReleaseStream();
|
||||
}
|
||||
|
||||
public void SetDecoderProperties(byte[] properties)
|
||||
{
|
||||
if (properties.Length < 5)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
int lc = properties[0] % 9;
|
||||
int remainder = properties[0] / 9;
|
||||
int lp = remainder % 5;
|
||||
int pb = remainder / 5;
|
||||
if (pb > Base.kNumPosStatesBitsMax)
|
||||
{
|
||||
throw new InvalidParamException();
|
||||
}
|
||||
|
||||
UInt32 dictionarySize = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
dictionarySize += ((UInt32)properties[1 + i]) << (i * 8);
|
||||
}
|
||||
|
||||
SetDictionarySize(dictionarySize);
|
||||
SetLiteralProperties(lp, lc);
|
||||
SetPosBitsProperties(pb);
|
||||
}
|
||||
|
||||
public bool Train(System.IO.Stream stream)
|
||||
{
|
||||
_solid = true;
|
||||
return m_OutWindow.Train(stream);
|
||||
}
|
||||
|
||||
/*
|
||||
public override bool CanRead { get { return true; }}
|
||||
public override bool CanWrite { get { return true; }}
|
||||
public override bool CanSeek { get { return true; }}
|
||||
public override long Length { get { return 0; }}
|
||||
public override long Position
|
||||
{
|
||||
get { return 0; }
|
||||
set { }
|
||||
}
|
||||
public override void Flush() { }
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
}
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
public override void SetLength(long value) {}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -1,243 +1,243 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
internal class Encoder
|
||||
{
|
||||
public const uint kTopValue = 1 << 24;
|
||||
|
||||
private System.IO.Stream Stream;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
private uint _cacheSize;
|
||||
private byte _cache;
|
||||
|
||||
private long StartPosition;
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint)Low < 0xFF000000 || (uint)(Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte)(temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
}
|
||||
while (--_cacheSize != 0);
|
||||
_cache = (byte)(((uint)Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint)Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
{
|
||||
Low += Range;
|
||||
}
|
||||
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
{
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return _cacheSize +
|
||||
Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Decoder
|
||||
{
|
||||
public const uint kTopValue = 1 << 24;
|
||||
public uint Range;
|
||||
public uint Code;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public System.IO.Stream Stream;
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}
|
||||
|
||||
public void Decode(uint start, uint size, uint total)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte)Stream.ReadByte();
|
||||
range <<= 8;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
internal class Encoder
|
||||
{
|
||||
public const uint kTopValue = 1 << 24;
|
||||
|
||||
private System.IO.Stream Stream;
|
||||
|
||||
public UInt64 Low;
|
||||
public uint Range;
|
||||
private uint _cacheSize;
|
||||
private byte _cache;
|
||||
|
||||
private long StartPosition;
|
||||
|
||||
public void SetStream(System.IO.Stream stream)
|
||||
{
|
||||
Stream = stream;
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
StartPosition = Stream.Position;
|
||||
|
||||
Low = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
_cacheSize = 1;
|
||||
_cache = 0;
|
||||
}
|
||||
|
||||
public void FlushData()
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void FlushStream()
|
||||
{
|
||||
Stream.Flush();
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Encode(uint start, uint size, uint total)
|
||||
{
|
||||
Low += start * (Range /= total);
|
||||
Range *= size;
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public void ShiftLow()
|
||||
{
|
||||
if ((uint)Low < 0xFF000000 || (uint)(Low >> 32) == 1)
|
||||
{
|
||||
byte temp = _cache;
|
||||
do
|
||||
{
|
||||
Stream.WriteByte((byte)(temp + (Low >> 32)));
|
||||
temp = 0xFF;
|
||||
}
|
||||
while (--_cacheSize != 0);
|
||||
_cache = (byte)(((uint)Low) >> 24);
|
||||
}
|
||||
_cacheSize++;
|
||||
Low = ((uint)Low) << 8;
|
||||
}
|
||||
|
||||
public void EncodeDirectBits(uint v, int numTotalBits)
|
||||
{
|
||||
for (int i = numTotalBits - 1; i >= 0; i--)
|
||||
{
|
||||
Range >>= 1;
|
||||
if (((v >> i) & 1) == 1)
|
||||
{
|
||||
Low += Range;
|
||||
}
|
||||
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void EncodeBit(uint size0, int numTotalBits, uint symbol)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
if (symbol == 0)
|
||||
{
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
Low += newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Range <<= 8;
|
||||
ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
public long GetProcessedSizeAdd()
|
||||
{
|
||||
return _cacheSize +
|
||||
Stream.Position - StartPosition + 4;
|
||||
// (long)Stream.GetProcessedSize();
|
||||
}
|
||||
}
|
||||
|
||||
internal class Decoder
|
||||
{
|
||||
public const uint kTopValue = 1 << 24;
|
||||
public uint Range;
|
||||
public uint Code;
|
||||
// public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
|
||||
public System.IO.Stream Stream;
|
||||
|
||||
public void Init(System.IO.Stream stream)
|
||||
{
|
||||
// Stream.Init(stream);
|
||||
Stream = stream;
|
||||
|
||||
Code = 0;
|
||||
Range = 0xFFFFFFFF;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseStream()
|
||||
{
|
||||
// Stream.ReleaseStream();
|
||||
Stream = null;
|
||||
}
|
||||
|
||||
public void CloseStream()
|
||||
{
|
||||
Stream.Close();
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
while (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public void Normalize2()
|
||||
{
|
||||
if (Range < kTopValue)
|
||||
{
|
||||
Code = (Code << 8) | (byte)Stream.ReadByte();
|
||||
Range <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetThreshold(uint total)
|
||||
{
|
||||
return Code / (Range /= total);
|
||||
}
|
||||
|
||||
public void Decode(uint start, uint size, uint total)
|
||||
{
|
||||
Code -= start * Range;
|
||||
Range *= size;
|
||||
Normalize();
|
||||
}
|
||||
|
||||
public uint DecodeDirectBits(int numTotalBits)
|
||||
{
|
||||
uint range = Range;
|
||||
uint code = Code;
|
||||
uint result = 0;
|
||||
for (int i = numTotalBits; i > 0; i--)
|
||||
{
|
||||
range >>= 1;
|
||||
/*
|
||||
result <<= 1;
|
||||
if (code >= range)
|
||||
{
|
||||
code -= range;
|
||||
result |= 1;
|
||||
}
|
||||
*/
|
||||
uint t = (code - range) >> 31;
|
||||
code -= range & (t - 1);
|
||||
result = (result << 1) | (1 - t);
|
||||
|
||||
if (range < kTopValue)
|
||||
{
|
||||
code = (code << 8) | (byte)Stream.ReadByte();
|
||||
range <<= 8;
|
||||
}
|
||||
}
|
||||
Range = range;
|
||||
Code = code;
|
||||
return result;
|
||||
}
|
||||
|
||||
public uint DecodeBit(uint size0, int numTotalBits)
|
||||
{
|
||||
uint newBound = (Range >> numTotalBits) * size0;
|
||||
uint symbol;
|
||||
if (Code < newBound)
|
||||
{
|
||||
symbol = 0;
|
||||
Range = newBound;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol = 1;
|
||||
Code -= newBound;
|
||||
Range -= newBound;
|
||||
}
|
||||
Normalize();
|
||||
return symbol;
|
||||
}
|
||||
|
||||
// ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
|
||||
}
|
||||
}
|
||||
@@ -1,127 +1,127 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitEncoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
|
||||
private const int kNumMoveBits = 5;
|
||||
private const int kNumMoveReducingBits = 2;
|
||||
public const int kNumBitPriceShiftBits = 6;
|
||||
|
||||
private uint Prob;
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public void UpdateModel(uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
{
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
Prob -= Prob >> kNumMoveBits;
|
||||
}
|
||||
}
|
||||
|
||||
public void Encode(Encoder encoder, uint symbol)
|
||||
{
|
||||
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
||||
// UpdateModel(symbol);
|
||||
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (symbol == 0)
|
||||
{
|
||||
encoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Low += newBound;
|
||||
encoder.Range -= newBound;
|
||||
Prob -= Prob >> kNumMoveBits;
|
||||
}
|
||||
if (encoder.Range < Encoder.kTopValue)
|
||||
{
|
||||
encoder.Range <<= 8;
|
||||
encoder.ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
|
||||
|
||||
static BitEncoder()
|
||||
{
|
||||
const int kNumBits = kNumBitModelTotalBits - kNumMoveReducingBits;
|
||||
for (int i = kNumBits - 1; i >= 0; i--)
|
||||
{
|
||||
UInt32 start = (UInt32)1 << (kNumBits - i - 1);
|
||||
UInt32 end = (UInt32)1 << (kNumBits - i);
|
||||
for (UInt32 j = start; j < end; j++)
|
||||
{
|
||||
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
|
||||
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetPrice(uint symbol)
|
||||
{
|
||||
return ProbPrices[(((Prob - symbol) ^ (-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
|
||||
}
|
||||
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
|
||||
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
|
||||
}
|
||||
|
||||
internal struct BitDecoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
|
||||
private const int kNumMoveBits = 5;
|
||||
|
||||
private uint Prob;
|
||||
|
||||
public void UpdateModel(int numMoveBits, uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
{
|
||||
Prob += (kBitModelTotal - Prob) >> numMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
Prob -= Prob >> numMoveBits;
|
||||
}
|
||||
}
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public uint Decode(Decoder rangeDecoder)
|
||||
{
|
||||
uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (rangeDecoder.Code < newBound)
|
||||
{
|
||||
rangeDecoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder.Range -= newBound;
|
||||
rangeDecoder.Code -= newBound;
|
||||
Prob -= Prob >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitEncoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
|
||||
private const int kNumMoveBits = 5;
|
||||
private const int kNumMoveReducingBits = 2;
|
||||
public const int kNumBitPriceShiftBits = 6;
|
||||
|
||||
private uint Prob;
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public void UpdateModel(uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
{
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
Prob -= Prob >> kNumMoveBits;
|
||||
}
|
||||
}
|
||||
|
||||
public void Encode(Encoder encoder, uint symbol)
|
||||
{
|
||||
// encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
|
||||
// UpdateModel(symbol);
|
||||
uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (symbol == 0)
|
||||
{
|
||||
encoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
encoder.Low += newBound;
|
||||
encoder.Range -= newBound;
|
||||
Prob -= Prob >> kNumMoveBits;
|
||||
}
|
||||
if (encoder.Range < Encoder.kTopValue)
|
||||
{
|
||||
encoder.Range <<= 8;
|
||||
encoder.ShiftLow();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
|
||||
|
||||
static BitEncoder()
|
||||
{
|
||||
const int kNumBits = kNumBitModelTotalBits - kNumMoveReducingBits;
|
||||
for (int i = kNumBits - 1; i >= 0; i--)
|
||||
{
|
||||
UInt32 start = (UInt32)1 << (kNumBits - i - 1);
|
||||
UInt32 end = (UInt32)1 << (kNumBits - i);
|
||||
for (UInt32 j = start; j < end; j++)
|
||||
{
|
||||
ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
|
||||
(((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetPrice(uint symbol)
|
||||
{
|
||||
return ProbPrices[(((Prob - symbol) ^ (-(int)symbol)) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
|
||||
}
|
||||
public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
|
||||
public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
|
||||
}
|
||||
|
||||
internal struct BitDecoder
|
||||
{
|
||||
public const int kNumBitModelTotalBits = 11;
|
||||
public const uint kBitModelTotal = 1 << kNumBitModelTotalBits;
|
||||
private const int kNumMoveBits = 5;
|
||||
|
||||
private uint Prob;
|
||||
|
||||
public void UpdateModel(int numMoveBits, uint symbol)
|
||||
{
|
||||
if (symbol == 0)
|
||||
{
|
||||
Prob += (kBitModelTotal - Prob) >> numMoveBits;
|
||||
}
|
||||
else
|
||||
{
|
||||
Prob -= Prob >> numMoveBits;
|
||||
}
|
||||
}
|
||||
|
||||
public void Init() { Prob = kBitModelTotal >> 1; }
|
||||
|
||||
public uint Decode(Decoder rangeDecoder)
|
||||
{
|
||||
uint newBound = (rangeDecoder.Range >> kNumBitModelTotalBits) * Prob;
|
||||
if (rangeDecoder.Code < newBound)
|
||||
{
|
||||
rangeDecoder.Range = newBound;
|
||||
Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
rangeDecoder.Range -= newBound;
|
||||
rangeDecoder.Code -= newBound;
|
||||
Prob -= Prob >> kNumMoveBits;
|
||||
if (rangeDecoder.Range < Decoder.kTopValue)
|
||||
{
|
||||
rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
|
||||
rangeDecoder.Range <<= 8;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +1,164 @@
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitTreeEncoder
|
||||
{
|
||||
private readonly BitEncoder[] Models;
|
||||
private readonly int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
{
|
||||
Models[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct BitTreeDecoder
|
||||
{
|
||||
private readonly BitDecoder[] Models;
|
||||
private readonly int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
{
|
||||
Models[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public uint Decode(Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
{
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
}
|
||||
|
||||
return m - ((uint)1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= bit << bitIndex;
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= bit << bitIndex;
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
|
||||
namespace SevenZip.Compression.RangeCoder
|
||||
{
|
||||
internal struct BitTreeEncoder
|
||||
{
|
||||
private readonly BitEncoder[] Models;
|
||||
private readonly int NumBitLevels;
|
||||
|
||||
public BitTreeEncoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitEncoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
{
|
||||
Models[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public void Encode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
}
|
||||
|
||||
public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (UInt32 i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
public UInt32 GetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0;)
|
||||
{
|
||||
bitIndex--;
|
||||
UInt32 bit = (symbol >> bitIndex) & 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) + bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public UInt32 ReverseGetPrice(UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
|
||||
int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 price = 0;
|
||||
UInt32 m = 1;
|
||||
for (int i = NumBitLevels; i > 0; i--)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
symbol >>= 1;
|
||||
price += Models[startIndex + m].GetPrice(bit);
|
||||
m = (m << 1) | bit;
|
||||
}
|
||||
return price;
|
||||
}
|
||||
|
||||
public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
|
||||
Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
|
||||
{
|
||||
UInt32 m = 1;
|
||||
for (int i = 0; i < NumBitLevels; i++)
|
||||
{
|
||||
UInt32 bit = symbol & 1;
|
||||
Models[startIndex + m].Encode(rangeEncoder, bit);
|
||||
m = (m << 1) | bit;
|
||||
symbol >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal struct BitTreeDecoder
|
||||
{
|
||||
private readonly BitDecoder[] Models;
|
||||
private readonly int NumBitLevels;
|
||||
|
||||
public BitTreeDecoder(int numBitLevels)
|
||||
{
|
||||
NumBitLevels = numBitLevels;
|
||||
Models = new BitDecoder[1 << numBitLevels];
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
for (uint i = 1; i < (1 << NumBitLevels); i++)
|
||||
{
|
||||
Models[i].Init();
|
||||
}
|
||||
}
|
||||
|
||||
public uint Decode(Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
|
||||
{
|
||||
m = (m << 1) + Models[m].Decode(rangeDecoder);
|
||||
}
|
||||
|
||||
return m - ((uint)1 << NumBitLevels);
|
||||
}
|
||||
|
||||
public uint ReverseDecode(Decoder rangeDecoder)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= bit << bitIndex;
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
|
||||
public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
|
||||
Decoder rangeDecoder, int NumBitLevels)
|
||||
{
|
||||
uint m = 1;
|
||||
uint symbol = 0;
|
||||
for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
|
||||
{
|
||||
uint bit = Models[startIndex + m].Decode(rangeDecoder);
|
||||
m <<= 1;
|
||||
m += bit;
|
||||
symbol |= bit << bitIndex;
|
||||
}
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,173 +1,173 @@
|
||||
// ICoder.h
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
internal class DataErrorException : ApplicationException
|
||||
{
|
||||
public DataErrorException() : base("Data Error") { }
|
||||
|
||||
public DataErrorException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public DataErrorException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
internal class InvalidParamException : ApplicationException
|
||||
{
|
||||
public InvalidParamException() : base("Invalid Parameter") { }
|
||||
|
||||
public InvalidParamException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidParamException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
};
|
||||
|
||||
public interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
/// <exception cref="DataErrorException">
|
||||
/// if input stream is not valid
|
||||
/// </exception>
|
||||
void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null);
|
||||
};
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
public enum CoderPropID
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 <= x <= 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker
|
||||
};
|
||||
|
||||
public interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
|
||||
};
|
||||
|
||||
public interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(System.IO.Stream outStream);
|
||||
}
|
||||
|
||||
public interface ISetDecoderProperties
|
||||
{
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
||||
// ICoder.h
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace SevenZip
|
||||
{
|
||||
/// <summary>
|
||||
/// The exception that is thrown when an error in input stream occurs during decoding.
|
||||
/// </summary>
|
||||
internal class DataErrorException : ApplicationException
|
||||
{
|
||||
public DataErrorException() : base("Data Error") { }
|
||||
|
||||
public DataErrorException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public DataErrorException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The exception that is thrown when the value of an argument is outside the allowable range.
|
||||
/// </summary>
|
||||
internal class InvalidParamException : ApplicationException
|
||||
{
|
||||
public InvalidParamException() : base("Invalid Parameter") { }
|
||||
|
||||
public InvalidParamException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public InvalidParamException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICodeProgress
|
||||
{
|
||||
/// <summary>
|
||||
/// Callback progress.
|
||||
/// </summary>
|
||||
/// <param name="inSize">
|
||||
/// input size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output size. -1 if unknown.
|
||||
/// </param>
|
||||
void SetProgress(Int64 inSize, Int64 outSize);
|
||||
};
|
||||
|
||||
public interface ICoder
|
||||
{
|
||||
/// <summary>
|
||||
/// Codes streams.
|
||||
/// </summary>
|
||||
/// <param name="inStream">
|
||||
/// input Stream.
|
||||
/// </param>
|
||||
/// <param name="outStream">
|
||||
/// output Stream.
|
||||
/// </param>
|
||||
/// <param name="inSize">
|
||||
/// input Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="outSize">
|
||||
/// output Size. -1 if unknown.
|
||||
/// </param>
|
||||
/// <param name="progress">
|
||||
/// callback progress reference.
|
||||
/// </param>
|
||||
/// <exception cref="DataErrorException">
|
||||
/// if input stream is not valid
|
||||
/// </exception>
|
||||
void Code(System.IO.Stream inStream, System.IO.Stream outStream,
|
||||
Int64 inSize, Int64 outSize, ICodeProgress progress, CancellationToken? token = null);
|
||||
};
|
||||
|
||||
/*
|
||||
public interface ICoder2
|
||||
{
|
||||
void Code(ISequentialInStream []inStreams,
|
||||
const UInt64 []inSizes,
|
||||
ISequentialOutStream []outStreams,
|
||||
UInt64 []outSizes,
|
||||
ICodeProgress progress);
|
||||
};
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// Provides the fields that represent properties idenitifiers for compressing.
|
||||
/// </summary>
|
||||
public enum CoderPropID
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies default property.
|
||||
/// </summary>
|
||||
DefaultProp = 0,
|
||||
/// <summary>
|
||||
/// Specifies size of dictionary.
|
||||
/// </summary>
|
||||
DictionarySize,
|
||||
/// <summary>
|
||||
/// Specifies size of memory for PPM*.
|
||||
/// </summary>
|
||||
UsedMemorySize,
|
||||
/// <summary>
|
||||
/// Specifies order for PPM methods.
|
||||
/// </summary>
|
||||
Order,
|
||||
/// <summary>
|
||||
/// Specifies Block Size.
|
||||
/// </summary>
|
||||
BlockSize,
|
||||
/// <summary>
|
||||
/// Specifies number of postion state bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
PosStateBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal context bits for LZMA (0 <= x <= 8).
|
||||
/// </summary>
|
||||
LitContextBits,
|
||||
/// <summary>
|
||||
/// Specifies number of literal position bits for LZMA (0 <= x <= 4).
|
||||
/// </summary>
|
||||
LitPosBits,
|
||||
/// <summary>
|
||||
/// Specifies number of fast bytes for LZ*.
|
||||
/// </summary>
|
||||
NumFastBytes,
|
||||
/// <summary>
|
||||
/// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
|
||||
/// </summary>
|
||||
MatchFinder,
|
||||
/// <summary>
|
||||
/// Specifies the number of match finder cyckes.
|
||||
/// </summary>
|
||||
MatchFinderCycles,
|
||||
/// <summary>
|
||||
/// Specifies number of passes.
|
||||
/// </summary>
|
||||
NumPasses,
|
||||
/// <summary>
|
||||
/// Specifies number of algorithm.
|
||||
/// </summary>
|
||||
Algorithm,
|
||||
/// <summary>
|
||||
/// Specifies the number of threads.
|
||||
/// </summary>
|
||||
NumThreads,
|
||||
/// <summary>
|
||||
/// Specifies mode with end marker.
|
||||
/// </summary>
|
||||
EndMarker
|
||||
};
|
||||
|
||||
public interface ISetCoderProperties
|
||||
{
|
||||
void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
|
||||
};
|
||||
|
||||
public interface IWriteCoderProperties
|
||||
{
|
||||
void WriteCoderProperties(System.IO.Stream outStream);
|
||||
}
|
||||
|
||||
public interface ISetDecoderProperties
|
||||
{
|
||||
void SetDecoderProperties(byte[] properties);
|
||||
}
|
||||
}
|
||||
@@ -1,112 +1,112 @@
|
||||
<!--
|
||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.
|
||||
-->
|
||||
|
||||
<Application x:Class="WPinternals.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="Views\StartupWindow.xaml"
|
||||
xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=PresentationFramework"
|
||||
>
|
||||
<Application.Resources>
|
||||
<Style TargetType="{x:Type UserControl}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="ComponentModel:DesignerProperties.IsInDesignMode"
|
||||
Value="true">
|
||||
<Setter Property="Background"
|
||||
Value="White" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<ControlTemplate x:Key="TopicExpanderTemplate" TargetType="{x:Type Expander}">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True">
|
||||
<DockPanel>
|
||||
<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ToggleButton.FocusVisualStyle>
|
||||
<Style>
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Border>
|
||||
<Rectangle Margin="0" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ToggleButton.FocusVisualStyle>
|
||||
<ToggleButton.Style>
|
||||
<Style TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||
<Border Padding="{TemplateBinding Padding}">
|
||||
<Grid Background="Transparent" SnapsToDevicePixels="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="19"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse x:Name="circle" Fill="White" HorizontalAlignment="Center" Height="19" Stroke="#FF333333" VerticalAlignment="Center" Width="19" Grid.Column="1" />
|
||||
<Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF333333" StrokeThickness="2" VerticalAlignment="Center" Grid.Column="1" />
|
||||
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="0,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center" TextBlock.FontSize="18" TextBlock.FontWeight="Bold" TextBlock.Foreground="#FF3753A6"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Stroke" TargetName="circle" Value="#FF5593FF"/>
|
||||
<Setter Property="Fill" TargetName="circle" Value="#FFF3F9FF"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Stroke" TargetName="circle" Value="#FF3C77DD"/>
|
||||
<Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
|
||||
<Setter Property="Fill" TargetName="circle" Value="#FFD9ECFF"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Stroke" TargetName="circle" Value="#FFBCBCBC"/>
|
||||
<Setter Property="Fill" TargetName="circle" Value="#FFE6E6E6"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ToggleButton.Style>
|
||||
</ToggleButton>
|
||||
<ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsExpanded" Value="True">
|
||||
<Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<Application x:Class="WPinternals.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="Views\StartupWindow.xaml"
|
||||
xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=PresentationFramework"
|
||||
>
|
||||
<Application.Resources>
|
||||
<Style TargetType="{x:Type UserControl}">
|
||||
<Style.Triggers>
|
||||
<Trigger Property="ComponentModel:DesignerProperties.IsInDesignMode"
|
||||
Value="true">
|
||||
<Setter Property="Background"
|
||||
Value="White" />
|
||||
</Trigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<ControlTemplate x:Key="TopicExpanderTemplate" TargetType="{x:Type Expander}">
|
||||
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="3" SnapsToDevicePixels="True">
|
||||
<DockPanel>
|
||||
<ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" DockPanel.Dock="Top" Foreground="{TemplateBinding Foreground}" FontWeight="{TemplateBinding FontWeight}" FontStyle="{TemplateBinding FontStyle}" FontStretch="{TemplateBinding FontStretch}" FontSize="{TemplateBinding FontSize}" FontFamily="{TemplateBinding FontFamily}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ToggleButton.FocusVisualStyle>
|
||||
<Style>
|
||||
<Setter Property="Control.Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate>
|
||||
<Border>
|
||||
<Rectangle Margin="0" SnapsToDevicePixels="True" Stroke="Black" StrokeThickness="1" StrokeDashArray="1 2"/>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ToggleButton.FocusVisualStyle>
|
||||
<ToggleButton.Style>
|
||||
<Style TargetType="{x:Type ToggleButton}">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="{x:Type ToggleButton}">
|
||||
<Border Padding="{TemplateBinding Padding}">
|
||||
<Grid Background="Transparent" SnapsToDevicePixels="False">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="19"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Ellipse x:Name="circle" Fill="White" HorizontalAlignment="Center" Height="19" Stroke="#FF333333" VerticalAlignment="Center" Width="19" Grid.Column="1" />
|
||||
<Path x:Name="arrow" Data="M1,1.5L4.5,5 8,1.5" HorizontalAlignment="Center" SnapsToDevicePixels="False" Stroke="#FF333333" StrokeThickness="2" VerticalAlignment="Center" Grid.Column="1" />
|
||||
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" ContentStringFormat="{TemplateBinding ContentStringFormat}" HorizontalAlignment="Left" Margin="0,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center" TextBlock.FontSize="18" TextBlock.FontWeight="Bold" TextBlock.Foreground="#FF3753A6"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsChecked" Value="True">
|
||||
<Setter Property="Data" TargetName="arrow" Value="M1,4.5L4.5,1 8,4.5"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter Property="Stroke" TargetName="circle" Value="#FF5593FF"/>
|
||||
<Setter Property="Fill" TargetName="circle" Value="#FFF3F9FF"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter Property="Stroke" TargetName="circle" Value="#FF3C77DD"/>
|
||||
<Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
|
||||
<Setter Property="Fill" TargetName="circle" Value="#FFD9ECFF"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="Black"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Stroke" TargetName="circle" Value="#FFBCBCBC"/>
|
||||
<Setter Property="Fill" TargetName="circle" Value="#FFE6E6E6"/>
|
||||
<Setter Property="Stroke" TargetName="arrow" Value="#FF707070"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ToggleButton.Style>
|
||||
</ToggleButton>
|
||||
<ContentPresenter x:Name="ExpandSite" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" DockPanel.Dock="Bottom" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" Visibility="Collapsed" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsExpanded" Value="True">
|
||||
<Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
|
||||
</Trigger>
|
||||
<Trigger Property="IsEnabled" Value="False">
|
||||
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -1,103 +1,103 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
internal static Action NavigateToGettingStarted;
|
||||
internal static Action NavigateToUnlockBoot;
|
||||
internal static PatchEngine PatchEngine;
|
||||
internal static WPinternalsConfig Config;
|
||||
internal static Mutex mutex = new(false, "Global\\WPinternalsRunning");
|
||||
internal static DownloadsViewModel DownloadManager;
|
||||
internal static bool InterruptBoot = false;
|
||||
internal static bool IsPnPEventLogMissing = true;
|
||||
|
||||
public App()
|
||||
: base()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
|
||||
#if NETCORE
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
#endif
|
||||
|
||||
if (Environment.GetCommandLineArgs().Length > 1)
|
||||
{
|
||||
CommandLine.OpenConsole();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!mutex.WaitOne(0, false))
|
||||
{
|
||||
if (Environment.GetCommandLineArgs().Length > 1)
|
||||
{
|
||||
Console.WriteLine("Windows Phone Internals is already running");
|
||||
CommandLine.CloseConsole();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Windows Phone Internals is already running.", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||
}
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
catch (AbandonedMutexException) { }
|
||||
|
||||
Registration.CheckExpiration();
|
||||
|
||||
string PatchDefintionsXml;
|
||||
string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PatchDefintions.xml");
|
||||
if (File.Exists(PatchDefintionsPath))
|
||||
{
|
||||
PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
using Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("WPinternals.PatchDefinitions.xml");
|
||||
using StreamReader sr = new(stream);
|
||||
PatchDefintionsXml = sr.ReadToEnd();
|
||||
}
|
||||
PatchEngine = new PatchEngine(PatchDefintionsXml);
|
||||
|
||||
Config = WPinternalsConfig.ReadConfig();
|
||||
}
|
||||
|
||||
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (e.ExceptionObject is Exception)
|
||||
{
|
||||
LogFile.LogException(e.ExceptionObject as Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
internal static Action NavigateToGettingStarted;
|
||||
internal static Action NavigateToUnlockBoot;
|
||||
internal static PatchEngine PatchEngine;
|
||||
internal static WPinternalsConfig Config;
|
||||
internal static Mutex mutex = new(false, "Global\\WPinternalsRunning");
|
||||
internal static DownloadsViewModel DownloadManager;
|
||||
internal static bool InterruptBoot = false;
|
||||
internal static bool IsPnPEventLogMissing = true;
|
||||
|
||||
public App()
|
||||
: base()
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
|
||||
#if NETCORE
|
||||
System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
|
||||
#endif
|
||||
|
||||
if (Environment.GetCommandLineArgs().Length > 1)
|
||||
{
|
||||
CommandLine.OpenConsole();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!mutex.WaitOne(0, false))
|
||||
{
|
||||
if (Environment.GetCommandLineArgs().Length > 1)
|
||||
{
|
||||
Console.WriteLine("Windows Phone Internals is already running");
|
||||
CommandLine.CloseConsole();
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("Windows Phone Internals is already running.", "Windows Phone Internals", MessageBoxButton.OK, MessageBoxImage.Exclamation);
|
||||
}
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
catch (AbandonedMutexException) { }
|
||||
|
||||
Registration.CheckExpiration();
|
||||
|
||||
string PatchDefintionsXml;
|
||||
string PatchDefintionsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "PatchDefintions.xml");
|
||||
if (File.Exists(PatchDefintionsPath))
|
||||
{
|
||||
PatchDefintionsXml = File.ReadAllText(PatchDefintionsPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
using Stream stream = System.Reflection.Assembly.GetEntryAssembly().GetManifestResourceStream("WPinternals.PatchDefinitions.xml");
|
||||
using StreamReader sr = new(stream);
|
||||
PatchDefintionsXml = sr.ReadToEnd();
|
||||
}
|
||||
PatchEngine = new PatchEngine(PatchDefintionsXml);
|
||||
|
||||
Config = WPinternalsConfig.ReadConfig();
|
||||
}
|
||||
|
||||
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
if (e.ExceptionObject is Exception)
|
||||
{
|
||||
LogFile.LogException(e.ExceptionObject as Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace DiscUtils.Internal
|
||||
result.Add(func(sVal));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
return [.. result];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -31,15 +31,15 @@ namespace DiscUtils.Fat
|
||||
private const byte SpaceByte = 0x20;
|
||||
|
||||
public static readonly FileName SelfEntryName =
|
||||
new(new byte[] { 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
|
||||
new([0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], 0);
|
||||
|
||||
public static readonly FileName ParentEntryName =
|
||||
new(new byte[] { 0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, 0);
|
||||
new([0x2E, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20], 0);
|
||||
|
||||
public static readonly FileName Null =
|
||||
new(new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0);
|
||||
new([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00], 0);
|
||||
|
||||
private static readonly byte[] InvalidBytes = { 0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C };
|
||||
private static readonly byte[] InvalidBytes = [0x22, 0x2A, 0x2B, 0x2C, 0x2E, 0x2F, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x5B, 0x5C, 0x5D, 0x7C];
|
||||
|
||||
private readonly byte[] _raw;
|
||||
|
||||
@@ -33,10 +33,10 @@ namespace DiscUtils.Fat
|
||||
{
|
||||
if (FatFileSystem.Detect(stream))
|
||||
{
|
||||
return new FileSystemInfo[] { new VfsFileSystemInfo("FAT", "Microsoft FAT", Open) };
|
||||
return [new VfsFileSystemInfo("FAT", "Microsoft FAT", Open)];
|
||||
}
|
||||
|
||||
return System.Array.Empty<FileSystemInfo>();
|
||||
return [];
|
||||
}
|
||||
|
||||
private DiscFileSystem Open(Stream stream, VolumeInfo volumeInfo, FileSystemParameters parameters)
|
||||
@@ -80,22 +80,22 @@ namespace DiscUtils.Fat
|
||||
{
|
||||
// see http://home.teleport.com/~brainy/lfn.htm
|
||||
// NOTE: we assume ordinals are ok here.
|
||||
char[] chars = new char[13];
|
||||
chars[0] = (char)((256 * buffer[2]) + buffer[1]);
|
||||
chars[1] = (char)((256 * buffer[4]) + buffer[3]);
|
||||
chars[2] = (char)((256 * buffer[6]) + buffer[5]);
|
||||
chars[3] = (char)((256 * buffer[8]) + buffer[7]);
|
||||
chars[4] = (char)((256 * buffer[10]) + buffer[9]);
|
||||
|
||||
chars[5] = (char)((256 * buffer[15]) + buffer[14]);
|
||||
chars[6] = (char)((256 * buffer[17]) + buffer[16]);
|
||||
chars[7] = (char)((256 * buffer[19]) + buffer[18]);
|
||||
chars[8] = (char)((256 * buffer[21]) + buffer[20]);
|
||||
chars[9] = (char)((256 * buffer[23]) + buffer[22]);
|
||||
chars[10] = (char)((256 * buffer[25]) + buffer[24]);
|
||||
|
||||
chars[11] = (char)((256 * buffer[29]) + buffer[28]);
|
||||
chars[12] = (char)((256 * buffer[31]) + buffer[30]);
|
||||
char[] chars =
|
||||
[
|
||||
(char)((256 * buffer[2]) + buffer[1]),
|
||||
(char)((256 * buffer[4]) + buffer[3]),
|
||||
(char)((256 * buffer[6]) + buffer[5]),
|
||||
(char)((256 * buffer[8]) + buffer[7]),
|
||||
(char)((256 * buffer[10]) + buffer[9]),
|
||||
(char)((256 * buffer[15]) + buffer[14]),
|
||||
(char)((256 * buffer[17]) + buffer[16]),
|
||||
(char)((256 * buffer[19]) + buffer[18]),
|
||||
(char)((256 * buffer[21]) + buffer[20]),
|
||||
(char)((256 * buffer[23]) + buffer[22]),
|
||||
(char)((256 * buffer[25]) + buffer[24]),
|
||||
(char)((256 * buffer[29]) + buffer[28]),
|
||||
(char)((256 * buffer[31]) + buffer[30]),
|
||||
];
|
||||
string chunk = new(chars);
|
||||
int zero = chunk.IndexOf('\0');
|
||||
return zero >= 0 ? chunk.Substring(0, zero) : chunk;
|
||||
@@ -201,7 +201,7 @@ namespace DiscUtils.Fat
|
||||
}
|
||||
}
|
||||
|
||||
return dirs.ToArray();
|
||||
return [.. dirs];
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetFiles()
|
||||
@@ -215,7 +215,7 @@ namespace DiscUtils.Fat
|
||||
}
|
||||
}
|
||||
|
||||
return files.ToArray();
|
||||
return [.. files];
|
||||
}
|
||||
|
||||
public DirectoryEntry GetEntry(long id)
|
||||
@@ -1258,7 +1258,7 @@ namespace DiscUtils.Fat
|
||||
dirs.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
||||
}
|
||||
|
||||
return dirs.ToArray();
|
||||
return [.. dirs];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1275,7 +1275,7 @@ namespace DiscUtils.Fat
|
||||
|
||||
List<string> dirs = new();
|
||||
DoSearch(dirs, path, re, searchOption == SearchOption.AllDirectories, true, false);
|
||||
return dirs.ToArray();
|
||||
return [.. dirs];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1294,7 +1294,7 @@ namespace DiscUtils.Fat
|
||||
files.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
||||
}
|
||||
|
||||
return files.ToArray();
|
||||
return [.. files];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1311,7 +1311,7 @@ namespace DiscUtils.Fat
|
||||
|
||||
List<string> results = new();
|
||||
DoSearch(results, path, re, searchOption == SearchOption.AllDirectories, false, true);
|
||||
return results.ToArray();
|
||||
return [.. results];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1330,7 +1330,7 @@ namespace DiscUtils.Fat
|
||||
result.Add(Utilities.CombinePaths(path, dirEntry.Name.GetDisplayName(FatOptions.FileNameEncoding)));
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
return [.. result];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1356,7 +1356,7 @@ namespace DiscUtils.Fat
|
||||
}
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
return [.. result];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1915,9 +1915,7 @@ namespace DiscUtils.Fat
|
||||
throw new DirectoryNotFoundException(string.Format(CultureInfo.InvariantCulture, "The directory '{0}' was not found", path));
|
||||
}
|
||||
|
||||
DirectoryEntry[] entries = dir.Entries;
|
||||
|
||||
foreach (DirectoryEntry de in entries)
|
||||
foreach (DirectoryEntry de in dir.Entries)
|
||||
{
|
||||
bool isDir = (de.Attributes & FatAttributes.Directory) != 0;
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
<!--
|
||||
Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.
|
||||
-->
|
||||
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:WPinternals" x:Class="WPinternals.FilePickerBase"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="100" d:DesignWidth="300"
|
||||
x:Name="FilePickerControlName"
|
||||
SizeChanged="SizeChangedHandler" Loaded="LoadedHandler"
|
||||
>
|
||||
<Grid>
|
||||
<TextBlock x:Name="CaptionTextBlock" HorizontalAlignment="Left" Text=""/>
|
||||
<TextBlock x:Name="PathTextBlock" FontWeight="Bold" HorizontalAlignment="Left" Text="Path here"/>
|
||||
<TextBlock x:Name="SelectLink" Margin="150,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Select" Click="SelectLink_Click"><TextBlock Text="{Binding Path=SelectionText, ElementName=FilePickerControlName}"/></Hyperlink></TextBlock>
|
||||
<TextBlock x:Name="ChangeLink" Margin="210,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Change" Click="ChangeLink_Click">Change</Hyperlink></TextBlock>
|
||||
<TextBlock x:Name="ClearLink" Margin="260,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Clear" Click="ClearLink_Click">Clear</Hyperlink></TextBlock>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:WPinternals" x:Class="WPinternals.FilePickerBase"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="100" d:DesignWidth="300"
|
||||
x:Name="FilePickerControlName"
|
||||
SizeChanged="SizeChangedHandler" Loaded="LoadedHandler"
|
||||
>
|
||||
<Grid>
|
||||
<TextBlock x:Name="CaptionTextBlock" HorizontalAlignment="Left" Text=""/>
|
||||
<TextBlock x:Name="PathTextBlock" FontWeight="Bold" HorizontalAlignment="Left" Text="Path here"/>
|
||||
<TextBlock x:Name="SelectLink" Margin="150,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Select" Click="SelectLink_Click"><TextBlock Text="{Binding Path=SelectionText, ElementName=FilePickerControlName}"/></Hyperlink></TextBlock>
|
||||
<TextBlock x:Name="ChangeLink" Margin="210,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Change" Click="ChangeLink_Click">Change</Hyperlink></TextBlock>
|
||||
<TextBlock x:Name="ClearLink" Margin="260,0,0,0" HorizontalAlignment="Left"><Hyperlink NavigateUri="Clear" Click="ClearLink_Click">Clear</Hyperlink></TextBlock>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@@ -1,120 +1,120 @@
|
||||
// This class was found online.
|
||||
// Original author is probably: Swizzy
|
||||
// https://github.com/ttgxdinger/Random/blob/master/CPUKey%20Checker/CPUKey%20Checker/FolderSelectDialog.cs
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps System.Windows.Forms.OpenFileDialog to make it present
|
||||
/// a vista-style dialog.
|
||||
/// </summary>
|
||||
public class FolderSelectDialog
|
||||
{
|
||||
// Wrapped dialog
|
||||
private readonly OpenFileDialog ofd = null;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public FolderSelectDialog()
|
||||
{
|
||||
ofd = new OpenFileDialog
|
||||
{
|
||||
Filter = "Folders|\n",
|
||||
AddExtension = false,
|
||||
CheckFileExists = false,
|
||||
DereferenceLinks = true,
|
||||
Multiselect = false
|
||||
};
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the initial folder to be selected. A null value selects the current directory.
|
||||
/// </summary>
|
||||
public string InitialDirectory
|
||||
{
|
||||
get { return ofd.InitialDirectory; }
|
||||
set { ofd.InitialDirectory = string.IsNullOrEmpty(value) ? Environment.CurrentDirectory : value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the title to show in the dialog
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get { return ofd.Title; }
|
||||
set { ofd.Title = value ?? "Select a folder"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected folder
|
||||
/// </summary>
|
||||
public string FileName
|
||||
{
|
||||
get { return ofd.FileName; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Shows the dialog
|
||||
/// </summary>
|
||||
/// <returns>True if the user presses OK else false</returns>
|
||||
public bool ShowDialog()
|
||||
{
|
||||
return ShowDialog(IntPtr.Zero);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the dialog
|
||||
/// </summary>
|
||||
/// <param name="hWndOwner">Handle of the control to be parent</param>
|
||||
/// <returns>True if the user presses OK else false</returns>
|
||||
public bool ShowDialog(IntPtr hWndOwner)
|
||||
{
|
||||
var fbd = new FolderBrowserDialog
|
||||
{
|
||||
Description = this.Title,
|
||||
SelectedPath = this.InitialDirectory,
|
||||
ShowNewFolderButton = false
|
||||
};
|
||||
if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ofd.FileName = fbd.SelectedPath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates IWin32Window around an IntPtr
|
||||
/// </summary>
|
||||
public class WindowWrapper : IWin32Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="handle">Handle to wrap</param>
|
||||
public WindowWrapper(IntPtr handle)
|
||||
{
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Original ptr
|
||||
/// </summary>
|
||||
public IntPtr Handle { get; }
|
||||
}
|
||||
}
|
||||
// This class was found online.
|
||||
// Original author is probably: Swizzy
|
||||
// https://github.com/ttgxdinger/Random/blob/master/CPUKey%20Checker/CPUKey%20Checker/FolderSelectDialog.cs
|
||||
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
/// <summary>
|
||||
/// Wraps System.Windows.Forms.OpenFileDialog to make it present
|
||||
/// a vista-style dialog.
|
||||
/// </summary>
|
||||
public class FolderSelectDialog
|
||||
{
|
||||
// Wrapped dialog
|
||||
private readonly OpenFileDialog ofd = null;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor
|
||||
/// </summary>
|
||||
public FolderSelectDialog()
|
||||
{
|
||||
ofd = new OpenFileDialog
|
||||
{
|
||||
Filter = "Folders|\n",
|
||||
AddExtension = false,
|
||||
CheckFileExists = false,
|
||||
DereferenceLinks = true,
|
||||
Multiselect = false
|
||||
};
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the initial folder to be selected. A null value selects the current directory.
|
||||
/// </summary>
|
||||
public string InitialDirectory
|
||||
{
|
||||
get { return ofd.InitialDirectory; }
|
||||
set { ofd.InitialDirectory = string.IsNullOrEmpty(value) ? Environment.CurrentDirectory : value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/Sets the title to show in the dialog
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get { return ofd.Title; }
|
||||
set { ofd.Title = value ?? "Select a folder"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the selected folder
|
||||
/// </summary>
|
||||
public string FileName
|
||||
{
|
||||
get { return ofd.FileName; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
/// <summary>
|
||||
/// Shows the dialog
|
||||
/// </summary>
|
||||
/// <returns>True if the user presses OK else false</returns>
|
||||
public bool ShowDialog()
|
||||
{
|
||||
return ShowDialog(IntPtr.Zero);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the dialog
|
||||
/// </summary>
|
||||
/// <param name="hWndOwner">Handle of the control to be parent</param>
|
||||
/// <returns>True if the user presses OK else false</returns>
|
||||
public bool ShowDialog(IntPtr hWndOwner)
|
||||
{
|
||||
var fbd = new FolderBrowserDialog
|
||||
{
|
||||
Description = this.Title,
|
||||
SelectedPath = this.InitialDirectory,
|
||||
ShowNewFolderButton = false
|
||||
};
|
||||
if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ofd.FileName = fbd.SelectedPath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates IWin32Window around an IntPtr
|
||||
/// </summary>
|
||||
public class WindowWrapper : IWin32Window
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="handle">Handle to wrap</param>
|
||||
public WindowWrapper(IntPtr handle)
|
||||
{
|
||||
Handle = handle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Original ptr
|
||||
/// </summary>
|
||||
public IntPtr Handle { get; }
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
@@ -1,401 +1,401 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.
|
||||
|
||||
// These functions assume same endianness for the CPU architecture and the raw data it reads from or writes to.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class ByteOperations
|
||||
{
|
||||
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||
{
|
||||
byte[] Bytes = new byte[Length];
|
||||
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||
return System.Text.Encoding.ASCII.GetString(Bytes);
|
||||
}
|
||||
|
||||
internal static string ReadUnicodeString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||
{
|
||||
byte[] Bytes = new byte[Length];
|
||||
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||
return System.Text.Encoding.Unicode.GetString(Bytes);
|
||||
}
|
||||
|
||||
internal static void WriteAsciiString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
|
||||
{
|
||||
if (MaxBufferLength != null)
|
||||
{
|
||||
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
|
||||
}
|
||||
|
||||
byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(Text);
|
||||
int WriteLength = TextBytes.Length;
|
||||
if (WriteLength > MaxBufferLength)
|
||||
{
|
||||
WriteLength = (int)MaxBufferLength;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
|
||||
}
|
||||
|
||||
internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
|
||||
{
|
||||
if (MaxBufferLength != null)
|
||||
{
|
||||
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
|
||||
}
|
||||
|
||||
byte[] TextBytes = System.Text.Encoding.Unicode.GetBytes(Text);
|
||||
int WriteLength = TextBytes.Length;
|
||||
if (WriteLength > MaxBufferLength)
|
||||
{
|
||||
WriteLength = (int)MaxBufferLength;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
|
||||
}
|
||||
|
||||
internal static UInt32 ReadUInt32(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToUInt32(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteUInt32(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||
}
|
||||
|
||||
internal static Int32 ReadInt32(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToInt32(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteInt32(byte[] ByteArray, UInt32 Offset, Int32 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||
}
|
||||
|
||||
internal static UInt16 ReadUInt16(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToUInt16(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteUInt16(byte[] ByteArray, UInt32 Offset, UInt16 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||
}
|
||||
|
||||
internal static Int16 ReadInt16(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToInt16(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteInt16(byte[] ByteArray, UInt32 Offset, Int16 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||
}
|
||||
|
||||
internal static byte ReadUInt8(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return ByteArray[Offset];
|
||||
}
|
||||
|
||||
internal static void WriteUInt8(byte[] ByteArray, UInt32 Offset, byte Value)
|
||||
{
|
||||
ByteArray[Offset] = Value;
|
||||
}
|
||||
|
||||
internal static UInt32 ReadUInt24(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return (UInt32)(ByteArray[Offset] + (ByteArray[Offset + 1] << 8) + (ByteArray[Offset + 2] << 16));
|
||||
}
|
||||
|
||||
internal static void WriteUInt24(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 3);
|
||||
}
|
||||
|
||||
internal static UInt64 ReadUInt64(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToUInt64(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteUInt64(byte[] ByteArray, UInt32 Offset, UInt64 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8);
|
||||
}
|
||||
|
||||
internal static Guid ReadGuid(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
byte[] GuidBuffer = new byte[0x10];
|
||||
Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10);
|
||||
return new Guid(GuidBuffer);
|
||||
}
|
||||
|
||||
internal static void WriteGuid(byte[] ByteArray, UInt32 Offset, Guid Value)
|
||||
{
|
||||
Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10);
|
||||
}
|
||||
|
||||
internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment)
|
||||
{
|
||||
if (((Offset - Base) % Alignment) == 0)
|
||||
{
|
||||
return Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base;
|
||||
}
|
||||
}
|
||||
|
||||
internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern)
|
||||
{
|
||||
// The mask is optional.
|
||||
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||
|
||||
UInt32? Result = null;
|
||||
|
||||
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
|
||||
|
||||
byte[] Buffer = new byte[0x10000 + Pattern.Length - 1];
|
||||
UInt32 BufferReadPosition = 0; // Position in buffer where file-chunk is being read.
|
||||
UInt32 BytesInBuffer = 0;
|
||||
UInt32 BytesRead;
|
||||
UInt32 SearchPositionFile = 0;
|
||||
UInt32 SearchPositionBuffer = 0;
|
||||
UInt32 BufferFileOffset = 0; // Offset in file where data from buffer is located.
|
||||
bool Match = false;
|
||||
int i;
|
||||
|
||||
OutPattern = null;
|
||||
|
||||
while (SearchPositionFile <= (Stream.Length - Pattern.Length))
|
||||
{
|
||||
if ((SearchPositionBuffer + Pattern.Length) > BytesInBuffer)
|
||||
{
|
||||
// Need to read next chunk
|
||||
if ((BytesInBuffer - SearchPositionBuffer) > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, Buffer, 0, (int)(BytesInBuffer - SearchPositionBuffer));
|
||||
}
|
||||
BufferReadPosition = BytesInBuffer - SearchPositionBuffer;
|
||||
BytesInBuffer -= SearchPositionBuffer;
|
||||
BufferFileOffset += SearchPositionBuffer;
|
||||
SearchPositionBuffer = 0;
|
||||
|
||||
BytesRead = (UInt32)Stream.Read(Buffer, (int)BufferReadPosition, Buffer.Length - (int)BufferReadPosition);
|
||||
BytesInBuffer += BytesRead;
|
||||
}
|
||||
|
||||
Match = true;
|
||||
for (i = 0; i < Pattern.Length; i++)
|
||||
{
|
||||
if (Buffer[SearchPositionBuffer + i] != Pattern[i])
|
||||
{
|
||||
if ((Mask == null) || (Mask[i] == 0))
|
||||
{
|
||||
Match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Match)
|
||||
{
|
||||
Result = SearchPositionFile;
|
||||
|
||||
OutPattern = new byte[Pattern.Length];
|
||||
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, OutPattern, 0, Pattern.Length);
|
||||
break;
|
||||
}
|
||||
|
||||
SearchPositionBuffer++;
|
||||
SearchPositionFile++;
|
||||
}
|
||||
|
||||
Stream.Close();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, System.Text.Encoding.ASCII.GetBytes(Pattern), null, null);
|
||||
}
|
||||
|
||||
internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, System.Text.Encoding.Unicode.GetBytes(Pattern), null, null);
|
||||
}
|
||||
|
||||
internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, BitConverter.GetBytes(Pattern), null, null);
|
||||
}
|
||||
|
||||
internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern);
|
||||
}
|
||||
|
||||
internal static bool Compare(byte[] Array1, byte[] Array2)
|
||||
{
|
||||
return System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Array1, Array2);
|
||||
}
|
||||
|
||||
internal static UInt32? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||
{
|
||||
// The mask is optional.
|
||||
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||
|
||||
UInt32? Result = null;
|
||||
|
||||
UInt32 SearchPosition = SourceOffset;
|
||||
bool Match = false;
|
||||
int i;
|
||||
|
||||
while ((SearchPosition <= (SourceBuffer.Length - Pattern.Length)) && ((SourceSize == null) || (SearchPosition <= (SourceOffset + SourceSize - Pattern.Length))))
|
||||
{
|
||||
Match = true;
|
||||
for (i = 0; i < Pattern.Length; i++)
|
||||
{
|
||||
if (SourceBuffer[SearchPosition + i] != Pattern[i])
|
||||
{
|
||||
if ((Mask == null) || (Mask[i] == 0))
|
||||
{
|
||||
Match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Match)
|
||||
{
|
||||
Result = SearchPosition;
|
||||
|
||||
if (OutPattern != null)
|
||||
{
|
||||
Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SearchPosition++;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal static byte CalculateChecksum8(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||
{
|
||||
byte Checksum = 0;
|
||||
|
||||
for (UInt32 i = Offset; i < (Offset + Size); i++)
|
||||
{
|
||||
Checksum += Buffer[i];
|
||||
}
|
||||
|
||||
return (byte)(0x100 - Checksum);
|
||||
}
|
||||
|
||||
internal static UInt16 CalculateChecksum16(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||
{
|
||||
UInt16 Checksum = 0;
|
||||
|
||||
for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2)
|
||||
{
|
||||
Checksum += BitConverter.ToUInt16(Buffer, (int)i);
|
||||
}
|
||||
|
||||
return (UInt16)(0x10000 - Checksum);
|
||||
}
|
||||
|
||||
private static readonly UInt32[] CRC32Table = new UInt32[] {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
|
||||
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
|
||||
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
|
||||
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
|
||||
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
|
||||
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
|
||||
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
|
||||
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
|
||||
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
|
||||
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
|
||||
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
|
||||
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
|
||||
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
|
||||
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
|
||||
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
|
||||
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
|
||||
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
|
||||
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
|
||||
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
|
||||
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
|
||||
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
};
|
||||
|
||||
internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length)
|
||||
{
|
||||
if ((Input == null) || ((Offset + Length) > Input.Length))
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
unchecked
|
||||
{
|
||||
uint crc = (uint)(((uint)0) ^ (-1));
|
||||
for (var i = Offset; i < (Offset + Length); i++)
|
||||
{
|
||||
crc = (crc >> 8) ^ CRC32Table[(crc ^ Input[i]) & 0xFF];
|
||||
}
|
||||
crc = (uint)(crc ^ (-1));
|
||||
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
|
||||
// These functions assume same endianness for the CPU architecture and the raw data it reads from or writes to.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class ByteOperations
|
||||
{
|
||||
internal static string ReadAsciiString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||
{
|
||||
byte[] Bytes = new byte[Length];
|
||||
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||
return System.Text.Encoding.ASCII.GetString(Bytes);
|
||||
}
|
||||
|
||||
internal static string ReadUnicodeString(byte[] ByteArray, UInt32 Offset, UInt32 Length)
|
||||
{
|
||||
byte[] Bytes = new byte[Length];
|
||||
Buffer.BlockCopy(ByteArray, (int)Offset, Bytes, 0, (int)Length);
|
||||
return System.Text.Encoding.Unicode.GetString(Bytes);
|
||||
}
|
||||
|
||||
internal static void WriteAsciiString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
|
||||
{
|
||||
if (MaxBufferLength != null)
|
||||
{
|
||||
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
|
||||
}
|
||||
|
||||
byte[] TextBytes = System.Text.Encoding.ASCII.GetBytes(Text);
|
||||
int WriteLength = TextBytes.Length;
|
||||
if (WriteLength > MaxBufferLength)
|
||||
{
|
||||
WriteLength = (int)MaxBufferLength;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
|
||||
}
|
||||
|
||||
internal static void WriteUnicodeString(byte[] ByteArray, UInt32 Offset, string Text, UInt32? MaxBufferLength = null)
|
||||
{
|
||||
if (MaxBufferLength != null)
|
||||
{
|
||||
Array.Clear(ByteArray, (int)Offset, (int)MaxBufferLength);
|
||||
}
|
||||
|
||||
byte[] TextBytes = System.Text.Encoding.Unicode.GetBytes(Text);
|
||||
int WriteLength = TextBytes.Length;
|
||||
if (WriteLength > MaxBufferLength)
|
||||
{
|
||||
WriteLength = (int)MaxBufferLength;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(TextBytes, 0, ByteArray, (int)Offset, WriteLength);
|
||||
}
|
||||
|
||||
internal static UInt32 ReadUInt32(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToUInt32(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteUInt32(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||
}
|
||||
|
||||
internal static Int32 ReadInt32(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToInt32(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteInt32(byte[] ByteArray, UInt32 Offset, Int32 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 4);
|
||||
}
|
||||
|
||||
internal static UInt16 ReadUInt16(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToUInt16(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteUInt16(byte[] ByteArray, UInt32 Offset, UInt16 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||
}
|
||||
|
||||
internal static Int16 ReadInt16(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToInt16(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteInt16(byte[] ByteArray, UInt32 Offset, Int16 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 2);
|
||||
}
|
||||
|
||||
internal static byte ReadUInt8(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return ByteArray[Offset];
|
||||
}
|
||||
|
||||
internal static void WriteUInt8(byte[] ByteArray, UInt32 Offset, byte Value)
|
||||
{
|
||||
ByteArray[Offset] = Value;
|
||||
}
|
||||
|
||||
internal static UInt32 ReadUInt24(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return (UInt32)(ByteArray[Offset] + (ByteArray[Offset + 1] << 8) + (ByteArray[Offset + 2] << 16));
|
||||
}
|
||||
|
||||
internal static void WriteUInt24(byte[] ByteArray, UInt32 Offset, UInt32 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 3);
|
||||
}
|
||||
|
||||
internal static UInt64 ReadUInt64(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
return BitConverter.ToUInt64(ByteArray, (int)Offset);
|
||||
}
|
||||
|
||||
internal static void WriteUInt64(byte[] ByteArray, UInt32 Offset, UInt64 Value)
|
||||
{
|
||||
Buffer.BlockCopy(BitConverter.GetBytes(Value), 0, ByteArray, (int)Offset, 8);
|
||||
}
|
||||
|
||||
internal static Guid ReadGuid(byte[] ByteArray, UInt32 Offset)
|
||||
{
|
||||
byte[] GuidBuffer = new byte[0x10];
|
||||
Buffer.BlockCopy(ByteArray, (int)Offset, GuidBuffer, 0, 0x10);
|
||||
return new Guid(GuidBuffer);
|
||||
}
|
||||
|
||||
internal static void WriteGuid(byte[] ByteArray, UInt32 Offset, Guid Value)
|
||||
{
|
||||
Buffer.BlockCopy(Value.ToByteArray(), 0, ByteArray, (int)Offset, 0x10);
|
||||
}
|
||||
|
||||
internal static UInt32 Align(UInt32 Base, UInt32 Offset, UInt32 Alignment)
|
||||
{
|
||||
if (((Offset - Base) % Alignment) == 0)
|
||||
{
|
||||
return Offset;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((((Offset - Base) / Alignment) + 1) * Alignment) + Base;
|
||||
}
|
||||
}
|
||||
|
||||
internal static UInt32? FindPatternInFile(string FileName, byte[] Pattern, byte[] Mask, out byte[] OutPattern)
|
||||
{
|
||||
// The mask is optional.
|
||||
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||
|
||||
UInt32? Result = null;
|
||||
|
||||
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
|
||||
|
||||
byte[] Buffer = new byte[0x10000 + Pattern.Length - 1];
|
||||
UInt32 BufferReadPosition = 0; // Position in buffer where file-chunk is being read.
|
||||
UInt32 BytesInBuffer = 0;
|
||||
UInt32 BytesRead;
|
||||
UInt32 SearchPositionFile = 0;
|
||||
UInt32 SearchPositionBuffer = 0;
|
||||
UInt32 BufferFileOffset = 0; // Offset in file where data from buffer is located.
|
||||
bool Match = false;
|
||||
int i;
|
||||
|
||||
OutPattern = null;
|
||||
|
||||
while (SearchPositionFile <= (Stream.Length - Pattern.Length))
|
||||
{
|
||||
if ((SearchPositionBuffer + Pattern.Length) > BytesInBuffer)
|
||||
{
|
||||
// Need to read next chunk
|
||||
if ((BytesInBuffer - SearchPositionBuffer) > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, Buffer, 0, (int)(BytesInBuffer - SearchPositionBuffer));
|
||||
}
|
||||
BufferReadPosition = BytesInBuffer - SearchPositionBuffer;
|
||||
BytesInBuffer -= SearchPositionBuffer;
|
||||
BufferFileOffset += SearchPositionBuffer;
|
||||
SearchPositionBuffer = 0;
|
||||
|
||||
BytesRead = (UInt32)Stream.Read(Buffer, (int)BufferReadPosition, Buffer.Length - (int)BufferReadPosition);
|
||||
BytesInBuffer += BytesRead;
|
||||
}
|
||||
|
||||
Match = true;
|
||||
for (i = 0; i < Pattern.Length; i++)
|
||||
{
|
||||
if (Buffer[SearchPositionBuffer + i] != Pattern[i])
|
||||
{
|
||||
if ((Mask == null) || (Mask[i] == 0))
|
||||
{
|
||||
Match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Match)
|
||||
{
|
||||
Result = SearchPositionFile;
|
||||
|
||||
OutPattern = new byte[Pattern.Length];
|
||||
System.Buffer.BlockCopy(Buffer, (int)SearchPositionBuffer, OutPattern, 0, Pattern.Length);
|
||||
break;
|
||||
}
|
||||
|
||||
SearchPositionBuffer++;
|
||||
SearchPositionFile++;
|
||||
}
|
||||
|
||||
Stream.Close();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal static UInt32? FindAscii(byte[] SourceBuffer, string Pattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, System.Text.Encoding.ASCII.GetBytes(Pattern), null, null);
|
||||
}
|
||||
|
||||
internal static UInt32? FindUnicode(byte[] SourceBuffer, string Pattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, System.Text.Encoding.Unicode.GetBytes(Pattern), null, null);
|
||||
}
|
||||
|
||||
internal static UInt32? FindUint(byte[] SourceBuffer, UInt32 Pattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, BitConverter.GetBytes(Pattern), null, null);
|
||||
}
|
||||
|
||||
internal static UInt32? FindPattern(byte[] SourceBuffer, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||
{
|
||||
return FindPattern(SourceBuffer, 0, null, Pattern, Mask, OutPattern);
|
||||
}
|
||||
|
||||
internal static bool Compare(byte[] Array1, byte[] Array2)
|
||||
{
|
||||
return System.Collections.StructuralComparisons.StructuralEqualityComparer.Equals(Array1, Array2);
|
||||
}
|
||||
|
||||
internal static UInt32? FindPattern(byte[] SourceBuffer, uint SourceOffset, uint? SourceSize, byte[] Pattern, byte[] Mask, byte[] OutPattern)
|
||||
{
|
||||
// The mask is optional.
|
||||
// In the mask 0x00 means the value must match, and 0xFF means that this position is a wildcard.
|
||||
|
||||
UInt32? Result = null;
|
||||
|
||||
UInt32 SearchPosition = SourceOffset;
|
||||
bool Match = false;
|
||||
int i;
|
||||
|
||||
while ((SearchPosition <= (SourceBuffer.Length - Pattern.Length)) && ((SourceSize == null) || (SearchPosition <= (SourceOffset + SourceSize - Pattern.Length))))
|
||||
{
|
||||
Match = true;
|
||||
for (i = 0; i < Pattern.Length; i++)
|
||||
{
|
||||
if (SourceBuffer[SearchPosition + i] != Pattern[i])
|
||||
{
|
||||
if ((Mask == null) || (Mask[i] == 0))
|
||||
{
|
||||
Match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Match)
|
||||
{
|
||||
Result = SearchPosition;
|
||||
|
||||
if (OutPattern != null)
|
||||
{
|
||||
Buffer.BlockCopy(SourceBuffer, (int)SearchPosition, OutPattern, 0, Pattern.Length);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
SearchPosition++;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal static byte CalculateChecksum8(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||
{
|
||||
byte Checksum = 0;
|
||||
|
||||
for (UInt32 i = Offset; i < (Offset + Size); i++)
|
||||
{
|
||||
Checksum += Buffer[i];
|
||||
}
|
||||
|
||||
return (byte)(0x100 - Checksum);
|
||||
}
|
||||
|
||||
internal static UInt16 CalculateChecksum16(byte[] Buffer, UInt32 Offset, UInt32 Size)
|
||||
{
|
||||
UInt16 Checksum = 0;
|
||||
|
||||
for (UInt32 i = Offset; i < (Offset + Size - 1); i += 2)
|
||||
{
|
||||
Checksum += BitConverter.ToUInt16(Buffer, (int)i);
|
||||
}
|
||||
|
||||
return (UInt16)(0x10000 - Checksum);
|
||||
}
|
||||
|
||||
private static readonly UInt32[] CRC32Table = [
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
|
||||
0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
||||
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2,
|
||||
0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
||||
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
|
||||
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
||||
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
|
||||
0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
||||
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
|
||||
0xCFBA9599, 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
||||
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, 0x01DB7106,
|
||||
0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
||||
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
|
||||
0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
||||
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
|
||||
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
||||
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
|
||||
0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
||||
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA,
|
||||
0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
||||
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
|
||||
0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
||||
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84,
|
||||
0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
||||
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
|
||||
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
||||
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8, 0xA1D1937E,
|
||||
0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
||||
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
|
||||
0x316E8EEF, 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
||||
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28,
|
||||
0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
||||
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
|
||||
0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
||||
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
|
||||
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
||||
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
|
||||
0x616BFFD3, 0x166CCF45, 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
||||
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC,
|
||||
0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
||||
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
|
||||
0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
||||
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
||||
];
|
||||
|
||||
internal static UInt32 CRC32(byte[] Input, UInt32 Offset, UInt32 Length)
|
||||
{
|
||||
if ((Input == null) || ((Offset + Length) > Input.Length))
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
unchecked
|
||||
{
|
||||
uint crc = (uint)(((uint)0) ^ (-1));
|
||||
for (var i = Offset; i < (Offset + Length); i++)
|
||||
{
|
||||
crc = (crc >> 8) ^ CRC32Table[(crc ^ Input[i]) & 0xFF];
|
||||
}
|
||||
crc = (uint)(crc ^ (-1));
|
||||
|
||||
return crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,487 +1,487 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class FFU
|
||||
{
|
||||
internal int ChunkSize;
|
||||
internal string Path;
|
||||
internal byte[] SecurityHeader;
|
||||
internal byte[] ImageHeader;
|
||||
internal byte[] StoreHeader;
|
||||
private readonly int?[] ChunkIndexes;
|
||||
private FileStream FFUFile = null;
|
||||
private int FileOpenCount = 0;
|
||||
|
||||
internal string PlatformID;
|
||||
internal GPT GPT;
|
||||
|
||||
internal UInt64 TotalSize;
|
||||
internal UInt64 HeaderSize;
|
||||
internal UInt64 PayloadSize;
|
||||
internal UInt64 TotalChunkCount;
|
||||
|
||||
internal FFU(string Path)
|
||||
{
|
||||
this.Path = Path;
|
||||
|
||||
try
|
||||
{
|
||||
OpenFile();
|
||||
|
||||
// Read Security Header
|
||||
byte[] ShortSecurityHeader = new byte[0x20];
|
||||
FFUFile.Read(ShortSecurityHeader, 0, 0x20);
|
||||
if (ByteOperations.ReadAsciiString(ShortSecurityHeader, 0x04, 0x0C) != "SignedImage ")
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
ChunkSize = ByteOperations.ReadInt32(ShortSecurityHeader, 0x10) * 1024;
|
||||
UInt32 SecurityHeaderSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x00);
|
||||
UInt32 CatalogSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x18);
|
||||
UInt32 HashTableSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x1C);
|
||||
SecurityHeader = new byte[RoundUpToChunks(SecurityHeaderSize + CatalogSize + HashTableSize)];
|
||||
FFUFile.Seek(0, SeekOrigin.Begin);
|
||||
FFUFile.Read(SecurityHeader, 0, SecurityHeader.Length);
|
||||
|
||||
// Read Image Header
|
||||
byte[] ShortImageHeader = new byte[0x1C];
|
||||
FFUFile.Read(ShortImageHeader, 0, 0x1C);
|
||||
if (ByteOperations.ReadAsciiString(ShortImageHeader, 0x04, 0x0C) != "ImageFlash ")
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 ImageHeaderSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x00);
|
||||
UInt32 ManifestSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x10);
|
||||
ImageHeader = new byte[RoundUpToChunks(ImageHeaderSize + ManifestSize)];
|
||||
FFUFile.Seek(SecurityHeader.Length, SeekOrigin.Begin);
|
||||
FFUFile.Read(ImageHeader, 0, ImageHeader.Length);
|
||||
|
||||
// Read Store Header
|
||||
byte[] ShortStoreHeader = new byte[248];
|
||||
FFUFile.Read(ShortStoreHeader, 0, 248);
|
||||
PlatformID = ByteOperations.ReadAsciiString(ShortStoreHeader, 0x0C, 192).TrimEnd(new char[] { (char)0, ' ' });
|
||||
int WriteDescriptorCount = ByteOperations.ReadInt32(ShortStoreHeader, 208);
|
||||
UInt32 WriteDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 212);
|
||||
UInt32 ValidateDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 220);
|
||||
StoreHeader = new byte[RoundUpToChunks(248 + WriteDescriptorLength + ValidateDescriptorLength)];
|
||||
FFUFile.Seek(SecurityHeader.Length + ImageHeader.Length, SeekOrigin.Begin);
|
||||
FFUFile.Read(StoreHeader, 0, StoreHeader.Length);
|
||||
|
||||
// Parse Chunk Indexes
|
||||
int HighestChunkIndex = 0;
|
||||
UInt32 LocationCount;
|
||||
int ChunkIndex;
|
||||
int ChunkCount;
|
||||
int DiskAccessMethod;
|
||||
UInt32 WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength;
|
||||
int FFUChunkIndex = 0;
|
||||
for (int i = 0; i < WriteDescriptorCount; i++)
|
||||
{
|
||||
LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00);
|
||||
ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04);
|
||||
|
||||
for (int j = 0; j < LocationCount; j++)
|
||||
{
|
||||
DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08)));
|
||||
ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08)));
|
||||
|
||||
if (DiskAccessMethod == 0 && (ChunkIndex + ChunkCount - 1) > HighestChunkIndex) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
|
||||
{
|
||||
HighestChunkIndex = ChunkIndex + ChunkCount - 1;
|
||||
}
|
||||
}
|
||||
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
|
||||
FFUChunkIndex += ChunkCount;
|
||||
}
|
||||
ChunkIndexes = new int?[HighestChunkIndex + 1];
|
||||
WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength;
|
||||
FFUChunkIndex = 0;
|
||||
for (int i = 0; i < WriteDescriptorCount; i++)
|
||||
{
|
||||
LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00);
|
||||
ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04);
|
||||
|
||||
for (int j = 0; j < LocationCount; j++)
|
||||
{
|
||||
DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08)));
|
||||
ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08)));
|
||||
|
||||
if (DiskAccessMethod == 0) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
|
||||
{
|
||||
for (int k = 0; k < ChunkCount; k++)
|
||||
{
|
||||
ChunkIndexes[ChunkIndex + k] = FFUChunkIndex + k;
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
|
||||
FFUChunkIndex += ChunkCount;
|
||||
}
|
||||
|
||||
byte[] GPTBuffer = GetSectors(0x01, 0x21);
|
||||
GPT = new GPT(GPTBuffer);
|
||||
|
||||
HeaderSize = (UInt64)(SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length);
|
||||
|
||||
TotalChunkCount = (UInt64)FFUChunkIndex;
|
||||
PayloadSize = TotalChunkCount * (UInt64)ChunkSize;
|
||||
TotalSize = HeaderSize + PayloadSize;
|
||||
|
||||
if (TotalSize != (UInt64)FFUFile.Length)
|
||||
{
|
||||
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + "Expected size: " + TotalSize.ToString() + ". Actual size: " + FFUFile.Length + ".");
|
||||
}
|
||||
}
|
||||
catch (WPinternalsException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + Ex.Message, Ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseFile();
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsFFU(string FileName)
|
||||
{
|
||||
bool Result = false;
|
||||
|
||||
FileStream FFUFile = new(FileName, FileMode.Open, FileAccess.Read);
|
||||
|
||||
byte[] Signature = new byte[0x10];
|
||||
FFUFile.Read(Signature, 0, 0x10);
|
||||
|
||||
Result = ByteOperations.ReadAsciiString(Signature, 0x04, 0x0C) == "SignedImage ";
|
||||
|
||||
FFUFile.Close();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
private void OpenFile()
|
||||
{
|
||||
if (FFUFile == null)
|
||||
{
|
||||
FFUFile = new FileStream(Path, FileMode.Open, FileAccess.Read);
|
||||
FileOpenCount = 0;
|
||||
}
|
||||
FileOpenCount++;
|
||||
}
|
||||
|
||||
private void CloseFile()
|
||||
{
|
||||
FileOpenCount--;
|
||||
if (FileOpenCount == 0)
|
||||
{
|
||||
FFUFile.Close();
|
||||
FFUFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void FileSeek(long Position)
|
||||
{
|
||||
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/2e67ca57-3556-4275-accd-58b7df30d424/unnecessary-filestreamseek-and-setting-filestreamposition-has-huge-effect-on-performance?forum=csharpgeneral
|
||||
|
||||
if (FFUFile != null && FFUFile.Position != Position)
|
||||
{
|
||||
FFUFile.Seek(Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
internal UInt32 RoundUpToChunks(UInt32 Size)
|
||||
{
|
||||
if ((Size % ChunkSize) > 0)
|
||||
{
|
||||
return (UInt32)(((Size / ChunkSize) + 1) * ChunkSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
|
||||
internal UInt32 RoundDownToChunks(UInt32 Size)
|
||||
{
|
||||
if ((Size % ChunkSize) > 0)
|
||||
{
|
||||
return (UInt32)(Size / ChunkSize * ChunkSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] GetSectors(int StartSector, int SectorCount)
|
||||
{
|
||||
int FirstChunk = GetChunkIndexFromSectorIndex(StartSector);
|
||||
int LastChunk = GetChunkIndexFromSectorIndex(StartSector + SectorCount - 1);
|
||||
|
||||
byte[] Buffer = new byte[ChunkSize];
|
||||
|
||||
OpenFile();
|
||||
|
||||
byte[] Result = new byte[SectorCount * 0x200];
|
||||
|
||||
int ResultOffset = 0;
|
||||
|
||||
for (int j = FirstChunk; j <= LastChunk; j++)
|
||||
{
|
||||
GetChunk(Buffer, j);
|
||||
|
||||
int FirstSector = 0;
|
||||
int LastSector = (ChunkSize / 0x200) - 1;
|
||||
|
||||
if (j == FirstChunk)
|
||||
{
|
||||
FirstSector = GetSectorNumberInChunkFromSectorIndex(StartSector);
|
||||
}
|
||||
|
||||
if (j == LastChunk)
|
||||
{
|
||||
LastSector = GetSectorNumberInChunkFromSectorIndex(StartSector + SectorCount - 1);
|
||||
}
|
||||
|
||||
int Offset = FirstSector * 0x200;
|
||||
int Size = (LastSector - FirstSector + 1) * 0x200;
|
||||
|
||||
System.Buffer.BlockCopy(Buffer, Offset, Result, ResultOffset, Size);
|
||||
|
||||
ResultOffset += Size;
|
||||
}
|
||||
|
||||
CloseFile();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal byte[] GetPartition(string Name)
|
||||
{
|
||||
Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (Target == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return GetSectors((int)Target.FirstSector, (int)(Target.LastSector - Target.FirstSector + 1));
|
||||
}
|
||||
|
||||
internal void WritePartition(string Name, string FilePath, bool Compress = false)
|
||||
{
|
||||
WritePartition(Name, FilePath, null, null, Compress);
|
||||
}
|
||||
|
||||
internal void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, bool Compress = false)
|
||||
{
|
||||
WritePartition(Name, FilePath, ProgressUpdateCallback, null, Compress);
|
||||
}
|
||||
|
||||
internal void WritePartition(string Name, string FilePath, ProgressUpdater UpdaterPerSector, bool Compress = false)
|
||||
{
|
||||
WritePartition(Name, FilePath, null, UpdaterPerSector, Compress);
|
||||
}
|
||||
|
||||
private void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, bool Compress = false)
|
||||
{
|
||||
Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (Target == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
int FirstChunk = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
|
||||
int LastChunk = GetChunkIndexFromSectorIndex((int)Target.LastSector);
|
||||
|
||||
ProgressUpdater Updater = UpdaterPerSector;
|
||||
if ((Updater == null) && (ProgressUpdateCallback != null))
|
||||
{
|
||||
Updater = new ProgressUpdater(Target.LastSector - Target.FirstSector + 1, ProgressUpdateCallback);
|
||||
}
|
||||
|
||||
byte[] Buffer = new byte[ChunkSize];
|
||||
|
||||
OpenFile();
|
||||
|
||||
FileStream OutputFile = new(FilePath, FileMode.Create, FileAccess.Write);
|
||||
Stream OutStream = OutputFile;
|
||||
|
||||
// We use gzip compression
|
||||
//
|
||||
// LZMA is about 60 times slower (compression is twice as good, but compressed size is already really small, so it doesnt matter much)
|
||||
// OutStream = new LZMACompressionStream(OutputFile, System.IO.Compression.CompressionMode.Compress, false);
|
||||
//
|
||||
// DeflateStream is a raw compression stream without recognizable header
|
||||
// Deflate has almost no performance penalty
|
||||
// OutStream = new DeflateStream(OutputFile, CompressionLevel.Optimal, false);
|
||||
//
|
||||
// GZip can be recognized. It always starts with 1F 8B 08 (1F 8B is the magic value, 08 is the Deflate compression method)
|
||||
// With GZip compression, dump time goes from 1m to 1m37s. So that doesnt matter much.
|
||||
if (Compress)
|
||||
{
|
||||
OutStream = new CompressedStream(OutputFile, (Target.LastSector - Target.FirstSector + 1) * 0x200);
|
||||
}
|
||||
|
||||
for (int j = FirstChunk; j <= LastChunk; j++)
|
||||
{
|
||||
GetChunk(Buffer, j);
|
||||
|
||||
int FirstSector = 0;
|
||||
int LastSector = (ChunkSize / 0x200) - 1;
|
||||
|
||||
if (j == FirstChunk)
|
||||
{
|
||||
FirstSector = GetSectorNumberInChunkFromSectorIndex((int)Target.FirstSector);
|
||||
}
|
||||
|
||||
if (j == LastChunk)
|
||||
{
|
||||
LastSector = GetSectorNumberInChunkFromSectorIndex((int)Target.LastSector);
|
||||
}
|
||||
|
||||
int Offset = FirstSector * 0x200;
|
||||
int Size = (LastSector - FirstSector + 1) * 0x200;
|
||||
|
||||
OutStream.Write(Buffer, Offset, Size);
|
||||
|
||||
Updater?.IncreaseProgress((UInt64)(ChunkSize / 0x200));
|
||||
}
|
||||
|
||||
OutStream.Close();
|
||||
|
||||
CloseFile();
|
||||
}
|
||||
|
||||
private byte[] GetChunk(int ChunkIndex)
|
||||
{
|
||||
long BaseOffset = (long)SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
|
||||
if (ChunkIndexes[ChunkIndex] == null)
|
||||
{
|
||||
return new byte[ChunkSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenFile();
|
||||
FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize));
|
||||
byte[] Chunk = new byte[ChunkSize];
|
||||
FFUFile.Read(Chunk, 0, ChunkSize);
|
||||
CloseFile();
|
||||
return Chunk;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetChunk(byte[] Chunk, int ChunkIndex)
|
||||
{
|
||||
long BaseOffset = SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
|
||||
if (ChunkIndexes[ChunkIndex] == null)
|
||||
{
|
||||
Array.Clear(Chunk, 0, ChunkSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenFile();
|
||||
FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize));
|
||||
FFUFile.Read(Chunk, 0, ChunkSize);
|
||||
CloseFile();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetChunkIndexFromSectorIndex(int SectorIndex)
|
||||
{
|
||||
int SectorsPerChunk = ChunkSize / 0x200;
|
||||
return SectorIndex / SectorsPerChunk;
|
||||
}
|
||||
|
||||
private int GetSectorNumberInChunkFromSectorIndex(int SectorIndex)
|
||||
{
|
||||
int SectorsPerChunk = ChunkSize / 0x200;
|
||||
return SectorIndex % SectorsPerChunk;
|
||||
}
|
||||
|
||||
internal bool IsPartitionPresentInFFU(string PartitionName)
|
||||
{
|
||||
Partition Target = GPT.GetPartition(PartitionName);
|
||||
if (Target == null)
|
||||
{
|
||||
throw new InvalidOperationException("Partitionname is not found!");
|
||||
}
|
||||
|
||||
int ChunkIndex = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
|
||||
return ChunkIndexes[ChunkIndex] != null;
|
||||
}
|
||||
|
||||
private int GetChunkIndexFromSectorIndex(ulong p)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal string GetFirmwareVersion()
|
||||
{
|
||||
string Result = null;
|
||||
|
||||
Partition Plat = GPT.GetPartition("PLAT");
|
||||
if (Plat != null)
|
||||
{
|
||||
byte[] Data = GetPartition("PLAT");
|
||||
uint? Offset = ByteOperations.FindAscii(Data, "SWVERSION=");
|
||||
if (Offset != null)
|
||||
{
|
||||
uint Start = (uint)Offset + 10;
|
||||
uint Length = (uint)ByteOperations.FindPattern(Data, Start, 0x100, new byte[] { 0x00 }, null, null) - Start;
|
||||
uint? Offset0D = ByteOperations.FindPattern(Data, Start, 0x100, new byte[] { 0x0D }, null, null);
|
||||
if ((Offset0D != null) && (Offset0D < (Start + Length)))
|
||||
{
|
||||
Length = (uint)Offset0D - Start;
|
||||
}
|
||||
|
||||
Result = ByteOperations.ReadAsciiString(Data, Start, Length);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal string GetOSVersion()
|
||||
{
|
||||
byte[] efiesp = GetPartition("EFIESP");
|
||||
MemoryStream s = new(efiesp);
|
||||
DiscUtils.Fat.FatFileSystem fs = new(s);
|
||||
Stream mss = fs.OpenFile(@"\Windows\System32\Boot\mobilestartup.efi", FileMode.Open, FileAccess.Read);
|
||||
MemoryStream msms = new();
|
||||
mss.CopyTo(msms);
|
||||
byte[] mobilestartup = msms.ToArray();
|
||||
Version OSVersion = PE.GetProductVersion(mobilestartup);
|
||||
s.Close();
|
||||
|
||||
return OSVersion.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class FFU
|
||||
{
|
||||
internal int ChunkSize;
|
||||
internal string Path;
|
||||
internal byte[] SecurityHeader;
|
||||
internal byte[] ImageHeader;
|
||||
internal byte[] StoreHeader;
|
||||
private readonly int?[] ChunkIndexes;
|
||||
private FileStream FFUFile = null;
|
||||
private int FileOpenCount = 0;
|
||||
|
||||
internal string PlatformID;
|
||||
internal GPT GPT;
|
||||
|
||||
internal UInt64 TotalSize;
|
||||
internal UInt64 HeaderSize;
|
||||
internal UInt64 PayloadSize;
|
||||
internal UInt64 TotalChunkCount;
|
||||
|
||||
internal FFU(string Path)
|
||||
{
|
||||
this.Path = Path;
|
||||
|
||||
try
|
||||
{
|
||||
OpenFile();
|
||||
|
||||
// Read Security Header
|
||||
byte[] ShortSecurityHeader = new byte[0x20];
|
||||
FFUFile.Read(ShortSecurityHeader, 0, 0x20);
|
||||
if (ByteOperations.ReadAsciiString(ShortSecurityHeader, 0x04, 0x0C) != "SignedImage ")
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
ChunkSize = ByteOperations.ReadInt32(ShortSecurityHeader, 0x10) * 1024;
|
||||
UInt32 SecurityHeaderSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x00);
|
||||
UInt32 CatalogSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x18);
|
||||
UInt32 HashTableSize = ByteOperations.ReadUInt32(ShortSecurityHeader, 0x1C);
|
||||
SecurityHeader = new byte[RoundUpToChunks(SecurityHeaderSize + CatalogSize + HashTableSize)];
|
||||
FFUFile.Seek(0, SeekOrigin.Begin);
|
||||
FFUFile.Read(SecurityHeader, 0, SecurityHeader.Length);
|
||||
|
||||
// Read Image Header
|
||||
byte[] ShortImageHeader = new byte[0x1C];
|
||||
FFUFile.Read(ShortImageHeader, 0, 0x1C);
|
||||
if (ByteOperations.ReadAsciiString(ShortImageHeader, 0x04, 0x0C) != "ImageFlash ")
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 ImageHeaderSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x00);
|
||||
UInt32 ManifestSize = ByteOperations.ReadUInt32(ShortImageHeader, 0x10);
|
||||
ImageHeader = new byte[RoundUpToChunks(ImageHeaderSize + ManifestSize)];
|
||||
FFUFile.Seek(SecurityHeader.Length, SeekOrigin.Begin);
|
||||
FFUFile.Read(ImageHeader, 0, ImageHeader.Length);
|
||||
|
||||
// Read Store Header
|
||||
byte[] ShortStoreHeader = new byte[248];
|
||||
FFUFile.Read(ShortStoreHeader, 0, 248);
|
||||
PlatformID = ByteOperations.ReadAsciiString(ShortStoreHeader, 0x0C, 192).TrimEnd([(char)0, ' ']);
|
||||
int WriteDescriptorCount = ByteOperations.ReadInt32(ShortStoreHeader, 208);
|
||||
UInt32 WriteDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 212);
|
||||
UInt32 ValidateDescriptorLength = ByteOperations.ReadUInt32(ShortStoreHeader, 220);
|
||||
StoreHeader = new byte[RoundUpToChunks(248 + WriteDescriptorLength + ValidateDescriptorLength)];
|
||||
FFUFile.Seek(SecurityHeader.Length + ImageHeader.Length, SeekOrigin.Begin);
|
||||
FFUFile.Read(StoreHeader, 0, StoreHeader.Length);
|
||||
|
||||
// Parse Chunk Indexes
|
||||
int HighestChunkIndex = 0;
|
||||
UInt32 LocationCount;
|
||||
int ChunkIndex;
|
||||
int ChunkCount;
|
||||
int DiskAccessMethod;
|
||||
UInt32 WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength;
|
||||
int FFUChunkIndex = 0;
|
||||
for (int i = 0; i < WriteDescriptorCount; i++)
|
||||
{
|
||||
LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00);
|
||||
ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04);
|
||||
|
||||
for (int j = 0; j < LocationCount; j++)
|
||||
{
|
||||
DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08)));
|
||||
ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08)));
|
||||
|
||||
if (DiskAccessMethod == 0 && (ChunkIndex + ChunkCount - 1) > HighestChunkIndex) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
|
||||
{
|
||||
HighestChunkIndex = ChunkIndex + ChunkCount - 1;
|
||||
}
|
||||
}
|
||||
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
|
||||
FFUChunkIndex += ChunkCount;
|
||||
}
|
||||
ChunkIndexes = new int?[HighestChunkIndex + 1];
|
||||
WriteDescriptorEntryOffset = 248 + ValidateDescriptorLength;
|
||||
FFUChunkIndex = 0;
|
||||
for (int i = 0; i < WriteDescriptorCount; i++)
|
||||
{
|
||||
LocationCount = ByteOperations.ReadUInt32(StoreHeader, WriteDescriptorEntryOffset + 0x00);
|
||||
ChunkCount = ByteOperations.ReadInt32(StoreHeader, WriteDescriptorEntryOffset + 0x04);
|
||||
|
||||
for (int j = 0; j < LocationCount; j++)
|
||||
{
|
||||
DiskAccessMethod = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x08 + (j * 0x08)));
|
||||
ChunkIndex = ByteOperations.ReadInt32(StoreHeader, (UInt32)(WriteDescriptorEntryOffset + 0x0C + (j * 0x08)));
|
||||
|
||||
if (DiskAccessMethod == 0) // 0 = From begin, 2 = From end. We ignore chunks at end of disk. These contain secondairy GPT.
|
||||
{
|
||||
for (int k = 0; k < ChunkCount; k++)
|
||||
{
|
||||
ChunkIndexes[ChunkIndex + k] = FFUChunkIndex + k;
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteDescriptorEntryOffset += 8 + (LocationCount * 0x08);
|
||||
FFUChunkIndex += ChunkCount;
|
||||
}
|
||||
|
||||
byte[] GPTBuffer = GetSectors(0x01, 0x21);
|
||||
GPT = new GPT(GPTBuffer);
|
||||
|
||||
HeaderSize = (UInt64)(SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length);
|
||||
|
||||
TotalChunkCount = (UInt64)FFUChunkIndex;
|
||||
PayloadSize = TotalChunkCount * (UInt64)ChunkSize;
|
||||
TotalSize = HeaderSize + PayloadSize;
|
||||
|
||||
if (TotalSize != (UInt64)FFUFile.Length)
|
||||
{
|
||||
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + "Expected size: " + TotalSize.ToString() + ". Actual size: " + FFUFile.Length + ".");
|
||||
}
|
||||
}
|
||||
catch (WPinternalsException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
throw new WPinternalsException("Bad FFU file", "Bad FFU file: " + Path + "." + Environment.NewLine + Ex.Message, Ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
CloseFile();
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool IsFFU(string FileName)
|
||||
{
|
||||
bool Result = false;
|
||||
|
||||
FileStream FFUFile = new(FileName, FileMode.Open, FileAccess.Read);
|
||||
|
||||
byte[] Signature = new byte[0x10];
|
||||
FFUFile.Read(Signature, 0, 0x10);
|
||||
|
||||
Result = ByteOperations.ReadAsciiString(Signature, 0x04, 0x0C) == "SignedImage ";
|
||||
|
||||
FFUFile.Close();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
private void OpenFile()
|
||||
{
|
||||
if (FFUFile == null)
|
||||
{
|
||||
FFUFile = new FileStream(Path, FileMode.Open, FileAccess.Read);
|
||||
FileOpenCount = 0;
|
||||
}
|
||||
FileOpenCount++;
|
||||
}
|
||||
|
||||
private void CloseFile()
|
||||
{
|
||||
FileOpenCount--;
|
||||
if (FileOpenCount == 0)
|
||||
{
|
||||
FFUFile.Close();
|
||||
FFUFile = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void FileSeek(long Position)
|
||||
{
|
||||
// https://social.msdn.microsoft.com/Forums/vstudio/en-US/2e67ca57-3556-4275-accd-58b7df30d424/unnecessary-filestreamseek-and-setting-filestreamposition-has-huge-effect-on-performance?forum=csharpgeneral
|
||||
|
||||
if (FFUFile != null && FFUFile.Position != Position)
|
||||
{
|
||||
FFUFile.Seek(Position, SeekOrigin.Begin);
|
||||
}
|
||||
}
|
||||
|
||||
internal UInt32 RoundUpToChunks(UInt32 Size)
|
||||
{
|
||||
if ((Size % ChunkSize) > 0)
|
||||
{
|
||||
return (UInt32)(((Size / ChunkSize) + 1) * ChunkSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
|
||||
internal UInt32 RoundDownToChunks(UInt32 Size)
|
||||
{
|
||||
if ((Size % ChunkSize) > 0)
|
||||
{
|
||||
return (UInt32)(Size / ChunkSize * ChunkSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Size;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] GetSectors(int StartSector, int SectorCount)
|
||||
{
|
||||
int FirstChunk = GetChunkIndexFromSectorIndex(StartSector);
|
||||
int LastChunk = GetChunkIndexFromSectorIndex(StartSector + SectorCount - 1);
|
||||
|
||||
byte[] Buffer = new byte[ChunkSize];
|
||||
|
||||
OpenFile();
|
||||
|
||||
byte[] Result = new byte[SectorCount * 0x200];
|
||||
|
||||
int ResultOffset = 0;
|
||||
|
||||
for (int j = FirstChunk; j <= LastChunk; j++)
|
||||
{
|
||||
GetChunk(Buffer, j);
|
||||
|
||||
int FirstSector = 0;
|
||||
int LastSector = (ChunkSize / 0x200) - 1;
|
||||
|
||||
if (j == FirstChunk)
|
||||
{
|
||||
FirstSector = GetSectorNumberInChunkFromSectorIndex(StartSector);
|
||||
}
|
||||
|
||||
if (j == LastChunk)
|
||||
{
|
||||
LastSector = GetSectorNumberInChunkFromSectorIndex(StartSector + SectorCount - 1);
|
||||
}
|
||||
|
||||
int Offset = FirstSector * 0x200;
|
||||
int Size = (LastSector - FirstSector + 1) * 0x200;
|
||||
|
||||
System.Buffer.BlockCopy(Buffer, Offset, Result, ResultOffset, Size);
|
||||
|
||||
ResultOffset += Size;
|
||||
}
|
||||
|
||||
CloseFile();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal byte[] GetPartition(string Name)
|
||||
{
|
||||
Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (Target == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
return GetSectors((int)Target.FirstSector, (int)(Target.LastSector - Target.FirstSector + 1));
|
||||
}
|
||||
|
||||
internal void WritePartition(string Name, string FilePath, bool Compress = false)
|
||||
{
|
||||
WritePartition(Name, FilePath, null, null, Compress);
|
||||
}
|
||||
|
||||
internal void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, bool Compress = false)
|
||||
{
|
||||
WritePartition(Name, FilePath, ProgressUpdateCallback, null, Compress);
|
||||
}
|
||||
|
||||
internal void WritePartition(string Name, string FilePath, ProgressUpdater UpdaterPerSector, bool Compress = false)
|
||||
{
|
||||
WritePartition(Name, FilePath, null, UpdaterPerSector, Compress);
|
||||
}
|
||||
|
||||
private void WritePartition(string Name, string FilePath, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, bool Compress = false)
|
||||
{
|
||||
Partition Target = GPT.Partitions.Find(p => string.Equals(p.Name, Name, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (Target == null)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
int FirstChunk = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
|
||||
int LastChunk = GetChunkIndexFromSectorIndex((int)Target.LastSector);
|
||||
|
||||
ProgressUpdater Updater = UpdaterPerSector;
|
||||
if ((Updater == null) && (ProgressUpdateCallback != null))
|
||||
{
|
||||
Updater = new ProgressUpdater(Target.LastSector - Target.FirstSector + 1, ProgressUpdateCallback);
|
||||
}
|
||||
|
||||
byte[] Buffer = new byte[ChunkSize];
|
||||
|
||||
OpenFile();
|
||||
|
||||
FileStream OutputFile = new(FilePath, FileMode.Create, FileAccess.Write);
|
||||
Stream OutStream = OutputFile;
|
||||
|
||||
// We use gzip compression
|
||||
//
|
||||
// LZMA is about 60 times slower (compression is twice as good, but compressed size is already really small, so it doesnt matter much)
|
||||
// OutStream = new LZMACompressionStream(OutputFile, System.IO.Compression.CompressionMode.Compress, false);
|
||||
//
|
||||
// DeflateStream is a raw compression stream without recognizable header
|
||||
// Deflate has almost no performance penalty
|
||||
// OutStream = new DeflateStream(OutputFile, CompressionLevel.Optimal, false);
|
||||
//
|
||||
// GZip can be recognized. It always starts with 1F 8B 08 (1F 8B is the magic value, 08 is the Deflate compression method)
|
||||
// With GZip compression, dump time goes from 1m to 1m37s. So that doesnt matter much.
|
||||
if (Compress)
|
||||
{
|
||||
OutStream = new CompressedStream(OutputFile, (Target.LastSector - Target.FirstSector + 1) * 0x200);
|
||||
}
|
||||
|
||||
for (int j = FirstChunk; j <= LastChunk; j++)
|
||||
{
|
||||
GetChunk(Buffer, j);
|
||||
|
||||
int FirstSector = 0;
|
||||
int LastSector = (ChunkSize / 0x200) - 1;
|
||||
|
||||
if (j == FirstChunk)
|
||||
{
|
||||
FirstSector = GetSectorNumberInChunkFromSectorIndex((int)Target.FirstSector);
|
||||
}
|
||||
|
||||
if (j == LastChunk)
|
||||
{
|
||||
LastSector = GetSectorNumberInChunkFromSectorIndex((int)Target.LastSector);
|
||||
}
|
||||
|
||||
int Offset = FirstSector * 0x200;
|
||||
int Size = (LastSector - FirstSector + 1) * 0x200;
|
||||
|
||||
OutStream.Write(Buffer, Offset, Size);
|
||||
|
||||
Updater?.IncreaseProgress((UInt64)(ChunkSize / 0x200));
|
||||
}
|
||||
|
||||
OutStream.Close();
|
||||
|
||||
CloseFile();
|
||||
}
|
||||
|
||||
private byte[] GetChunk(int ChunkIndex)
|
||||
{
|
||||
long BaseOffset = (long)SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
|
||||
if (ChunkIndexes[ChunkIndex] == null)
|
||||
{
|
||||
return new byte[ChunkSize];
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenFile();
|
||||
FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize));
|
||||
byte[] Chunk = new byte[ChunkSize];
|
||||
FFUFile.Read(Chunk, 0, ChunkSize);
|
||||
CloseFile();
|
||||
return Chunk;
|
||||
}
|
||||
}
|
||||
|
||||
private void GetChunk(byte[] Chunk, int ChunkIndex)
|
||||
{
|
||||
long BaseOffset = SecurityHeader.Length + ImageHeader.Length + StoreHeader.Length;
|
||||
if (ChunkIndexes[ChunkIndex] == null)
|
||||
{
|
||||
Array.Clear(Chunk, 0, ChunkSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
OpenFile();
|
||||
FileSeek(BaseOffset + ((long)ChunkIndexes[ChunkIndex] * ChunkSize));
|
||||
FFUFile.Read(Chunk, 0, ChunkSize);
|
||||
CloseFile();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetChunkIndexFromSectorIndex(int SectorIndex)
|
||||
{
|
||||
int SectorsPerChunk = ChunkSize / 0x200;
|
||||
return SectorIndex / SectorsPerChunk;
|
||||
}
|
||||
|
||||
private int GetSectorNumberInChunkFromSectorIndex(int SectorIndex)
|
||||
{
|
||||
int SectorsPerChunk = ChunkSize / 0x200;
|
||||
return SectorIndex % SectorsPerChunk;
|
||||
}
|
||||
|
||||
internal bool IsPartitionPresentInFFU(string PartitionName)
|
||||
{
|
||||
Partition Target = GPT.GetPartition(PartitionName);
|
||||
if (Target == null)
|
||||
{
|
||||
throw new InvalidOperationException("Partitionname is not found!");
|
||||
}
|
||||
|
||||
int ChunkIndex = GetChunkIndexFromSectorIndex((int)Target.FirstSector);
|
||||
return ChunkIndexes[ChunkIndex] != null;
|
||||
}
|
||||
|
||||
private int GetChunkIndexFromSectorIndex(ulong p)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal string GetFirmwareVersion()
|
||||
{
|
||||
string Result = null;
|
||||
|
||||
Partition Plat = GPT.GetPartition("PLAT");
|
||||
if (Plat != null)
|
||||
{
|
||||
byte[] Data = GetPartition("PLAT");
|
||||
uint? Offset = ByteOperations.FindAscii(Data, "SWVERSION=");
|
||||
if (Offset != null)
|
||||
{
|
||||
uint Start = (uint)Offset + 10;
|
||||
uint Length = (uint)ByteOperations.FindPattern(Data, Start, 0x100, [0x00], null, null) - Start;
|
||||
uint? Offset0D = ByteOperations.FindPattern(Data, Start, 0x100, [0x0D], null, null);
|
||||
if ((Offset0D != null) && (Offset0D < (Start + Length)))
|
||||
{
|
||||
Length = (uint)Offset0D - Start;
|
||||
}
|
||||
|
||||
Result = ByteOperations.ReadAsciiString(Data, Start, Length);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal string GetOSVersion()
|
||||
{
|
||||
byte[] efiesp = GetPartition("EFIESP");
|
||||
MemoryStream s = new(efiesp);
|
||||
DiscUtils.Fat.FatFileSystem fs = new(s);
|
||||
Stream mss = fs.OpenFile(@"\Windows\System32\Boot\mobilestartup.efi", FileMode.Open, FileAccess.Read);
|
||||
MemoryStream msms = new();
|
||||
mss.CopyTo(msms);
|
||||
byte[] mobilestartup = msms.ToArray();
|
||||
Version OSVersion = PE.GetProductVersion(mobilestartup);
|
||||
s.Close();
|
||||
|
||||
return OSVersion.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,312 +1,312 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.
|
||||
|
||||
// SevenZip LZMA SDK: http://www.7-zip.org/download.html
|
||||
// Usage: http://stackoverflow.com/questions/7646328/how-to-use-the-7z-sdk-to-compress-and-decompress-a-file
|
||||
|
||||
using SevenZip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class LZMA
|
||||
{
|
||||
internal static byte[] Decompress(byte[] Input, UInt32 Offset, UInt32 InputSize)
|
||||
{
|
||||
byte[] Properties = new byte[5];
|
||||
Buffer.BlockCopy(Input, (int)Offset, Properties, 0, 5);
|
||||
|
||||
UInt64 OutputSize = ByteOperations.ReadUInt64(Input, Offset + 5);
|
||||
|
||||
SevenZip.Compression.LZMA.Decoder Coder = new();
|
||||
Coder.SetDecoderProperties(Properties);
|
||||
|
||||
MemoryStream InStream = new(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D);
|
||||
|
||||
byte[] Output = new byte[OutputSize];
|
||||
MemoryStream OutStream = new(Output, true);
|
||||
|
||||
Coder.Code(InStream, OutStream, (Int64)InputSize - 0x0D, (Int64)OutputSize, null);
|
||||
|
||||
OutStream.Flush();
|
||||
OutStream.Close();
|
||||
InStream.Close();
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal static byte[] Compress(byte[] Input, UInt32 Offset, UInt32 InputSize)
|
||||
{
|
||||
SevenZip.Compression.LZMA.Encoder Coder = new();
|
||||
|
||||
MemoryStream InStream = new(Input, (int)Offset, (int)InputSize);
|
||||
MemoryStream OutStream = new();
|
||||
|
||||
// Write the encoder properties
|
||||
Coder.WriteCoderProperties(OutStream);
|
||||
|
||||
// Write the decompressed file size
|
||||
OutStream.Write(BitConverter.GetBytes(InStream.Length), 0, 8);
|
||||
|
||||
// Encode the file
|
||||
Coder.Code(InStream, OutStream, InputSize, -1, null);
|
||||
|
||||
byte[] Output = new byte[OutStream.Length];
|
||||
Buffer.BlockCopy(OutStream.GetBuffer(), 0, Output, 0, (int)OutStream.Length);
|
||||
|
||||
OutStream.Flush();
|
||||
OutStream.Close();
|
||||
InStream.Close();
|
||||
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
|
||||
public class LZMACompressionStream : Stream
|
||||
{
|
||||
private readonly SevenZip.Compression.LZMA.Encoder Encoder = null;
|
||||
private readonly SevenZip.Compression.LZMA.Decoder Decoder = null;
|
||||
private readonly PumpStream BufferStream;
|
||||
private readonly Stream stream;
|
||||
private readonly bool LeaveOpen;
|
||||
private readonly Thread WorkThread;
|
||||
private readonly CancellationTokenSource source;
|
||||
private readonly CancellationToken token;
|
||||
|
||||
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen, int DictionarySize, int PosStateBits,
|
||||
int LitContextBits, int LitPosBits, int Algorithm, int NumFastBytes, string MatchFinder, bool EndMarker)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.LeaveOpen = LeaveOpen;
|
||||
BufferStream = new PumpStream();
|
||||
source = new CancellationTokenSource();
|
||||
token = source.Token;
|
||||
|
||||
if (mode == CompressionMode.Compress)
|
||||
{
|
||||
Encoder = new SevenZip.Compression.LZMA.Encoder();
|
||||
if (DictionarySize != 0)
|
||||
{
|
||||
Encoder.SetCoderProperties(
|
||||
new CoderPropID[8] {CoderPropID.DictionarySize, CoderPropID.PosStateBits, CoderPropID.LitContextBits,
|
||||
CoderPropID.LitPosBits, CoderPropID.Algorithm, CoderPropID.NumFastBytes, CoderPropID.MatchFinder, CoderPropID.EndMarker},
|
||||
new object[8] { DictionarySize, PosStateBits, LitContextBits, LitPosBits, Algorithm, NumFastBytes, MatchFinder, EndMarker });
|
||||
}
|
||||
|
||||
Encoder.WriteCoderProperties(stream);
|
||||
WorkThread = new Thread(new ThreadStart(Encode));
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] DecoderProperties = new byte[5];
|
||||
stream.Read(DecoderProperties, 0, 5);
|
||||
Decoder = new SevenZip.Compression.LZMA.Decoder();
|
||||
Decoder.SetDecoderProperties(DecoderProperties);
|
||||
WorkThread = new Thread(new ThreadStart(Decode));
|
||||
}
|
||||
|
||||
WorkThread.Start();
|
||||
}
|
||||
|
||||
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen)
|
||||
: this(stream, mode, LeaveOpen, 0, 0, 0, 0, 0, 0, null, false)
|
||||
{
|
||||
}
|
||||
|
||||
private void Encode()
|
||||
{
|
||||
Encoder.Code(BufferStream, stream, -1, -1, null, token);
|
||||
if (!LeaveOpen)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void Decode()
|
||||
{
|
||||
Decoder.Code(stream, BufferStream, -1, -1, null, token);
|
||||
BufferStream.Close();
|
||||
if (!LeaveOpen)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (Encoder != null)
|
||||
{
|
||||
BufferStream.Close();
|
||||
}
|
||||
else if (WorkThread.IsAlive)
|
||||
{
|
||||
source?.Cancel();
|
||||
WorkThread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return BufferStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
BufferStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return Decoder != null; } }
|
||||
public override bool CanSeek { get { return false; } }
|
||||
public override bool CanWrite { get { return Encoder != null; } }
|
||||
public override void Flush() { }
|
||||
public override long Length { get { return 0; } }
|
||||
public override long Position { get { return 0; } set { } }
|
||||
public override long Seek(long offset, SeekOrigin origin) { return 0; }
|
||||
public override void SetLength(long value) { }
|
||||
}
|
||||
|
||||
public class PumpStream : Stream
|
||||
{
|
||||
private readonly Queue<byte[]> BufferQueue;
|
||||
private int BufferOffset;
|
||||
private readonly long MaxBufferSize;
|
||||
private long BufferSize;
|
||||
private bool Closed;
|
||||
private bool EOF;
|
||||
|
||||
public PumpStream(long MaxBufferSize, int ReadTimeout, int WriteTimeout)
|
||||
{
|
||||
this.MaxBufferSize = MaxBufferSize;
|
||||
this.ReadTimeout = ReadTimeout;
|
||||
this.WriteTimeout = WriteTimeout;
|
||||
BufferQueue = new Queue<byte[]>();
|
||||
BufferOffset = 0;
|
||||
BufferSize = 0;
|
||||
Closed = false;
|
||||
EOF = false;
|
||||
}
|
||||
|
||||
public PumpStream()
|
||||
: this(16777216, Timeout.Infinite, Timeout.Infinite)
|
||||
{
|
||||
}
|
||||
|
||||
public new void Dispose()
|
||||
{
|
||||
BufferQueue.Clear();
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Closed = true;
|
||||
lock (BufferQueue)
|
||||
{
|
||||
Monitor.Pulse(BufferQueue);
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int BytesRead = 0;
|
||||
lock (BufferQueue)
|
||||
{
|
||||
while (BytesRead < count && !EOF)
|
||||
{
|
||||
if (BufferQueue.Count > 0)
|
||||
{
|
||||
byte[] b = BufferQueue.Peek();
|
||||
|
||||
if ((b.Length - BufferOffset) <= (count - BytesRead))
|
||||
{
|
||||
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, b.Length - BufferOffset);
|
||||
|
||||
BufferQueue.Dequeue();
|
||||
BufferSize -= b.Length;
|
||||
Monitor.Pulse(BufferQueue);
|
||||
|
||||
BytesRead += b.Length - BufferOffset;
|
||||
BufferOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, count - BytesRead);
|
||||
|
||||
BufferOffset += count - BytesRead;
|
||||
BytesRead += count - BytesRead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Closed)
|
||||
{
|
||||
if (!Monitor.Wait(BufferQueue, ReadTimeout))
|
||||
{
|
||||
throw new IOException("Could not read from stream: Timeout expired waiting for data to be written.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EOF = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BytesRead;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
lock (BufferQueue)
|
||||
{
|
||||
while (BufferSize >= MaxBufferSize)
|
||||
{
|
||||
if (!Monitor.Wait(BufferQueue, WriteTimeout))
|
||||
{
|
||||
throw new IOException("Could not write to stream: Timeout expired waiting for data to be read.");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] b = new byte[count];
|
||||
Array.Copy(buffer, offset, b, 0, count);
|
||||
BufferQueue.Enqueue(b);
|
||||
BufferSize += b.Length;
|
||||
|
||||
Monitor.Pulse(BufferQueue);
|
||||
}
|
||||
}
|
||||
|
||||
public override int ReadTimeout { get; set; }
|
||||
public override int WriteTimeout { get; set; }
|
||||
public override bool CanRead { get { return true; } }
|
||||
public override bool CanSeek { get { return false; } }
|
||||
public override bool CanWrite { get { return true; } }
|
||||
public override void Flush() { }
|
||||
public override long Length { get { return 0; } }
|
||||
public override long Position { get { return 0; } set { } }
|
||||
public override long Seek(long offset, SeekOrigin origin) { return 0; }
|
||||
public override void SetLength(long value) { }
|
||||
}
|
||||
}
|
||||
// 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.
|
||||
|
||||
// SevenZip LZMA SDK: http://www.7-zip.org/download.html
|
||||
// Usage: http://stackoverflow.com/questions/7646328/how-to-use-the-7z-sdk-to-compress-and-decompress-a-file
|
||||
|
||||
using SevenZip;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class LZMA
|
||||
{
|
||||
internal static byte[] Decompress(byte[] Input, UInt32 Offset, UInt32 InputSize)
|
||||
{
|
||||
byte[] Properties = new byte[5];
|
||||
Buffer.BlockCopy(Input, (int)Offset, Properties, 0, 5);
|
||||
|
||||
UInt64 OutputSize = ByteOperations.ReadUInt64(Input, Offset + 5);
|
||||
|
||||
SevenZip.Compression.LZMA.Decoder Coder = new();
|
||||
Coder.SetDecoderProperties(Properties);
|
||||
|
||||
MemoryStream InStream = new(Input, (int)Offset + 0x0D, (int)InputSize - 0x0D);
|
||||
|
||||
byte[] Output = new byte[OutputSize];
|
||||
MemoryStream OutStream = new(Output, true);
|
||||
|
||||
Coder.Code(InStream, OutStream, (Int64)InputSize - 0x0D, (Int64)OutputSize, null);
|
||||
|
||||
OutStream.Flush();
|
||||
OutStream.Close();
|
||||
InStream.Close();
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
internal static byte[] Compress(byte[] Input, UInt32 Offset, UInt32 InputSize)
|
||||
{
|
||||
SevenZip.Compression.LZMA.Encoder Coder = new();
|
||||
|
||||
MemoryStream InStream = new(Input, (int)Offset, (int)InputSize);
|
||||
MemoryStream OutStream = new();
|
||||
|
||||
// Write the encoder properties
|
||||
Coder.WriteCoderProperties(OutStream);
|
||||
|
||||
// Write the decompressed file size
|
||||
OutStream.Write(BitConverter.GetBytes(InStream.Length), 0, 8);
|
||||
|
||||
// Encode the file
|
||||
Coder.Code(InStream, OutStream, InputSize, -1, null);
|
||||
|
||||
byte[] Output = new byte[OutStream.Length];
|
||||
Buffer.BlockCopy(OutStream.GetBuffer(), 0, Output, 0, (int)OutStream.Length);
|
||||
|
||||
OutStream.Flush();
|
||||
OutStream.Close();
|
||||
InStream.Close();
|
||||
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
|
||||
public class LZMACompressionStream : Stream
|
||||
{
|
||||
private readonly SevenZip.Compression.LZMA.Encoder Encoder = null;
|
||||
private readonly SevenZip.Compression.LZMA.Decoder Decoder = null;
|
||||
private readonly PumpStream BufferStream;
|
||||
private readonly Stream stream;
|
||||
private readonly bool LeaveOpen;
|
||||
private readonly Thread WorkThread;
|
||||
private readonly CancellationTokenSource source;
|
||||
private readonly CancellationToken token;
|
||||
|
||||
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen, int DictionarySize, int PosStateBits,
|
||||
int LitContextBits, int LitPosBits, int Algorithm, int NumFastBytes, string MatchFinder, bool EndMarker)
|
||||
{
|
||||
this.stream = stream;
|
||||
this.LeaveOpen = LeaveOpen;
|
||||
BufferStream = new PumpStream();
|
||||
source = new CancellationTokenSource();
|
||||
token = source.Token;
|
||||
|
||||
if (mode == CompressionMode.Compress)
|
||||
{
|
||||
Encoder = new SevenZip.Compression.LZMA.Encoder();
|
||||
if (DictionarySize != 0)
|
||||
{
|
||||
Encoder.SetCoderProperties(
|
||||
[CoderPropID.DictionarySize, CoderPropID.PosStateBits, CoderPropID.LitContextBits,
|
||||
CoderPropID.LitPosBits, CoderPropID.Algorithm, CoderPropID.NumFastBytes, CoderPropID.MatchFinder, CoderPropID.EndMarker],
|
||||
[DictionarySize, PosStateBits, LitContextBits, LitPosBits, Algorithm, NumFastBytes, MatchFinder, EndMarker]);
|
||||
}
|
||||
|
||||
Encoder.WriteCoderProperties(stream);
|
||||
WorkThread = new Thread(new ThreadStart(Encode));
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] DecoderProperties = new byte[5];
|
||||
stream.Read(DecoderProperties, 0, 5);
|
||||
Decoder = new SevenZip.Compression.LZMA.Decoder();
|
||||
Decoder.SetDecoderProperties(DecoderProperties);
|
||||
WorkThread = new Thread(new ThreadStart(Decode));
|
||||
}
|
||||
|
||||
WorkThread.Start();
|
||||
}
|
||||
|
||||
public LZMACompressionStream(Stream stream, CompressionMode mode, bool LeaveOpen)
|
||||
: this(stream, mode, LeaveOpen, 0, 0, 0, 0, 0, 0, null, false)
|
||||
{
|
||||
}
|
||||
|
||||
private void Encode()
|
||||
{
|
||||
Encoder.Code(BufferStream, stream, -1, -1, null, token);
|
||||
if (!LeaveOpen)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void Decode()
|
||||
{
|
||||
Decoder.Code(stream, BufferStream, -1, -1, null, token);
|
||||
BufferStream.Close();
|
||||
if (!LeaveOpen)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
if (Encoder != null)
|
||||
{
|
||||
BufferStream.Close();
|
||||
}
|
||||
else if (WorkThread.IsAlive)
|
||||
{
|
||||
source?.Cancel();
|
||||
WorkThread.Join();
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return BufferStream.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
BufferStream.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override bool CanRead { get { return Decoder != null; } }
|
||||
public override bool CanSeek { get { return false; } }
|
||||
public override bool CanWrite { get { return Encoder != null; } }
|
||||
public override void Flush() { }
|
||||
public override long Length { get { return 0; } }
|
||||
public override long Position { get { return 0; } set { } }
|
||||
public override long Seek(long offset, SeekOrigin origin) { return 0; }
|
||||
public override void SetLength(long value) { }
|
||||
}
|
||||
|
||||
public class PumpStream : Stream
|
||||
{
|
||||
private readonly Queue<byte[]> BufferQueue;
|
||||
private int BufferOffset;
|
||||
private readonly long MaxBufferSize;
|
||||
private long BufferSize;
|
||||
private bool Closed;
|
||||
private bool EOF;
|
||||
|
||||
public PumpStream(long MaxBufferSize, int ReadTimeout, int WriteTimeout)
|
||||
{
|
||||
this.MaxBufferSize = MaxBufferSize;
|
||||
this.ReadTimeout = ReadTimeout;
|
||||
this.WriteTimeout = WriteTimeout;
|
||||
BufferQueue = new Queue<byte[]>();
|
||||
BufferOffset = 0;
|
||||
BufferSize = 0;
|
||||
Closed = false;
|
||||
EOF = false;
|
||||
}
|
||||
|
||||
public PumpStream()
|
||||
: this(16777216, Timeout.Infinite, Timeout.Infinite)
|
||||
{
|
||||
}
|
||||
|
||||
public new void Dispose()
|
||||
{
|
||||
BufferQueue.Clear();
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Closed = true;
|
||||
lock (BufferQueue)
|
||||
{
|
||||
Monitor.Pulse(BufferQueue);
|
||||
}
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
int BytesRead = 0;
|
||||
lock (BufferQueue)
|
||||
{
|
||||
while (BytesRead < count && !EOF)
|
||||
{
|
||||
if (BufferQueue.Count > 0)
|
||||
{
|
||||
byte[] b = BufferQueue.Peek();
|
||||
|
||||
if ((b.Length - BufferOffset) <= (count - BytesRead))
|
||||
{
|
||||
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, b.Length - BufferOffset);
|
||||
|
||||
BufferQueue.Dequeue();
|
||||
BufferSize -= b.Length;
|
||||
Monitor.Pulse(BufferQueue);
|
||||
|
||||
BytesRead += b.Length - BufferOffset;
|
||||
BufferOffset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Copy(b, BufferOffset, buffer, offset + BytesRead, count - BytesRead);
|
||||
|
||||
BufferOffset += count - BytesRead;
|
||||
BytesRead += count - BytesRead;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!Closed)
|
||||
{
|
||||
if (!Monitor.Wait(BufferQueue, ReadTimeout))
|
||||
{
|
||||
throw new IOException("Could not read from stream: Timeout expired waiting for data to be written.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EOF = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BytesRead;
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
lock (BufferQueue)
|
||||
{
|
||||
while (BufferSize >= MaxBufferSize)
|
||||
{
|
||||
if (!Monitor.Wait(BufferQueue, WriteTimeout))
|
||||
{
|
||||
throw new IOException("Could not write to stream: Timeout expired waiting for data to be read.");
|
||||
}
|
||||
}
|
||||
|
||||
byte[] b = new byte[count];
|
||||
Array.Copy(buffer, offset, b, 0, count);
|
||||
BufferQueue.Enqueue(b);
|
||||
BufferSize += b.Length;
|
||||
|
||||
Monitor.Pulse(BufferQueue);
|
||||
}
|
||||
}
|
||||
|
||||
public override int ReadTimeout { get; set; }
|
||||
public override int WriteTimeout { get; set; }
|
||||
public override bool CanRead { get { return true; } }
|
||||
public override bool CanSeek { get { return false; } }
|
||||
public override bool CanWrite { get { return true; } }
|
||||
public override void Flush() { }
|
||||
public override long Length { get { return 0; } }
|
||||
public override long Position { get { return 0; } set { } }
|
||||
public override long Seek(long offset, SeekOrigin origin) { return 0; }
|
||||
public override void SetLength(long value) { }
|
||||
}
|
||||
}
|
||||
@@ -1,302 +1,302 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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 Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
[Flags]
|
||||
internal enum TokenAccessLevels
|
||||
{
|
||||
AssignPrimary = 0x00000001,
|
||||
Duplicate = 0x00000002,
|
||||
Impersonate = 0x00000004,
|
||||
Query = 0x00000008,
|
||||
QuerySource = 0x00000010,
|
||||
AdjustPrivileges = 0x00000020,
|
||||
AdjustGroups = 0x00000040,
|
||||
AdjustDefault = 0x00000080,
|
||||
AdjustSessionId = 0x00000100,
|
||||
|
||||
Read = 0x00020000 | Query,
|
||||
|
||||
Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,
|
||||
|
||||
AllAccess = 0x000F0000 |
|
||||
AssignPrimary |
|
||||
Duplicate |
|
||||
Impersonate |
|
||||
Query |
|
||||
QuerySource |
|
||||
AdjustPrivileges |
|
||||
AdjustGroups |
|
||||
AdjustDefault |
|
||||
AdjustSessionId,
|
||||
|
||||
MaximumAllowed = 0x02000000
|
||||
}
|
||||
|
||||
internal enum SecurityImpersonationLevel
|
||||
{
|
||||
Anonymous = 0,
|
||||
Identification = 1,
|
||||
Impersonation = 2,
|
||||
Delegation = 3,
|
||||
}
|
||||
|
||||
internal enum TokenType
|
||||
{
|
||||
Primary = 1,
|
||||
Impersonation = 2,
|
||||
}
|
||||
|
||||
internal enum EMoveMethod : uint
|
||||
{
|
||||
Begin = 0,
|
||||
Current = 1,
|
||||
End = 2
|
||||
}
|
||||
|
||||
internal sealed class NativeMethods
|
||||
{
|
||||
internal const uint SE_PRIVILEGE_DISABLED = 0x00000000;
|
||||
internal const uint SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct LUID
|
||||
{
|
||||
internal uint LowPart;
|
||||
internal uint HighPart;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct LUID_AND_ATTRIBUTES
|
||||
{
|
||||
internal LUID Luid;
|
||||
internal uint Attributes;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct TOKEN_PRIVILEGE
|
||||
{
|
||||
internal uint PrivilegeCount;
|
||||
internal LUID_AND_ATTRIBUTES Privilege;
|
||||
}
|
||||
|
||||
internal const string ADVAPI32 = "advapi32.dll";
|
||||
internal const string KERNEL32 = "kernel32.dll";
|
||||
|
||||
internal const int ERROR_SUCCESS = 0x0;
|
||||
internal const int ERROR_ACCESS_DENIED = 0x5;
|
||||
internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
|
||||
internal const int ERROR_NO_TOKEN = 0x3f0;
|
||||
internal const int ERROR_NOT_ALL_ASSIGNED = 0x514;
|
||||
internal const int ERROR_NO_SUCH_PRIVILEGE = 0x521;
|
||||
internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;
|
||||
|
||||
[DllImport(
|
||||
KERNEL32,
|
||||
SetLastError = true)]
|
||||
internal static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern bool AdjustTokenPrivileges(
|
||||
[In] SafeTokenHandle TokenHandle,
|
||||
[In] bool DisableAllPrivileges,
|
||||
[In] ref TOKEN_PRIVILEGE NewState,
|
||||
[In] uint BufferLength,
|
||||
[In, Out] ref TOKEN_PRIVILEGE PreviousState,
|
||||
[In, Out] ref uint ReturnLength);
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool RevertToSelf();
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
EntryPoint = "LookupPrivilegeValueW",
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool LookupPrivilegeValue(
|
||||
[In] string lpSystemName,
|
||||
[In] string lpName,
|
||||
[In, Out] ref LUID Luid);
|
||||
|
||||
[DllImport(
|
||||
KERNEL32,
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport(
|
||||
KERNEL32,
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
IntPtr GetCurrentThread();
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool OpenProcessToken(
|
||||
[In] IntPtr ProcessToken,
|
||||
[In] TokenAccessLevels DesiredAccess,
|
||||
[In, Out] ref SafeTokenHandle TokenHandle);
|
||||
|
||||
[DllImport
|
||||
(ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool OpenThreadToken(
|
||||
[In] IntPtr ThreadToken,
|
||||
[In] TokenAccessLevels DesiredAccess,
|
||||
[In] bool OpenAsSelf,
|
||||
[In, Out] ref SafeTokenHandle TokenHandle);
|
||||
|
||||
[DllImport
|
||||
(ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool DuplicateTokenEx(
|
||||
[In] SafeTokenHandle ExistingToken,
|
||||
[In] TokenAccessLevels DesiredAccess,
|
||||
[In] IntPtr TokenAttributes,
|
||||
[In] SecurityImpersonationLevel ImpersonationLevel,
|
||||
[In] TokenType TokenType,
|
||||
[In, Out] ref SafeTokenHandle NewToken);
|
||||
|
||||
[DllImport
|
||||
(ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool SetThreadToken(
|
||||
[In] IntPtr Thread,
|
||||
[In] SafeTokenHandle Token);
|
||||
|
||||
internal const uint FILE_SHARE_READ = 0x00000001;
|
||||
internal const uint FILE_SHARE_WRITE = 0x00000002;
|
||||
internal const uint FILE_SHARE_DELETE = 0x00000004;
|
||||
internal const uint OPEN_EXISTING = 3;
|
||||
|
||||
internal const uint GENERIC_READ = 0x80000000;
|
||||
internal const uint GENERIC_WRITE = 0x40000000;
|
||||
|
||||
internal const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
|
||||
internal const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
|
||||
internal const uint FILE_READ_ATTRIBUTES = 0x0080;
|
||||
internal const uint FILE_WRITE_ATTRIBUTES = 0x0100;
|
||||
internal const uint ERROR_INSUFFICIENT_BUFFER = 122;
|
||||
internal const uint FILE_BEGIN = 0;
|
||||
internal const uint FSCTL_LOCK_VOLUME = 0x00090018;
|
||||
internal const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
|
||||
internal const uint FSCTL_UNLOCK_VOLUME = 0x00090022;
|
||||
internal const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
|
||||
internal const uint IOCTL_STORAGE_LOAD_MEDIA = 0x2D480C;
|
||||
|
||||
internal const Int32 INVALID_HANDLE_VALUE = -1;
|
||||
internal const Int32 FILE_ATTRIBUTE_NORMAL = 1;
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern uint SetFilePointer(
|
||||
[In] IntPtr hFile,
|
||||
[In] int lDistanceToMove,
|
||||
[In, Out] ref int lpDistanceToMoveHigh,
|
||||
[In] EMoveMethod dwMoveMethod);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern IntPtr CreateFile(
|
||||
string lpFileName,
|
||||
uint dwDesiredAccess,
|
||||
uint dwShareMode,
|
||||
IntPtr lpSecurityAttributes,
|
||||
uint dwCreationDisposition,
|
||||
uint dwFlagsAndAttributes,
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
|
||||
public static extern bool DeviceIoControl(
|
||||
IntPtr hDevice,
|
||||
uint IoControlCode,
|
||||
[In] object InBuffer,
|
||||
uint nInBufferSize,
|
||||
[Out] object OutBuffer,
|
||||
uint nOutBufferSize,
|
||||
ref uint pBytesReturned,
|
||||
IntPtr Overlapped
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool FlushFileBuffers(IntPtr hFile);
|
||||
|
||||
static NativeMethods()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeTokenHandle() : base(true) { }
|
||||
|
||||
// 0 is an Invalid Handle
|
||||
internal SafeTokenHandle(IntPtr handle)
|
||||
: base(true)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
internal static SafeTokenHandle InvalidHandle
|
||||
{
|
||||
get { return new SafeTokenHandle(IntPtr.Zero); }
|
||||
}
|
||||
|
||||
[DllImport(NativeMethods.KERNEL32, SetLastError = true),
|
||||
SuppressUnmanagedCodeSecurity]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
override protected bool ReleaseHandle()
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 Microsoft.Win32.SafeHandles;
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
[Flags]
|
||||
internal enum TokenAccessLevels
|
||||
{
|
||||
AssignPrimary = 0x00000001,
|
||||
Duplicate = 0x00000002,
|
||||
Impersonate = 0x00000004,
|
||||
Query = 0x00000008,
|
||||
QuerySource = 0x00000010,
|
||||
AdjustPrivileges = 0x00000020,
|
||||
AdjustGroups = 0x00000040,
|
||||
AdjustDefault = 0x00000080,
|
||||
AdjustSessionId = 0x00000100,
|
||||
|
||||
Read = 0x00020000 | Query,
|
||||
|
||||
Write = 0x00020000 | AdjustPrivileges | AdjustGroups | AdjustDefault,
|
||||
|
||||
AllAccess = 0x000F0000 |
|
||||
AssignPrimary |
|
||||
Duplicate |
|
||||
Impersonate |
|
||||
Query |
|
||||
QuerySource |
|
||||
AdjustPrivileges |
|
||||
AdjustGroups |
|
||||
AdjustDefault |
|
||||
AdjustSessionId,
|
||||
|
||||
MaximumAllowed = 0x02000000
|
||||
}
|
||||
|
||||
internal enum SecurityImpersonationLevel
|
||||
{
|
||||
Anonymous = 0,
|
||||
Identification = 1,
|
||||
Impersonation = 2,
|
||||
Delegation = 3,
|
||||
}
|
||||
|
||||
internal enum TokenType
|
||||
{
|
||||
Primary = 1,
|
||||
Impersonation = 2,
|
||||
}
|
||||
|
||||
internal enum EMoveMethod : uint
|
||||
{
|
||||
Begin = 0,
|
||||
Current = 1,
|
||||
End = 2
|
||||
}
|
||||
|
||||
internal sealed class NativeMethods
|
||||
{
|
||||
internal const uint SE_PRIVILEGE_DISABLED = 0x00000000;
|
||||
internal const uint SE_PRIVILEGE_ENABLED = 0x00000002;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct LUID
|
||||
{
|
||||
internal uint LowPart;
|
||||
internal uint HighPart;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct LUID_AND_ATTRIBUTES
|
||||
{
|
||||
internal LUID Luid;
|
||||
internal uint Attributes;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
internal struct TOKEN_PRIVILEGE
|
||||
{
|
||||
internal uint PrivilegeCount;
|
||||
internal LUID_AND_ATTRIBUTES Privilege;
|
||||
}
|
||||
|
||||
internal const string ADVAPI32 = "advapi32.dll";
|
||||
internal const string KERNEL32 = "kernel32.dll";
|
||||
|
||||
internal const int ERROR_SUCCESS = 0x0;
|
||||
internal const int ERROR_ACCESS_DENIED = 0x5;
|
||||
internal const int ERROR_NOT_ENOUGH_MEMORY = 0x8;
|
||||
internal const int ERROR_NO_TOKEN = 0x3f0;
|
||||
internal const int ERROR_NOT_ALL_ASSIGNED = 0x514;
|
||||
internal const int ERROR_NO_SUCH_PRIVILEGE = 0x521;
|
||||
internal const int ERROR_CANT_OPEN_ANONYMOUS = 0x543;
|
||||
|
||||
[DllImport(
|
||||
KERNEL32,
|
||||
SetLastError = true)]
|
||||
internal static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern bool AdjustTokenPrivileges(
|
||||
[In] SafeTokenHandle TokenHandle,
|
||||
[In] bool DisableAllPrivileges,
|
||||
[In] ref TOKEN_PRIVILEGE NewState,
|
||||
[In] uint BufferLength,
|
||||
[In, Out] ref TOKEN_PRIVILEGE PreviousState,
|
||||
[In, Out] ref uint ReturnLength);
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool RevertToSelf();
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
EntryPoint = "LookupPrivilegeValueW",
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool LookupPrivilegeValue(
|
||||
[In] string lpSystemName,
|
||||
[In] string lpName,
|
||||
[In, Out] ref LUID Luid);
|
||||
|
||||
[DllImport(
|
||||
KERNEL32,
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
IntPtr GetCurrentProcess();
|
||||
|
||||
[DllImport(
|
||||
KERNEL32,
|
||||
CharSet = CharSet.Auto,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
IntPtr GetCurrentThread();
|
||||
|
||||
[DllImport(
|
||||
ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool OpenProcessToken(
|
||||
[In] IntPtr ProcessToken,
|
||||
[In] TokenAccessLevels DesiredAccess,
|
||||
[In, Out] ref SafeTokenHandle TokenHandle);
|
||||
|
||||
[DllImport
|
||||
(ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool OpenThreadToken(
|
||||
[In] IntPtr ThreadToken,
|
||||
[In] TokenAccessLevels DesiredAccess,
|
||||
[In] bool OpenAsSelf,
|
||||
[In, Out] ref SafeTokenHandle TokenHandle);
|
||||
|
||||
[DllImport
|
||||
(ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool DuplicateTokenEx(
|
||||
[In] SafeTokenHandle ExistingToken,
|
||||
[In] TokenAccessLevels DesiredAccess,
|
||||
[In] IntPtr TokenAttributes,
|
||||
[In] SecurityImpersonationLevel ImpersonationLevel,
|
||||
[In] TokenType TokenType,
|
||||
[In, Out] ref SafeTokenHandle NewToken);
|
||||
|
||||
[DllImport
|
||||
(ADVAPI32,
|
||||
CharSet = CharSet.Unicode,
|
||||
SetLastError = true)]
|
||||
internal static extern
|
||||
bool SetThreadToken(
|
||||
[In] IntPtr Thread,
|
||||
[In] SafeTokenHandle Token);
|
||||
|
||||
internal const uint FILE_SHARE_READ = 0x00000001;
|
||||
internal const uint FILE_SHARE_WRITE = 0x00000002;
|
||||
internal const uint FILE_SHARE_DELETE = 0x00000004;
|
||||
internal const uint OPEN_EXISTING = 3;
|
||||
|
||||
internal const uint GENERIC_READ = 0x80000000;
|
||||
internal const uint GENERIC_WRITE = 0x40000000;
|
||||
|
||||
internal const uint FILE_FLAG_WRITE_THROUGH = 0x80000000;
|
||||
internal const uint FILE_FLAG_NO_BUFFERING = 0x20000000;
|
||||
internal const uint FILE_READ_ATTRIBUTES = 0x0080;
|
||||
internal const uint FILE_WRITE_ATTRIBUTES = 0x0100;
|
||||
internal const uint ERROR_INSUFFICIENT_BUFFER = 122;
|
||||
internal const uint FILE_BEGIN = 0;
|
||||
internal const uint FSCTL_LOCK_VOLUME = 0x00090018;
|
||||
internal const uint FSCTL_DISMOUNT_VOLUME = 0x00090020;
|
||||
internal const uint FSCTL_UNLOCK_VOLUME = 0x00090022;
|
||||
internal const uint IOCTL_STORAGE_EJECT_MEDIA = 0x2D4808;
|
||||
internal const uint IOCTL_STORAGE_LOAD_MEDIA = 0x2D480C;
|
||||
|
||||
internal const Int32 INVALID_HANDLE_VALUE = -1;
|
||||
internal const Int32 FILE_ATTRIBUTE_NORMAL = 1;
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
|
||||
internal static extern uint SetFilePointer(
|
||||
[In] IntPtr hFile,
|
||||
[In] int lDistanceToMove,
|
||||
[In, Out] ref int lpDistanceToMoveHigh,
|
||||
[In] EMoveMethod dwMoveMethod);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
internal static extern IntPtr CreateFile(
|
||||
string lpFileName,
|
||||
uint dwDesiredAccess,
|
||||
uint dwShareMode,
|
||||
IntPtr lpSecurityAttributes,
|
||||
uint dwCreationDisposition,
|
||||
uint dwFlagsAndAttributes,
|
||||
IntPtr hTemplateFile);
|
||||
|
||||
[DllImport("Kernel32.dll", SetLastError = false, CharSet = CharSet.Auto)]
|
||||
public static extern bool DeviceIoControl(
|
||||
IntPtr hDevice,
|
||||
uint IoControlCode,
|
||||
[In] object InBuffer,
|
||||
uint nInBufferSize,
|
||||
[Out] object OutBuffer,
|
||||
uint nOutBufferSize,
|
||||
ref uint pBytesReturned,
|
||||
IntPtr Overlapped
|
||||
);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool FlushFileBuffers(IntPtr hFile);
|
||||
|
||||
static NativeMethods()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private SafeTokenHandle() : base(true) { }
|
||||
|
||||
// 0 is an Invalid Handle
|
||||
internal SafeTokenHandle(IntPtr handle)
|
||||
: base(true)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
internal static SafeTokenHandle InvalidHandle
|
||||
{
|
||||
get { return new SafeTokenHandle(IntPtr.Zero); }
|
||||
}
|
||||
|
||||
[DllImport(NativeMethods.KERNEL32, SetLastError = true),
|
||||
SuppressUnmanagedCodeSecurity]
|
||||
private static extern bool CloseHandle(IntPtr handle);
|
||||
|
||||
override protected bool ReleaseHandle()
|
||||
{
|
||||
return CloseHandle(handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,412 +1,412 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal 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 { }
|
||||
}
|
||||
|
||||
private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
byte[] Buffer;
|
||||
int Length;
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
const string jsonrpc = "2.0";
|
||||
int id = MessageId++;
|
||||
string method = JsonMethod;
|
||||
Dictionary<string, object> @params = new();
|
||||
if (Params != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> Param in Params)
|
||||
{
|
||||
if (Param.Value is byte[] v)
|
||||
{
|
||||
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
|
||||
}
|
||||
else
|
||||
{
|
||||
@params.Add(Param.Key, Param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@params.Add("MessageVersion", 0);
|
||||
string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params });
|
||||
Device.OutputPipe.Write(System.Text.Encoding.ASCII.GetBytes(Request));
|
||||
|
||||
Buffer = new byte[0x10000];
|
||||
Length = Device.InputPipe.Read(Buffer);
|
||||
}
|
||||
|
||||
JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length));
|
||||
|
||||
try
|
||||
{
|
||||
JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
|
||||
if ((ResultToken == null) || (ResultElement == null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ResultToken.Value.GetProperty(ResultElement);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethod(string JsonMethod, Dictionary<string, object> Params)
|
||||
{
|
||||
_ = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, null);
|
||||
}
|
||||
|
||||
public string ExecuteJsonMethodAsString(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.GetString();
|
||||
}
|
||||
|
||||
public string ExecuteJsonMethodAsString(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.GetString();
|
||||
}
|
||||
|
||||
public int ExecuteJsonMethodAsInteger(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Token.Value.GetInt32();
|
||||
}
|
||||
|
||||
public int ExecuteJsonMethodAsInteger(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Token.Value.GetInt32();
|
||||
}
|
||||
|
||||
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
|
||||
}
|
||||
|
||||
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
|
||||
}
|
||||
|
||||
public bool? ExecuteJsonMethodAsBoolean(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.GetBoolean();
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsync(string JsonMethod, Dictionary<string, object> Params)
|
||||
{
|
||||
lock (UsbLock)
|
||||
{
|
||||
const string jsonrpc = "2.0";
|
||||
int id = MessageId++;
|
||||
string method = JsonMethod;
|
||||
Dictionary<string, object> @params = new();
|
||||
if (Params != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> Param in Params)
|
||||
{
|
||||
if (Param.Value is byte[] v)
|
||||
{
|
||||
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
|
||||
}
|
||||
else
|
||||
{
|
||||
@params.Add(Param.Key, Param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@params.Add("MessageVersion", 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsync(string JsonMethod)
|
||||
{
|
||||
ExecuteJsonMethod(JsonMethod, null);
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackString(object State, string Result);
|
||||
|
||||
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackString Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackString Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackBoolean(object State, bool Result);
|
||||
|
||||
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackBytes(object State, byte[] Result);
|
||||
|
||||
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBytes Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBytes Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackInteger(object State, int Result);
|
||||
|
||||
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackInteger Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackInteger Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackToken(object State, JsonElement? Result);
|
||||
|
||||
public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackToken Callback)
|
||||
{
|
||||
byte[] Buffer;
|
||||
int Length;
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
const string jsonrpc = "2.0";
|
||||
int id = MessageId++;
|
||||
string method = JsonMethod;
|
||||
Dictionary<string, object> @params = new();
|
||||
if (Params != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> Param in Params)
|
||||
{
|
||||
if (Param.Value is byte[] v)
|
||||
{
|
||||
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
|
||||
}
|
||||
else
|
||||
{
|
||||
@params.Add(Param.Key, Param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@params.Add("MessageVersion", 0);
|
||||
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);
|
||||
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 { } // Reboot command looses connection
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var pipe in Device.Pipes)
|
||||
{
|
||||
pipe.Abort();
|
||||
pipe.Reset();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer for the UsbDevice. Disposes all unmanaged handles.
|
||||
/// </summary>
|
||||
~NokiaPhoneModel()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the object
|
||||
/// </summary>
|
||||
/// <param name="disposing">Indicates wether Dispose was called manually (true) or by
|
||||
/// the garbage collector (false) via the destructor.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Device?.Dispose();
|
||||
}
|
||||
|
||||
// Clean unmanaged resources here.
|
||||
// (none currently)
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal 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 { }
|
||||
}
|
||||
|
||||
private JsonElement? ExecuteJsonMethodAsJsonToken(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
byte[] Buffer;
|
||||
int Length;
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
const string jsonrpc = "2.0";
|
||||
int id = MessageId++;
|
||||
string method = JsonMethod;
|
||||
Dictionary<string, object> @params = new();
|
||||
if (Params != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> Param in Params)
|
||||
{
|
||||
if (Param.Value is byte[] v)
|
||||
{
|
||||
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
|
||||
}
|
||||
else
|
||||
{
|
||||
@params.Add(Param.Key, Param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@params.Add("MessageVersion", 0);
|
||||
string Request = JsonSerializer.Serialize(new { jsonrpc, id, method, @params });
|
||||
Device.OutputPipe.Write(System.Text.Encoding.ASCII.GetBytes(Request));
|
||||
|
||||
Buffer = new byte[0x10000];
|
||||
Length = Device.InputPipe.Read(Buffer);
|
||||
}
|
||||
|
||||
JsonDocument ResultMessage = JsonDocument.Parse(System.Text.Encoding.ASCII.GetString(Buffer, 0, Length));
|
||||
|
||||
try
|
||||
{
|
||||
JsonElement? ResultToken = ResultMessage.RootElement.GetProperty("result");
|
||||
if ((ResultToken == null) || (ResultElement == null))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ResultToken.Value.GetProperty(ResultElement);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethod(string JsonMethod, Dictionary<string, object> Params)
|
||||
{
|
||||
_ = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, null);
|
||||
}
|
||||
|
||||
public string ExecuteJsonMethodAsString(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.GetString();
|
||||
}
|
||||
|
||||
public string ExecuteJsonMethodAsString(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.GetString();
|
||||
}
|
||||
|
||||
public int ExecuteJsonMethodAsInteger(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Token.Value.GetInt32();
|
||||
}
|
||||
|
||||
public int ExecuteJsonMethodAsInteger(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Token.Value.GetInt32();
|
||||
}
|
||||
|
||||
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, Dictionary<string, object> Params, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, Params, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
|
||||
}
|
||||
|
||||
public byte[] ExecuteJsonMethodAsBytes(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray();
|
||||
}
|
||||
|
||||
public bool? ExecuteJsonMethodAsBoolean(string JsonMethod, string ResultElement)
|
||||
{
|
||||
JsonElement? Token = ExecuteJsonMethodAsJsonToken(JsonMethod, null, ResultElement);
|
||||
if (Token == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Token.Value.GetBoolean();
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsync(string JsonMethod, Dictionary<string, object> Params)
|
||||
{
|
||||
lock (UsbLock)
|
||||
{
|
||||
const string jsonrpc = "2.0";
|
||||
int id = MessageId++;
|
||||
string method = JsonMethod;
|
||||
Dictionary<string, object> @params = new();
|
||||
if (Params != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> Param in Params)
|
||||
{
|
||||
if (Param.Value is byte[] v)
|
||||
{
|
||||
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
|
||||
}
|
||||
else
|
||||
{
|
||||
@params.Add(Param.Key, Param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@params.Add("MessageVersion", 0);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsync(string JsonMethod)
|
||||
{
|
||||
ExecuteJsonMethod(JsonMethod, null);
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackString(object State, string Result);
|
||||
|
||||
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackString Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsStringAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackString Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetRawText()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackBoolean(object State, bool Result);
|
||||
|
||||
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsBooleanAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBoolean Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetBoolean()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackBytes(object State, byte[] Result);
|
||||
|
||||
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackBytes Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsBytesAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackBytes Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.EnumerateArray().Select(x => x.GetByte()).ToArray()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackInteger(object State, int Result);
|
||||
|
||||
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackInteger Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, Params, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
|
||||
}
|
||||
|
||||
public void ExecuteJsonMethodAsIntegerAsync(string JsonMethod, string ResultElement, object State, JsonMethodCallbackInteger Callback)
|
||||
{
|
||||
ExecuteJsonMethodAsTokenAsync(JsonMethod, null, ResultElement, State, (ReturnState, Token) => Callback(ReturnState, Token.Value.GetInt32()));
|
||||
}
|
||||
|
||||
public delegate void JsonMethodCallbackToken(object State, JsonElement? Result);
|
||||
|
||||
public void ExecuteJsonMethodAsTokenAsync(string JsonMethod, Dictionary<string, object> Params, string ResultElement, object State, JsonMethodCallbackToken Callback)
|
||||
{
|
||||
byte[] Buffer;
|
||||
int Length;
|
||||
|
||||
lock (UsbLock)
|
||||
{
|
||||
const string jsonrpc = "2.0";
|
||||
int id = MessageId++;
|
||||
string method = JsonMethod;
|
||||
Dictionary<string, object> @params = new();
|
||||
if (Params != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, object> Param in Params)
|
||||
{
|
||||
if (Param.Value is byte[] v)
|
||||
{
|
||||
@params.Add(Param.Key, v.Select(b => (int)b).ToArray()); // convert to int-array
|
||||
}
|
||||
else
|
||||
{
|
||||
@params.Add(Param.Key, Param.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@params.Add("MessageVersion", 0);
|
||||
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);
|
||||
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 { } // Reboot command looses connection
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetDevice()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var pipe in Device.Pipes)
|
||||
{
|
||||
pipe.Abort();
|
||||
pipe.Reset();
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalizer for the UsbDevice. Disposes all unmanaged handles.
|
||||
/// </summary>
|
||||
~NokiaPhoneModel()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the object
|
||||
/// </summary>
|
||||
/// <param name="disposing">Indicates wether Dispose was called manually (true) or by
|
||||
/// the garbage collector (false) via the destructor.</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
Device?.Dispose();
|
||||
}
|
||||
|
||||
// Clean unmanaged resources here.
|
||||
// (none currently)
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,145 +1,145 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class QualcommDownload
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommDownload(QualcommSerial Serial)
|
||||
{
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
public bool IsAlive()
|
||||
{
|
||||
try
|
||||
{
|
||||
Serial.SendCommand(new byte[] { 0x06 }, new byte[] { 0x02 });
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendToPhoneMemory(UInt32 Address, Stream Data, UInt32 Length = UInt32.MaxValue)
|
||||
{
|
||||
long Remaining = Length > (Data.Length - Data.Position) ? Data.Length - Data.Position : Length;
|
||||
UInt32 CurrentLength;
|
||||
byte[] Buffer = new byte[0x107];
|
||||
Buffer[0] = 0x0F;
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)0x100).Reverse().ToArray(), 0, Buffer, 5, 2); // Length is in Big Endian
|
||||
UInt32 CurrentAddress = Address;
|
||||
while (Remaining > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
|
||||
|
||||
CurrentLength = Remaining >= 0x100 ? 0x100 : (UInt32)Remaining;
|
||||
|
||||
CurrentLength = (UInt32)Data.Read(Buffer, 7, (int)CurrentLength);
|
||||
Serial.SendCommand(Buffer, new byte[] { 0x02 });
|
||||
|
||||
CurrentAddress += CurrentLength;
|
||||
Remaining -= CurrentLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendToPhoneMemory(UInt32 Address, byte[] Data, UInt32 Offset = 0, UInt32 Length = UInt32.MaxValue)
|
||||
{
|
||||
long Remaining;
|
||||
if (Offset > (Data.Length - 1))
|
||||
{
|
||||
throw new ArgumentException("Wrong offset");
|
||||
}
|
||||
|
||||
Remaining = Length > (Data.Length - Offset) ? Data.Length - Offset : Length;
|
||||
|
||||
UInt32 CurrentLength;
|
||||
UInt32 CurrentOffset = Offset;
|
||||
byte[] Buffer = new byte[0x107];
|
||||
UInt32 CurrentAddress = Address;
|
||||
byte[] CurrentBytes;
|
||||
while (Remaining > 0)
|
||||
{
|
||||
if (Remaining >= 0x100)
|
||||
{
|
||||
CurrentLength = 0x100;
|
||||
CurrentBytes = Buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentLength = (UInt32)Remaining;
|
||||
CurrentBytes = new byte[CurrentLength + 7];
|
||||
}
|
||||
CurrentBytes[0] = 0x0F;
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, CurrentBytes, 1, 4); // Address is in Big Endian
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)CurrentLength).Reverse().ToArray(), 0, CurrentBytes, 5, 2); // Length is in Big Endian
|
||||
System.Buffer.BlockCopy(Data, (int)CurrentOffset, CurrentBytes, 7, (int)CurrentLength);
|
||||
|
||||
Serial.SendCommand(CurrentBytes, new byte[] { 0x02 });
|
||||
|
||||
CurrentAddress += CurrentLength;
|
||||
CurrentOffset += CurrentLength;
|
||||
Remaining -= CurrentLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartBootloader(UInt32 Address)
|
||||
{
|
||||
byte[] Buffer = new byte[5];
|
||||
Buffer[0] = 0x05;
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(Address).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
|
||||
Serial.SendCommand(Buffer, new byte[] { 0x02 });
|
||||
}
|
||||
|
||||
// Reset interface. Interface becomes unresponsive.
|
||||
public void Reset()
|
||||
{
|
||||
Serial.SendCommand(new byte[] { 0x0A }, new byte[] { 0x02 });
|
||||
}
|
||||
|
||||
// This also resets interface. This does not actually reboot the phone. The interface becomes unresponsive.
|
||||
public void Shutdown()
|
||||
{
|
||||
Serial.SendCommand(new byte[] { 0x0E }, new byte[] { 0x02 });
|
||||
}
|
||||
|
||||
// This command only works on 9008 interface.
|
||||
public byte[] GetRKH()
|
||||
{
|
||||
byte[] Response = Serial.SendCommand(new byte[] { 0x18 }, new byte[] { 0x18, 0x01, 0x00 });
|
||||
byte[] Result = new byte[0x20];
|
||||
Buffer.BlockCopy(Response, 3, Result, 0, 0x20);
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void CloseSerial()
|
||||
{
|
||||
Serial.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class QualcommDownload
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommDownload(QualcommSerial Serial)
|
||||
{
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
public bool IsAlive()
|
||||
{
|
||||
try
|
||||
{
|
||||
Serial.SendCommand([0x06], [0x02]);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendToPhoneMemory(UInt32 Address, Stream Data, UInt32 Length = UInt32.MaxValue)
|
||||
{
|
||||
long Remaining = Length > (Data.Length - Data.Position) ? Data.Length - Data.Position : Length;
|
||||
UInt32 CurrentLength;
|
||||
byte[] Buffer = new byte[0x107];
|
||||
Buffer[0] = 0x0F;
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)0x100).Reverse().ToArray(), 0, Buffer, 5, 2); // Length is in Big Endian
|
||||
UInt32 CurrentAddress = Address;
|
||||
while (Remaining > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
|
||||
|
||||
CurrentLength = Remaining >= 0x100 ? 0x100 : (UInt32)Remaining;
|
||||
|
||||
CurrentLength = (UInt32)Data.Read(Buffer, 7, (int)CurrentLength);
|
||||
Serial.SendCommand(Buffer, [0x02]);
|
||||
|
||||
CurrentAddress += CurrentLength;
|
||||
Remaining -= CurrentLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void SendToPhoneMemory(UInt32 Address, byte[] Data, UInt32 Offset = 0, UInt32 Length = UInt32.MaxValue)
|
||||
{
|
||||
long Remaining;
|
||||
if (Offset > (Data.Length - 1))
|
||||
{
|
||||
throw new ArgumentException("Wrong offset");
|
||||
}
|
||||
|
||||
Remaining = Length > (Data.Length - Offset) ? Data.Length - Offset : Length;
|
||||
|
||||
UInt32 CurrentLength;
|
||||
UInt32 CurrentOffset = Offset;
|
||||
byte[] Buffer = new byte[0x107];
|
||||
UInt32 CurrentAddress = Address;
|
||||
byte[] CurrentBytes;
|
||||
while (Remaining > 0)
|
||||
{
|
||||
if (Remaining >= 0x100)
|
||||
{
|
||||
CurrentLength = 0x100;
|
||||
CurrentBytes = Buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentLength = (UInt32)Remaining;
|
||||
CurrentBytes = new byte[CurrentLength + 7];
|
||||
}
|
||||
CurrentBytes[0] = 0x0F;
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentAddress).Reverse().ToArray(), 0, CurrentBytes, 1, 4); // Address is in Big Endian
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes((UInt16)CurrentLength).Reverse().ToArray(), 0, CurrentBytes, 5, 2); // Length is in Big Endian
|
||||
System.Buffer.BlockCopy(Data, (int)CurrentOffset, CurrentBytes, 7, (int)CurrentLength);
|
||||
|
||||
Serial.SendCommand(CurrentBytes, [0x02]);
|
||||
|
||||
CurrentAddress += CurrentLength;
|
||||
CurrentOffset += CurrentLength;
|
||||
Remaining -= CurrentLength;
|
||||
}
|
||||
}
|
||||
|
||||
public void StartBootloader(UInt32 Address)
|
||||
{
|
||||
byte[] Buffer = new byte[5];
|
||||
Buffer[0] = 0x05;
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(Address).Reverse().ToArray(), 0, Buffer, 1, 4); // Address is in Big Endian
|
||||
Serial.SendCommand(Buffer, [0x02]);
|
||||
}
|
||||
|
||||
// Reset interface. Interface becomes unresponsive.
|
||||
public void Reset()
|
||||
{
|
||||
Serial.SendCommand([0x0A], [0x02]);
|
||||
}
|
||||
|
||||
// This also resets interface. This does not actually reboot the phone. The interface becomes unresponsive.
|
||||
public void Shutdown()
|
||||
{
|
||||
Serial.SendCommand([0x0E], [0x02]);
|
||||
}
|
||||
|
||||
// This command only works on 9008 interface.
|
||||
public byte[] GetRKH()
|
||||
{
|
||||
byte[] Response = Serial.SendCommand([0x18], [0x18, 0x01, 0x00]);
|
||||
byte[] Result = new byte[0x20];
|
||||
Buffer.BlockCopy(Response, 3, Result, 0, 0x20);
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void CloseSerial()
|
||||
{
|
||||
Serial.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,600 +1,384 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.Collections;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum SaharaMode : uint
|
||||
{
|
||||
ImageTransferPending = 0x00,
|
||||
ImagetransferComplete = 0x01,
|
||||
MemoryDebug = 0x02,
|
||||
Command = 0x03
|
||||
}
|
||||
|
||||
internal delegate void ReadyHandler();
|
||||
|
||||
internal class QualcommSahara
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommSahara(QualcommSerial Serial)
|
||||
{
|
||||
Serial.EncodeCommands = false;
|
||||
Serial.DecodeResponses = false;
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
public bool SendImage(string Path)
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
LogFile.Log("Sending programmer: " + Path, LogType.FileOnly);
|
||||
|
||||
int Step = 0;
|
||||
UInt32 Offset = 0;
|
||||
UInt32 Length = 0;
|
||||
|
||||
byte[] ImageBuffer = null;
|
||||
try
|
||||
{
|
||||
Step = 1;
|
||||
byte[] Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 });
|
||||
|
||||
// Incoming Hello packet:
|
||||
// 00000001 = Hello command id
|
||||
// xxxxxxxx = Length
|
||||
// xxxxxxxx = Protocol version
|
||||
// xxxxxxxx = Supported version
|
||||
// xxxxxxxx = Max packet length
|
||||
// xxxxxxxx = Expected mode
|
||||
// 6 dwords reserved space
|
||||
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
|
||||
|
||||
// Packet:
|
||||
// 00000002 = Hello response command id
|
||||
// 00000030 = Length
|
||||
// 00000002 = Protocol version
|
||||
// 00000001 = Supported version
|
||||
// 00000000 = Status OK
|
||||
// 00000000 = Mode
|
||||
// rest is reserved space
|
||||
Step = 2;
|
||||
byte[] HelloResponse = new byte[] {
|
||||
0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
Serial.SendData(HelloResponse);
|
||||
|
||||
Step = 3;
|
||||
using FileStream FileStream = new(Path, FileMode.Open, FileAccess.Read);
|
||||
while (true)
|
||||
{
|
||||
Step = 4;
|
||||
byte[] ReadDataRequest = Serial.GetResponse(null);
|
||||
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
|
||||
if (ResponseID == 4)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ResponseID != 3)
|
||||
{
|
||||
Step = 5;
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
|
||||
Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10);
|
||||
if ((ImageBuffer == null) || (ImageBuffer.Length != Length))
|
||||
{
|
||||
ImageBuffer = new byte[Length];
|
||||
}
|
||||
|
||||
if (FileStream.Position != Offset)
|
||||
{
|
||||
FileStream.Seek(Offset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
Step = 6;
|
||||
FileStream.Read(ImageBuffer, 0, (int)Length);
|
||||
|
||||
Step = 7;
|
||||
Serial.SendData(ImageBuffer);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8"));
|
||||
Result = false;
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
LogFile.Log("Programmer loaded into phone memory", LogType.FileOnly);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public bool Handshake()
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] Hello = Serial.GetResponse(new byte[] { 0x01, 0x00, 0x00, 0x00 });
|
||||
|
||||
// Incoming Hello packet:
|
||||
// 00000001 = Hello command id
|
||||
// xxxxxxxx = Length
|
||||
// xxxxxxxx = Protocol version
|
||||
// xxxxxxxx = Supported version
|
||||
// xxxxxxxx = Max packet length
|
||||
// xxxxxxxx = Expected mode
|
||||
// 6 dwords reserved space
|
||||
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
|
||||
|
||||
byte[] HelloResponse = new byte[] {
|
||||
0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
byte[] Ready = Serial.SendCommand(HelloResponse, new byte[] { 0x03, 0x00, 0x00, 0x00 });
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result = false;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void ResetSahara()
|
||||
{
|
||||
Serial.SendCommand(new byte[] { 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 }, new byte[] { 0x08, 0x00, 0x00, 0x00 });
|
||||
}
|
||||
|
||||
public bool ConnectToProgrammer(byte[] PacketFromPcToProgrammer)
|
||||
{
|
||||
// Behaviour of old firehose:
|
||||
// Takes about 20 ms to be started.
|
||||
// Then PC has to start talking to the phone.
|
||||
// Behaviour of new firehose:
|
||||
// After 2000 ms the firehose starts talking to the PC
|
||||
//
|
||||
// For the duration of 2.5 seconds we will send Hello packages
|
||||
// And also wait for incoming messages
|
||||
// An incoming message can be a response to our outgoing Hello packet (read incoming until "response value")
|
||||
// Or it can be an incoming Hello-packet from the programmer (always 2 packets, starting with "Chip serial num")
|
||||
// Sending the hello-packet can succeed immediately, or it can timeout.
|
||||
// When sending succeeds, an answer should be incoming immediately to complete the handshake.
|
||||
// When an incoming Hello was received, the phone still expects to receive another Hello.
|
||||
|
||||
int HelloSendCount = 0;
|
||||
bool HandshakeCompleted = false;
|
||||
string Incoming;
|
||||
do
|
||||
{
|
||||
Serial.SetTimeOut(200);
|
||||
HelloSendCount++;
|
||||
try
|
||||
{
|
||||
LogFile.Log("Send Hello to programmer (" + HelloSendCount.ToString() + ")", LogType.FileOnly);
|
||||
Serial.SendData(PacketFromPcToProgrammer);
|
||||
LogFile.Log("Hello packet accepted", LogType.FileOnly);
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogFile.Log("Hello packet not accepted", LogType.FileOnly);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Serial.SetTimeOut(500);
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
Serial.SetTimeOut(200);
|
||||
if (Incoming.Contains("Chip serial num"))
|
||||
{
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
LogFile.Log("Incoming Hello-packets received", LogType.FileOnly);
|
||||
}
|
||||
|
||||
while (Incoming.IndexOf("response value") < 0)
|
||||
{
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
}
|
||||
|
||||
LogFile.Log("Incoming Hello-response received", LogType.FileOnly);
|
||||
|
||||
if (!Incoming.Contains("Failed to authenticate Digital Signature."))
|
||||
{
|
||||
HandshakeCompleted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Programmer failed to authenticate Digital Signature", LogType.FileOnly);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
while (!HandshakeCompleted && (HelloSendCount < 6));
|
||||
|
||||
return HandshakeCompleted;
|
||||
}
|
||||
|
||||
public bool ConnectToProgrammerInTestMode()
|
||||
{
|
||||
byte[] HelloPacketFromPcToProgrammer = new byte[0x20C];
|
||||
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0, 0x57503730);
|
||||
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x28, 0x57503730);
|
||||
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x208, 0x57503730);
|
||||
ByteOperations.WriteUInt16(HelloPacketFromPcToProgrammer, 0x48, 0x4445);
|
||||
|
||||
bool HandshakeCompleted = ConnectToProgrammer(HelloPacketFromPcToProgrammer);
|
||||
|
||||
if (HandshakeCompleted)
|
||||
{
|
||||
LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Handshake with programmer failed", LogType.FileOnly);
|
||||
}
|
||||
|
||||
return HandshakeCompleted;
|
||||
}
|
||||
|
||||
public async Task<bool> Reset(string ProgrammerPath)
|
||||
{
|
||||
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
|
||||
if (!SendImageResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
await Task.Run(() => StartProgrammer());
|
||||
|
||||
bool Connected = await Task.Run(() => ConnectToProgrammerInTestMode());
|
||||
if (!Connected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LogFile.Log("Rebooting phone", LogType.FileAndConsole);
|
||||
const string Command03 = "<?xml version=\"1.0\" ?><data><power value=\"reset\"/></data>";
|
||||
LogFile.Log("Out: " + Command03, LogType.FileOnly);
|
||||
Serial.SendData(Encoding.ASCII.GetBytes(Command03));
|
||||
|
||||
string Incoming;
|
||||
do
|
||||
{
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
}
|
||||
while (Incoming.IndexOf("response value") < 0);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SwitchMode(SaharaMode Mode)
|
||||
{
|
||||
byte[] SwitchModeCommand = new byte[] { 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
ByteOperations.WriteUInt32(SwitchModeCommand, 8, (UInt32)Mode);
|
||||
byte[] ResponsePattern = null;
|
||||
switch (Mode)
|
||||
{
|
||||
case SaharaMode.ImageTransferPending:
|
||||
ResponsePattern = new byte[] { 0x04, 0x00, 0x00, 0x00 };
|
||||
break;
|
||||
case SaharaMode.MemoryDebug:
|
||||
ResponsePattern = new byte[] { 0x09, 0x00, 0x00, 0x00 };
|
||||
break;
|
||||
case SaharaMode.Command:
|
||||
ResponsePattern = new byte[] { 0x0B, 0x00, 0x00, 0x00 };
|
||||
break;
|
||||
}
|
||||
Serial.SendCommand(SwitchModeCommand, ResponsePattern);
|
||||
}
|
||||
|
||||
public void StartProgrammer()
|
||||
{
|
||||
LogFile.Log("Starting programmer", LogType.FileAndConsole);
|
||||
byte[] DoneCommand = new byte[] { 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00 };
|
||||
bool Started = false;
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
count++;
|
||||
try
|
||||
{
|
||||
byte[] DoneResponse = Serial.SendCommand(DoneCommand, new byte[] { 0x06, 0x00, 0x00, 0x00 });
|
||||
Started = true;
|
||||
}
|
||||
catch (BadConnectionException)
|
||||
{
|
||||
LogFile.Log("Problem while starting programmer. Attempting again.", LogType.FileAndConsole);
|
||||
}
|
||||
} while (!Started && count < 3);
|
||||
if (count >= 3 && !Started)
|
||||
{
|
||||
LogFile.Log("Maximum number of attempts to start the programmer exceeded.", LogType.FileAndConsole);
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
LogFile.Log("Programmer being launched on phone", LogType.FileOnly);
|
||||
}
|
||||
|
||||
public async Task<bool> SendEdPayload(string ProgrammerPath, string PayloadPath)
|
||||
{
|
||||
// First, let's read the Emergency Download payload header and verify its validity
|
||||
FileStream PayloadStream = File.OpenRead(PayloadPath);
|
||||
|
||||
byte[] ValidReferencePayloadHeader = new byte[] { 0x45, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x6E, 0x63, 0x79, 0x20, 0x50, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64 };
|
||||
|
||||
byte[] PayloadHeader = new byte[17];
|
||||
PayloadStream.Read(PayloadHeader, 0, 17);
|
||||
|
||||
bool IsValidEdPayloadImage = StructuralComparisons.StructuralEqualityComparer.Equals(PayloadHeader, ValidReferencePayloadHeader);
|
||||
if (!IsValidEdPayloadImage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now let's read the information block
|
||||
PayloadStream.Seek(0x64, SeekOrigin.Begin);
|
||||
byte[] PayloadInformationBlock = new byte[0x64];
|
||||
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
|
||||
string buildtime = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
|
||||
string builddate = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
|
||||
string version = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
PayloadInformationBlock = new byte[0x670];
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x670);
|
||||
string Info = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
// Print some information about the payload
|
||||
LogFile.Log("Emerency flasher version 0.1", LogType.FileAndConsole);
|
||||
LogFile.Log("Programmer information:", LogType.FileAndConsole);
|
||||
LogFile.Log("Build time: " + buildtime, LogType.FileAndConsole);
|
||||
LogFile.Log("Build date: " + builddate, LogType.FileAndConsole);
|
||||
LogFile.Log("Version: " + version, LogType.FileAndConsole);
|
||||
LogFile.Log("Info: " + Info, LogType.FileAndConsole);
|
||||
|
||||
// Send the emergency programmer to the phone
|
||||
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
|
||||
if (!SendImageResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start the emergency programmer on the phone
|
||||
await Task.Run(() => StartProgrammer());
|
||||
|
||||
// Wait a few seconds before sending commands
|
||||
LogFile.Log("Waiting...", LogType.FileAndConsole);
|
||||
Thread.Sleep(2000);
|
||||
LogFile.Log("Waiting...OK", LogType.FileAndConsole);
|
||||
|
||||
bool Terminated = false;
|
||||
bool Connected = false;
|
||||
bool ProgrammerRawMode = false;
|
||||
|
||||
string Incoming;
|
||||
|
||||
while (!Terminated)
|
||||
{
|
||||
PayloadInformationBlock = new byte[0x200];
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x200);
|
||||
string ProgrammerCommand = Encoding.ASCII.GetString(PayloadInformationBlock.Skip(0xC).ToArray()).Trim('\0');
|
||||
|
||||
LogFile.Log(ProgrammerCommand, LogType.FileAndConsole);
|
||||
|
||||
byte[] PacketFromPcToProgrammer = Array.Empty<byte>();
|
||||
byte[] temp = new byte[0x200];
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (PayloadStream.Position == PayloadStream.Length)
|
||||
{
|
||||
Terminated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
PayloadStream.Read(temp, 0, 0x200);
|
||||
|
||||
if (temp[12] == 77 && temp[13] == 83 && temp[14] == 71 && temp[15] == 95)
|
||||
{
|
||||
PayloadStream.Seek(-0x200, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
|
||||
PacketFromPcToProgrammer = PacketFromPcToProgrammer.Concat(temp).ToArray();
|
||||
}
|
||||
|
||||
bool ExpectingReplyFromProgrammer = false;
|
||||
|
||||
if (ProgrammerCommand.Contains("XML"))
|
||||
{
|
||||
string Outgoing = Encoding.ASCII.GetString(PacketFromPcToProgrammer).Trim('\0');
|
||||
PacketFromPcToProgrammer = Encoding.ASCII.GetBytes(Outgoing);
|
||||
LogFile.Log("Out: " + Outgoing, LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (!ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
|
||||
{
|
||||
ExpectingReplyFromProgrammer = true;
|
||||
}
|
||||
|
||||
if (ProgrammerCommand.Contains("LAST") && ProgrammerRawMode)
|
||||
{
|
||||
ExpectingReplyFromProgrammer = true;
|
||||
}
|
||||
|
||||
if (ProgrammerCommand.Contains("DATA_ALL") && ProgrammerRawMode)
|
||||
{
|
||||
ExpectingReplyFromProgrammer = true;
|
||||
}
|
||||
|
||||
if (ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
|
||||
{
|
||||
LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ProgrammerCommand.Contains("RAW_DATA") && ProgrammerRawMode)
|
||||
{
|
||||
LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Connected)
|
||||
{
|
||||
Serial.SendData(PacketFromPcToProgrammer);
|
||||
}
|
||||
|
||||
if (ExpectingReplyFromProgrammer)
|
||||
{
|
||||
if (!Connected)
|
||||
{
|
||||
Connected = ConnectToProgrammer(PacketFromPcToProgrammer);
|
||||
|
||||
if (Connected)
|
||||
{
|
||||
LogFile.Log("Handshake completed with programmer in validated image programming (VIP) mode", LogType.FileAndConsole);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Handshake with programmer failed", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (!Connected)
|
||||
{
|
||||
LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial.SetTimeOut(500);
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
Serial.SetTimeOut(200);
|
||||
LogFile.Log("In: " + Incoming, LogType.FileAndConsole);
|
||||
}
|
||||
while (Incoming.IndexOf("response value") < 0);
|
||||
|
||||
if (Incoming.Contains("rawmode=\"false\""))
|
||||
{
|
||||
ProgrammerRawMode = false;
|
||||
LogFile.Log("Raw mode: OFF", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (Incoming.Contains("rawmode=\"true\""))
|
||||
{
|
||||
ProgrammerRawMode = true;
|
||||
LogFile.Log("Raw mode: ON", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (!Incoming.Contains("ACK"))
|
||||
{
|
||||
LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed successfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class QualcommFirehose
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommFirehose(QualcommSerial Serial)
|
||||
{
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
public bool ConnectToProgrammer(byte[] PacketFromPcToProgrammer)
|
||||
{
|
||||
// Behaviour of old firehose:
|
||||
// Takes about 20 ms to be started.
|
||||
// Then PC has to start talking to the phone.
|
||||
// Behaviour of new firehose:
|
||||
// After 2000 ms the firehose starts talking to the PC
|
||||
//
|
||||
// For the duration of 2.5 seconds we will send Hello packages
|
||||
// And also wait for incoming messages
|
||||
// An incoming message can be a response to our outgoing Hello packet (read incoming until "response value")
|
||||
// Or it can be an incoming Hello-packet from the programmer (always 2 packets, starting with "Chip serial num")
|
||||
// Sending the hello-packet can succeed immediately, or it can timeout.
|
||||
// When sending succeeds, an answer should be incoming immediately to complete the handshake.
|
||||
// When an incoming Hello was received, the phone still expects to receive another Hello.
|
||||
|
||||
int HelloSendCount = 0;
|
||||
bool HandshakeCompleted = false;
|
||||
string Incoming;
|
||||
do
|
||||
{
|
||||
Serial.SetTimeOut(200);
|
||||
HelloSendCount++;
|
||||
try
|
||||
{
|
||||
LogFile.Log("Send Hello to programmer (" + HelloSendCount.ToString() + ")", LogType.FileOnly);
|
||||
Serial.SendData(PacketFromPcToProgrammer);
|
||||
LogFile.Log("Hello packet accepted", LogType.FileOnly);
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogFile.Log("Hello packet not accepted", LogType.FileOnly);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Serial.SetTimeOut(500);
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
Serial.SetTimeOut(200);
|
||||
if (Incoming.Contains("Chip serial num"))
|
||||
{
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
LogFile.Log("Incoming Hello-packets received", LogType.FileOnly);
|
||||
}
|
||||
|
||||
while (Incoming.IndexOf("response value") < 0)
|
||||
{
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
}
|
||||
|
||||
LogFile.Log("Incoming Hello-response received", LogType.FileOnly);
|
||||
|
||||
if (!Incoming.Contains("Failed to authenticate Digital Signature."))
|
||||
{
|
||||
HandshakeCompleted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Programmer failed to authenticate Digital Signature", LogType.FileOnly);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
while (!HandshakeCompleted && (HelloSendCount < 6));
|
||||
|
||||
return HandshakeCompleted;
|
||||
}
|
||||
|
||||
public bool ConnectToProgrammerInTestMode()
|
||||
{
|
||||
byte[] HelloPacketFromPcToProgrammer = new byte[0x20C];
|
||||
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0, 0x57503730);
|
||||
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x28, 0x57503730);
|
||||
ByteOperations.WriteUInt32(HelloPacketFromPcToProgrammer, 0x208, 0x57503730);
|
||||
ByteOperations.WriteUInt16(HelloPacketFromPcToProgrammer, 0x48, 0x4445);
|
||||
|
||||
bool HandshakeCompleted = ConnectToProgrammer(HelloPacketFromPcToProgrammer);
|
||||
|
||||
if (HandshakeCompleted)
|
||||
{
|
||||
LogFile.Log("Handshake completed with programmer in testmode", LogType.FileOnly);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Handshake with programmer failed", LogType.FileOnly);
|
||||
}
|
||||
|
||||
return HandshakeCompleted;
|
||||
}
|
||||
|
||||
public async Task<bool> Reset()
|
||||
{
|
||||
bool Connected = await Task.Run(() => ConnectToProgrammerInTestMode());
|
||||
if (!Connected)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
LogFile.Log("Rebooting phone", LogType.FileAndConsole);
|
||||
const string Command03 = "<?xml version=\"1.0\" ?><data><power value=\"reset\"/></data>";
|
||||
LogFile.Log("Out: " + Command03, LogType.FileOnly);
|
||||
Serial.SendData(Encoding.ASCII.GetBytes(Command03));
|
||||
|
||||
string Incoming;
|
||||
do
|
||||
{
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
LogFile.Log("In: " + Incoming, LogType.FileOnly);
|
||||
}
|
||||
while (Incoming.IndexOf("response value") < 0);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool SendEdPayload(string ProgrammerPath, string PayloadPath)
|
||||
{
|
||||
// First, let's read the Emergency Download payload header and verify its validity
|
||||
FileStream PayloadStream = File.OpenRead(PayloadPath);
|
||||
|
||||
byte[] ValidReferencePayloadHeader = [0x45, 0x6D, 0x65, 0x72, 0x67, 0x65, 0x6E, 0x63, 0x79, 0x20, 0x50, 0x61, 0x79, 0x6C, 0x6F, 0x61, 0x64];
|
||||
|
||||
byte[] PayloadHeader = new byte[17];
|
||||
PayloadStream.Read(PayloadHeader, 0, 17);
|
||||
|
||||
bool IsValidEdPayloadImage = StructuralComparisons.StructuralEqualityComparer.Equals(PayloadHeader, ValidReferencePayloadHeader);
|
||||
if (!IsValidEdPayloadImage)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now let's read the information block
|
||||
PayloadStream.Seek(0x64, SeekOrigin.Begin);
|
||||
byte[] PayloadInformationBlock = new byte[0x64];
|
||||
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
|
||||
string buildtime = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
|
||||
string builddate = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x64);
|
||||
string version = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
PayloadInformationBlock = new byte[0x670];
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x670);
|
||||
string Info = Encoding.ASCII.GetString(PayloadInformationBlock).Trim('\0');
|
||||
|
||||
// Print some information about the payload
|
||||
LogFile.Log("Emerency flasher version 0.1", LogType.FileAndConsole);
|
||||
LogFile.Log("Programmer information:", LogType.FileAndConsole);
|
||||
LogFile.Log("Build time: " + buildtime, LogType.FileAndConsole);
|
||||
LogFile.Log("Build date: " + builddate, LogType.FileAndConsole);
|
||||
LogFile.Log("Version: " + version, LogType.FileAndConsole);
|
||||
LogFile.Log("Info: " + Info, LogType.FileAndConsole);
|
||||
|
||||
// Wait a few seconds before sending commands
|
||||
LogFile.Log("Waiting...", LogType.FileAndConsole);
|
||||
Thread.Sleep(2000);
|
||||
LogFile.Log("Waiting...OK", LogType.FileAndConsole);
|
||||
|
||||
bool Terminated = false;
|
||||
bool Connected = false;
|
||||
bool ProgrammerRawMode = false;
|
||||
|
||||
string Incoming;
|
||||
|
||||
while (!Terminated)
|
||||
{
|
||||
PayloadInformationBlock = new byte[0x200];
|
||||
PayloadStream.Read(PayloadInformationBlock, 0, 0x200);
|
||||
string ProgrammerCommand = Encoding.ASCII.GetString(PayloadInformationBlock.Skip(0xC).ToArray()).Trim('\0');
|
||||
|
||||
LogFile.Log(ProgrammerCommand, LogType.FileAndConsole);
|
||||
|
||||
byte[] PacketFromPcToProgrammer = [];
|
||||
byte[] temp = new byte[0x200];
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (PayloadStream.Position == PayloadStream.Length)
|
||||
{
|
||||
Terminated = true;
|
||||
break;
|
||||
}
|
||||
|
||||
PayloadStream.Read(temp, 0, 0x200);
|
||||
|
||||
if (temp[12] == 77 && temp[13] == 83 && temp[14] == 71 && temp[15] == 95)
|
||||
{
|
||||
PayloadStream.Seek(-0x200, SeekOrigin.Current);
|
||||
break;
|
||||
}
|
||||
|
||||
PacketFromPcToProgrammer = [.. PacketFromPcToProgrammer, .. temp];
|
||||
}
|
||||
|
||||
bool ExpectingReplyFromProgrammer = false;
|
||||
|
||||
if (ProgrammerCommand.Contains("XML"))
|
||||
{
|
||||
string Outgoing = Encoding.ASCII.GetString(PacketFromPcToProgrammer).Trim('\0');
|
||||
PacketFromPcToProgrammer = Encoding.ASCII.GetBytes(Outgoing);
|
||||
LogFile.Log("Out: " + Outgoing, LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (!ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
|
||||
{
|
||||
ExpectingReplyFromProgrammer = true;
|
||||
}
|
||||
|
||||
if (ProgrammerCommand.Contains("LAST") && ProgrammerRawMode)
|
||||
{
|
||||
ExpectingReplyFromProgrammer = true;
|
||||
}
|
||||
|
||||
if (ProgrammerCommand.Contains("DATA_ALL") && ProgrammerRawMode)
|
||||
{
|
||||
ExpectingReplyFromProgrammer = true;
|
||||
}
|
||||
|
||||
if (ProgrammerCommand.Contains("RAW_DATA") && !ProgrammerRawMode)
|
||||
{
|
||||
LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ProgrammerCommand.Contains("RAW_DATA") && ProgrammerRawMode)
|
||||
{
|
||||
LogFile.Log("Phone is not in raw mode ON, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Connected)
|
||||
{
|
||||
Serial.SendData(PacketFromPcToProgrammer);
|
||||
}
|
||||
|
||||
if (ExpectingReplyFromProgrammer)
|
||||
{
|
||||
if (!Connected)
|
||||
{
|
||||
Connected = ConnectToProgrammer(PacketFromPcToProgrammer);
|
||||
|
||||
if (Connected)
|
||||
{
|
||||
LogFile.Log("Handshake completed with programmer in validated image programming (VIP) mode", LogType.FileAndConsole);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Handshake with programmer failed", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (!Connected)
|
||||
{
|
||||
LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial.SetTimeOut(500);
|
||||
Incoming = Encoding.ASCII.GetString(Serial.GetResponse(null));
|
||||
Serial.SetTimeOut(200);
|
||||
LogFile.Log("In: " + Incoming, LogType.FileAndConsole);
|
||||
}
|
||||
while (Incoming.IndexOf("response value") < 0);
|
||||
|
||||
if (Incoming.Contains("rawmode=\"false\""))
|
||||
{
|
||||
ProgrammerRawMode = false;
|
||||
LogFile.Log("Raw mode: OFF", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (Incoming.Contains("rawmode=\"true\""))
|
||||
{
|
||||
ProgrammerRawMode = true;
|
||||
LogFile.Log("Raw mode: ON", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
if (!Incoming.Contains("ACK"))
|
||||
{
|
||||
LogFile.Log("Phone programmer is now ignoring us, leaving...", LogType.FileAndConsole);
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed unsuccessfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround for problem
|
||||
// SerialPort is sometimes not disposed correctly when the device is already removed.
|
||||
// So explicitly dispose here
|
||||
Serial.Close();
|
||||
|
||||
LogFile.Log("Phone has been emergency flashed successfully!", LogType.FileAndConsole);
|
||||
PayloadStream.Dispose();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,228 +1,224 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum FlashUnit
|
||||
{
|
||||
Bytes,
|
||||
Sectors
|
||||
}
|
||||
|
||||
internal class QualcommFlasher
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommFlasher(QualcommSerial Serial)
|
||||
{
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
public void CloseSerial()
|
||||
{
|
||||
Serial.Close();
|
||||
}
|
||||
|
||||
public void Hello()
|
||||
{
|
||||
byte[] Command = new byte[]
|
||||
{
|
||||
0x01, // Hello command
|
||||
0x51, 0x43, 0x4F, 0x4D, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x6C, 0x6F, // "QCOM fast download protocol host"
|
||||
0x61, 0x64, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x68, 0x6F, 0x73, 0x74,
|
||||
0x02,
|
||||
0x02, // Protocol version - Must be at least 0x02
|
||||
0x01
|
||||
};
|
||||
|
||||
Serial.SendCommand(Command, new byte[] { 0x02 });
|
||||
}
|
||||
|
||||
public void SetSecurityMode(byte Mode)
|
||||
{
|
||||
byte[] Command = new byte[2];
|
||||
Command[0] = 0x17;
|
||||
Command[1] = Mode;
|
||||
|
||||
Serial.SendCommand(Command, new byte[] { 0x18 });
|
||||
}
|
||||
|
||||
// Use PartitionID 0x21
|
||||
public void OpenPartition(byte PartitionID)
|
||||
{
|
||||
byte[] Command = new byte[2];
|
||||
Command[0] = 0x1B;
|
||||
Command[1] = PartitionID;
|
||||
|
||||
Serial.SendCommand(Command, new byte[] { 0x1C });
|
||||
}
|
||||
|
||||
public void ClosePartition()
|
||||
{
|
||||
Serial.SendCommand(new byte[] { 0x15 }, new byte[] { 0x16 });
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, null, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, ProgressUpdateCallback, null, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, UpdaterPerSector, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
long Remaining = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - Data.Position))
|
||||
? Data.Length - Data.Position
|
||||
: LengthInBytes;
|
||||
UInt32 CurrentLength;
|
||||
byte[] Buffer = new byte[0x405];
|
||||
byte[] ResponsePattern = new byte[5];
|
||||
byte[] FinalCommand;
|
||||
Buffer[0] = 0x07;
|
||||
ResponsePattern[0] = 0x08;
|
||||
UInt32 CurrentPosition = StartInBytes;
|
||||
|
||||
ProgressUpdater Progress = UpdaterPerSector;
|
||||
if ((Progress == null) && (ProgressUpdateCallback != null))
|
||||
{
|
||||
Progress = new ProgressUpdater(GetSectorCount((UInt64)Remaining), ProgressUpdateCallback);
|
||||
}
|
||||
|
||||
while (Remaining > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
|
||||
|
||||
CurrentLength = Remaining >= 0x400 ? 0x400 : (UInt32)Remaining;
|
||||
|
||||
CurrentLength = (uint)Data.Read(Buffer, 5, (int)CurrentLength);
|
||||
|
||||
if (CurrentLength < 0x400)
|
||||
{
|
||||
FinalCommand = new byte[CurrentLength + 5];
|
||||
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
FinalCommand = Buffer;
|
||||
}
|
||||
|
||||
Serial.SendCommand(FinalCommand, ResponsePattern);
|
||||
|
||||
CurrentPosition += CurrentLength;
|
||||
Remaining -= CurrentLength;
|
||||
|
||||
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
|
||||
}
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, null, OffsetInBytes, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, ProgressUpdateCallback, null, OffsetInBytes, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, UpdaterPerSector, OffsetInBytes, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
long RemainingBytes;
|
||||
if (OffsetInBytes > (Data.Length - 1))
|
||||
{
|
||||
throw new ArgumentException("Wrong offset");
|
||||
}
|
||||
|
||||
RemainingBytes = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - OffsetInBytes))
|
||||
? Data.Length - OffsetInBytes
|
||||
: LengthInBytes;
|
||||
|
||||
UInt32 CurrentLength;
|
||||
UInt32 CurrentOffset = OffsetInBytes;
|
||||
byte[] Buffer = new byte[0x405];
|
||||
byte[] ResponsePattern = new byte[5];
|
||||
byte[] FinalCommand;
|
||||
Buffer[0] = 0x07;
|
||||
ResponsePattern[0] = 0x08;
|
||||
UInt32 CurrentPosition = StartInBytes;
|
||||
|
||||
ProgressUpdater Progress = UpdaterPerSector;
|
||||
if ((Progress == null) && (ProgressUpdateCallback != null))
|
||||
{
|
||||
Progress = new ProgressUpdater(GetSectorCount((UInt64)RemainingBytes), ProgressUpdateCallback);
|
||||
}
|
||||
|
||||
while (RemainingBytes > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
|
||||
|
||||
CurrentLength = RemainingBytes >= 0x400 ? 0x400 : (UInt32)RemainingBytes;
|
||||
|
||||
System.Buffer.BlockCopy(Data, (int)CurrentOffset, Buffer, 5, (int)CurrentLength);
|
||||
|
||||
if (CurrentLength < 0x400)
|
||||
{
|
||||
FinalCommand = new byte[CurrentLength + 5];
|
||||
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
FinalCommand = Buffer;
|
||||
}
|
||||
|
||||
Serial.SendCommand(FinalCommand, ResponsePattern);
|
||||
|
||||
CurrentPosition += CurrentLength;
|
||||
CurrentOffset += CurrentLength;
|
||||
RemainingBytes -= CurrentLength;
|
||||
|
||||
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
|
||||
}
|
||||
}
|
||||
|
||||
public UInt64 GetSectorCount(UInt64 ByteCount)
|
||||
{
|
||||
return (ByteCount / 0x200) + ((ByteCount % 0x200) > 0 ? 1 : (UInt64)0);
|
||||
}
|
||||
|
||||
public void Reboot()
|
||||
{
|
||||
Serial.SendCommand(new byte[] { 0x0B }, new byte[] { 0x0C });
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum FlashUnit
|
||||
{
|
||||
Bytes,
|
||||
Sectors
|
||||
}
|
||||
|
||||
internal class QualcommFlasher
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommFlasher(QualcommSerial Serial)
|
||||
{
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
public void CloseSerial()
|
||||
{
|
||||
Serial.Close();
|
||||
}
|
||||
|
||||
public void Hello()
|
||||
{
|
||||
byte[] Command =
|
||||
[
|
||||
0x01, // Hello command
|
||||
0x51, 0x43, 0x4F, 0x4D, 0x20, 0x66, 0x61, 0x73, 0x74, 0x20, 0x64, 0x6F, 0x77, 0x6E, 0x6C, 0x6F, // "QCOM fast download protocol host"
|
||||
0x61, 0x64, 0x20, 0x70, 0x72, 0x6F, 0x74, 0x6F, 0x63, 0x6F, 0x6C, 0x20, 0x68, 0x6F, 0x73, 0x74,
|
||||
0x02,
|
||||
0x02, // Protocol version - Must be at least 0x02
|
||||
0x01
|
||||
];
|
||||
|
||||
Serial.SendCommand(Command, [0x02]);
|
||||
}
|
||||
|
||||
public void SetSecurityMode(byte Mode)
|
||||
{
|
||||
byte[] Command = [0x17, Mode];
|
||||
|
||||
Serial.SendCommand(Command, [0x18]);
|
||||
}
|
||||
|
||||
// Use PartitionID 0x21
|
||||
public void OpenPartition(byte PartitionID)
|
||||
{
|
||||
byte[] Command = [0x1B, PartitionID];
|
||||
|
||||
Serial.SendCommand(Command, [0x1C]);
|
||||
}
|
||||
|
||||
public void ClosePartition()
|
||||
{
|
||||
Serial.SendCommand([0x15], [0x16]);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, null, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, ProgressUpdateCallback, null, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, UpdaterPerSector, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, Stream Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
long Remaining = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - Data.Position))
|
||||
? Data.Length - Data.Position
|
||||
: LengthInBytes;
|
||||
UInt32 CurrentLength;
|
||||
byte[] Buffer = new byte[0x405];
|
||||
byte[] ResponsePattern = new byte[5];
|
||||
byte[] FinalCommand;
|
||||
Buffer[0] = 0x07;
|
||||
ResponsePattern[0] = 0x08;
|
||||
UInt32 CurrentPosition = StartInBytes;
|
||||
|
||||
ProgressUpdater Progress = UpdaterPerSector;
|
||||
if ((Progress == null) && (ProgressUpdateCallback != null))
|
||||
{
|
||||
Progress = new ProgressUpdater(GetSectorCount((UInt64)Remaining), ProgressUpdateCallback);
|
||||
}
|
||||
|
||||
while (Remaining > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start is in bytes and in Little Endian (on Samsung devices start is in sectors!)
|
||||
|
||||
CurrentLength = Remaining >= 0x400 ? 0x400 : (UInt32)Remaining;
|
||||
|
||||
CurrentLength = (uint)Data.Read(Buffer, 5, (int)CurrentLength);
|
||||
|
||||
if (CurrentLength < 0x400)
|
||||
{
|
||||
FinalCommand = new byte[CurrentLength + 5];
|
||||
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
FinalCommand = Buffer;
|
||||
}
|
||||
|
||||
Serial.SendCommand(FinalCommand, ResponsePattern);
|
||||
|
||||
CurrentPosition += CurrentLength;
|
||||
Remaining -= CurrentLength;
|
||||
|
||||
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
|
||||
}
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, null, OffsetInBytes, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, ProgressUpdateCallback, null, OffsetInBytes, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
Flash(StartInBytes, Data, null, UpdaterPerSector, OffsetInBytes, LengthInBytes);
|
||||
}
|
||||
|
||||
public void Flash(UInt32 StartInBytes, byte[] Data, Action<int, TimeSpan?> ProgressUpdateCallback, ProgressUpdater UpdaterPerSector, UInt32 OffsetInBytes = 0, UInt32 LengthInBytes = UInt32.MaxValue)
|
||||
{
|
||||
long RemainingBytes;
|
||||
if (OffsetInBytes > (Data.Length - 1))
|
||||
{
|
||||
throw new ArgumentException("Wrong offset");
|
||||
}
|
||||
|
||||
RemainingBytes = (LengthInBytes == UInt32.MaxValue) || (LengthInBytes > (Data.Length - OffsetInBytes))
|
||||
? Data.Length - OffsetInBytes
|
||||
: LengthInBytes;
|
||||
|
||||
UInt32 CurrentLength;
|
||||
UInt32 CurrentOffset = OffsetInBytes;
|
||||
byte[] Buffer = new byte[0x405];
|
||||
byte[] ResponsePattern = new byte[5];
|
||||
byte[] FinalCommand;
|
||||
Buffer[0] = 0x07;
|
||||
ResponsePattern[0] = 0x08;
|
||||
UInt32 CurrentPosition = StartInBytes;
|
||||
|
||||
ProgressUpdater Progress = UpdaterPerSector;
|
||||
if ((Progress == null) && (ProgressUpdateCallback != null))
|
||||
{
|
||||
Progress = new ProgressUpdater(GetSectorCount((UInt64)RemainingBytes), ProgressUpdateCallback);
|
||||
}
|
||||
|
||||
while (RemainingBytes > 0)
|
||||
{
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, Buffer, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
|
||||
System.Buffer.BlockCopy(BitConverter.GetBytes(CurrentPosition), 0, ResponsePattern, 1, 4); // Start position is in bytes and in Little Endian (on Samsung phones the start position is in Sectors!!)
|
||||
|
||||
CurrentLength = RemainingBytes >= 0x400 ? 0x400 : (UInt32)RemainingBytes;
|
||||
|
||||
System.Buffer.BlockCopy(Data, (int)CurrentOffset, Buffer, 5, (int)CurrentLength);
|
||||
|
||||
if (CurrentLength < 0x400)
|
||||
{
|
||||
FinalCommand = new byte[CurrentLength + 5];
|
||||
System.Buffer.BlockCopy(Buffer, 0, FinalCommand, 0, (int)CurrentLength + 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
FinalCommand = Buffer;
|
||||
}
|
||||
|
||||
Serial.SendCommand(FinalCommand, ResponsePattern);
|
||||
|
||||
CurrentPosition += CurrentLength;
|
||||
CurrentOffset += CurrentLength;
|
||||
RemainingBytes -= CurrentLength;
|
||||
|
||||
Progress?.IncreaseProgress(GetSectorCount(CurrentLength));
|
||||
}
|
||||
}
|
||||
|
||||
public UInt64 GetSectorCount(UInt64 ByteCount)
|
||||
{
|
||||
return (ByteCount / 0x200) + ((ByteCount % 0x200) > 0 ? 1 : (UInt64)0);
|
||||
}
|
||||
|
||||
public void Reboot()
|
||||
{
|
||||
Serial.SendCommand([0x0B], [0x0C]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,125 +1,124 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class QualcommLoaders
|
||||
{
|
||||
internal static List<QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash)
|
||||
{
|
||||
List<QualcommPartition> Result = new();
|
||||
|
||||
try
|
||||
{
|
||||
IEnumerable<string> FilePaths = Directory.EnumerateFiles(Path);
|
||||
foreach (string FilePath in FilePaths)
|
||||
{
|
||||
try
|
||||
{
|
||||
FileInfo Info = new(FilePath);
|
||||
if (Info.Length <= 0x80000)
|
||||
{
|
||||
QualcommPartition Loader;
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("Evaluating loader: " + FilePath);
|
||||
#endif
|
||||
|
||||
byte[] Binary = ParseAsHexFile(FilePath);
|
||||
Loader = Binary == null ? new QualcommPartition(FilePath) : new QualcommPartition(Binary);
|
||||
|
||||
// Make sure the RootKeyHash is not blank
|
||||
// If the RootKeyHash is blank, this is an engineering device, and it will accept any RKH
|
||||
// We expect the user to know what he is doing in such case and we will ignore checks
|
||||
if (!StructuralComparisons.StructuralEqualityComparer.Equals(RootKeyHash, new byte[RootKeyHash.Length]))
|
||||
{
|
||||
if (StructuralComparisons.StructuralEqualityComparer.Equals(Loader.RootKeyHash, RootKeyHash)
|
||||
&& (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
|
||||
{
|
||||
Result.Add(Loader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
|
||||
{
|
||||
Result.Add(Loader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal static byte[] ParseAsHexFile(string FilePath)
|
||||
{
|
||||
byte[] Result = null;
|
||||
|
||||
try
|
||||
{
|
||||
string[] Lines = File.ReadAllLines(FilePath);
|
||||
byte[] Buffer = null;
|
||||
int BufferSize = 0;
|
||||
|
||||
foreach (string Line in Lines)
|
||||
{
|
||||
if (Line[0] != ':')
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
byte[] LineBytes = Converter.ConvertStringToHex(Line[1..]);
|
||||
|
||||
if ((LineBytes[0] + 5) != LineBytes.Length)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
if (Buffer == null)
|
||||
{
|
||||
Buffer = new byte[0x40000];
|
||||
}
|
||||
|
||||
if (LineBytes[3] == 0) // This is mem data
|
||||
{
|
||||
System.Buffer.BlockCopy(LineBytes, 4, Buffer, BufferSize, LineBytes[0]);
|
||||
BufferSize += LineBytes[0];
|
||||
}
|
||||
}
|
||||
|
||||
Result = new byte[BufferSize];
|
||||
System.Buffer.BlockCopy(Buffer, 0, Result, 0, BufferSize);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class QualcommLoaders
|
||||
{
|
||||
internal static List<QualcommPartition> GetPossibleLoadersForRootKeyHash(string Path, byte[] RootKeyHash)
|
||||
{
|
||||
List<QualcommPartition> Result = new();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (string FilePath in Directory.EnumerateFiles(Path))
|
||||
{
|
||||
try
|
||||
{
|
||||
FileInfo Info = new(FilePath);
|
||||
if (Info.Length <= 0x80000)
|
||||
{
|
||||
QualcommPartition Loader;
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("Evaluating loader: " + FilePath);
|
||||
#endif
|
||||
|
||||
byte[] Binary = ParseAsHexFile(FilePath);
|
||||
Loader = Binary == null ? new QualcommPartition(FilePath) : new QualcommPartition(Binary);
|
||||
|
||||
// Make sure the RootKeyHash is not blank
|
||||
// If the RootKeyHash is blank, this is an engineering device, and it will accept any RKH
|
||||
// We expect the user to know what he is doing in such case and we will ignore checks
|
||||
if (!StructuralComparisons.StructuralEqualityComparer.Equals(RootKeyHash, new byte[RootKeyHash.Length]))
|
||||
{
|
||||
if (StructuralComparisons.StructuralEqualityComparer.Equals(Loader.RootKeyHash, RootKeyHash)
|
||||
&& (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null)) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
|
||||
{
|
||||
Result.Add(Loader);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ByteOperations.FindUnicode(Loader.Binary, "QHSUSB_ARMPRG") != null) // To detect that this is a loader, and not SBL1 or something. V1 loaders are QHSUSB_ARMPRG. V2 loaders are QHSUSB__BULK. Only V1 supported for now, because V2 only accepts signed payload.
|
||||
{
|
||||
Result.Add(Loader);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
internal static byte[] ParseAsHexFile(string FilePath)
|
||||
{
|
||||
byte[] Result = null;
|
||||
|
||||
try
|
||||
{
|
||||
string[] Lines = File.ReadAllLines(FilePath);
|
||||
byte[] Buffer = null;
|
||||
int BufferSize = 0;
|
||||
|
||||
foreach (string Line in Lines)
|
||||
{
|
||||
if (Line[0] != ':')
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
byte[] LineBytes = Converter.ConvertStringToHex(Line[1..]);
|
||||
|
||||
if ((LineBytes[0] + 5) != LineBytes.Length)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
if (Buffer == null)
|
||||
{
|
||||
Buffer = new byte[0x40000];
|
||||
}
|
||||
|
||||
if (LineBytes[3] == 0) // This is mem data
|
||||
{
|
||||
System.Buffer.BlockCopy(LineBytes, 4, Buffer, BufferSize, LineBytes[0]);
|
||||
BufferSize += LineBytes[0];
|
||||
}
|
||||
}
|
||||
|
||||
Result = new byte[BufferSize];
|
||||
System.Buffer.BlockCopy(Buffer, 0, Result, 0, BufferSize);
|
||||
}
|
||||
catch { }
|
||||
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,174 +1,197 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum QualcommPartitionHeaderType
|
||||
{
|
||||
Long,
|
||||
Short
|
||||
};
|
||||
|
||||
internal class QualcommPartition
|
||||
{
|
||||
internal byte[] Binary;
|
||||
internal uint HeaderOffset;
|
||||
internal QualcommPartitionHeaderType HeaderType;
|
||||
internal uint ImageOffset;
|
||||
internal uint ImageAddress;
|
||||
internal uint ImageSize;
|
||||
internal uint CodeSize;
|
||||
internal uint SignatureAddress;
|
||||
internal uint SignatureSize;
|
||||
internal uint SignatureOffset;
|
||||
internal uint CertificatesAddress;
|
||||
internal uint CertificatesSize;
|
||||
internal uint CertificatesOffset;
|
||||
internal byte[] RootKeyHash = null;
|
||||
|
||||
internal QualcommPartition(string Path) : this(File.ReadAllBytes(Path)) { }
|
||||
|
||||
internal QualcommPartition(byte[] Binary, uint Offset = 0)
|
||||
{
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("Loader: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, 0, Binary.Length), ""));
|
||||
#endif
|
||||
|
||||
this.Binary = Binary;
|
||||
|
||||
byte[] LongHeaderPattern = new byte[] { 0xD1, 0xDC, 0x4B, 0x84, 0x34, 0x10, 0xD7, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
byte[] LongHeaderMask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
if (ByteOperations.FindPattern(Binary, Offset, 4, new byte[] { 0x7F, 0x45, 0x4C, 0x46 }, new byte[] { 0x00, 0x00, 0x00, 0x00 }, null) == 0)
|
||||
{
|
||||
// This is an ELF image
|
||||
// First program header is a reference to the elf-header
|
||||
// Second program header is a reference to the signed hash-table
|
||||
HeaderType = QualcommPartitionHeaderType.Short;
|
||||
UInt32 ProgramHeaderOffset;
|
||||
UInt16 ProgramHeaderEntrySize;
|
||||
UInt32 HashTableProgramHeaderOffset;
|
||||
if (Binary[Offset + 0x04] == 1)
|
||||
{
|
||||
// 32-bit elf image
|
||||
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x1c);
|
||||
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x2a);
|
||||
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
|
||||
ImageOffset = Offset + ByteOperations.ReadUInt32(Binary, HashTableProgramHeaderOffset + 0x04);
|
||||
HeaderOffset = ImageOffset + 8;
|
||||
}
|
||||
else if (Binary[Offset + 0x04] == 2)
|
||||
{
|
||||
// 64-bit elf image
|
||||
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x20);
|
||||
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x36);
|
||||
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
|
||||
ImageOffset = Offset + (UInt32)ByteOperations.ReadUInt64(Binary, HashTableProgramHeaderOffset + 0x08);
|
||||
HeaderOffset = ImageOffset + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WPinternalsException("Invalid programmer", "The type of elf image could not be determined from the provided programmer.");
|
||||
}
|
||||
}
|
||||
else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null)
|
||||
{
|
||||
HeaderType = QualcommPartitionHeaderType.Short;
|
||||
ImageOffset = Offset;
|
||||
HeaderOffset = ImageOffset + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderType = QualcommPartitionHeaderType.Long;
|
||||
ImageOffset = Offset;
|
||||
HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length;
|
||||
}
|
||||
|
||||
if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
|
||||
{
|
||||
ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00);
|
||||
}
|
||||
else if (HeaderType == QualcommPartitionHeaderType.Short)
|
||||
{
|
||||
ImageOffset += 0x28;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageOffset += 0x50;
|
||||
}
|
||||
|
||||
ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04);
|
||||
ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08);
|
||||
CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C);
|
||||
SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10);
|
||||
SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14);
|
||||
SignatureOffset = SignatureAddress - ImageAddress + ImageOffset;
|
||||
CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18);
|
||||
CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C);
|
||||
CertificatesOffset = CertificatesAddress - ImageAddress + ImageOffset;
|
||||
|
||||
uint CurrentCertificateOffset = CertificatesOffset;
|
||||
uint CertificateSize = 0;
|
||||
while (CurrentCertificateOffset < (CertificatesOffset + CertificatesSize))
|
||||
{
|
||||
if ((Binary[CurrentCertificateOffset] == 0x30) && (Binary[CurrentCertificateOffset + 1] == 0x82))
|
||||
{
|
||||
CertificateSize = (uint)(Binary[CurrentCertificateOffset + 2] * 0x100) + Binary[CurrentCertificateOffset + 3] + 4; // Big endian!
|
||||
|
||||
if ((CurrentCertificateOffset + CertificateSize) == (CertificatesOffset + CertificatesSize))
|
||||
{
|
||||
// This is the last certificate. So this is the root key.
|
||||
RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize);
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
else
|
||||
{
|
||||
System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize), ""));
|
||||
}
|
||||
#endif
|
||||
CurrentCertificateOffset += CertificateSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((RootKeyHash == null) && (CurrentCertificateOffset > CertificatesOffset))
|
||||
{
|
||||
CurrentCertificateOffset -= CertificateSize;
|
||||
|
||||
// This is the last certificate. So this is the root key.
|
||||
RootKeyHash = new SHA256Managed().ComputeHash(Binary, (int)CurrentCertificateOffset, (int)CertificateSize);
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum QualcommPartitionHeaderType
|
||||
{
|
||||
Long,
|
||||
Short
|
||||
};
|
||||
|
||||
internal class QualcommPartition
|
||||
{
|
||||
internal byte[] Binary;
|
||||
internal uint HeaderOffset;
|
||||
internal QualcommPartitionHeaderType HeaderType;
|
||||
internal uint ImageOffset;
|
||||
internal uint ImageAddress;
|
||||
internal uint ImageSize;
|
||||
internal uint CodeSize;
|
||||
internal uint SignatureAddress;
|
||||
internal uint SignatureSize;
|
||||
internal uint SignatureOffset;
|
||||
internal uint CertificatesAddress;
|
||||
internal uint CertificatesSize;
|
||||
internal uint CertificatesOffset;
|
||||
internal byte[] RootKeyHash = null;
|
||||
|
||||
internal QualcommPartition(string Path) : this(File.ReadAllBytes(Path)) { }
|
||||
|
||||
internal QualcommPartition(byte[] Binary, uint Offset = 0)
|
||||
{
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("Loader: " + Converter.ConvertHexToString(SHA256.HashData(Binary.AsSpan(0, Binary.Length)), ""));
|
||||
#endif
|
||||
|
||||
this.Binary = Binary;
|
||||
|
||||
byte[] LongHeaderPattern = [0xD1, 0xDC, 0x4B, 0x84, 0x34, 0x10, 0xD7, 0x73, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF];
|
||||
byte[] LongHeaderMask = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
|
||||
|
||||
if (ByteOperations.FindPattern(Binary, Offset, 4, [0x7F, 0x45, 0x4C, 0x46], [0x00, 0x00, 0x00, 0x00], null) == 0)
|
||||
{
|
||||
// This is an ELF image
|
||||
// First program header is a reference to the elf-header
|
||||
// Second program header is a reference to the signed hash-table
|
||||
HeaderType = QualcommPartitionHeaderType.Short;
|
||||
UInt32 ProgramHeaderOffset;
|
||||
UInt16 ProgramHeaderEntrySize;
|
||||
UInt32 HashTableProgramHeaderOffset;
|
||||
if (Binary[Offset + 0x04] == 1)
|
||||
{
|
||||
// 32-bit elf image
|
||||
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x1c);
|
||||
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x2a);
|
||||
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
|
||||
ImageOffset = Offset + ByteOperations.ReadUInt32(Binary, HashTableProgramHeaderOffset + 0x04);
|
||||
HeaderOffset = ImageOffset + 8;
|
||||
}
|
||||
else if (Binary[Offset + 0x04] == 2)
|
||||
{
|
||||
// 64-bit elf image
|
||||
ProgramHeaderOffset = Offset + ByteOperations.ReadUInt32(Binary, Offset + 0x20);
|
||||
ProgramHeaderEntrySize = ByteOperations.ReadUInt16(Binary, Offset + 0x36);
|
||||
HashTableProgramHeaderOffset = ProgramHeaderOffset + ProgramHeaderEntrySize;
|
||||
ImageOffset = Offset + (UInt32)ByteOperations.ReadUInt64(Binary, HashTableProgramHeaderOffset + 0x08);
|
||||
HeaderOffset = ImageOffset + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new WPinternalsException("Invalid programmer", "The type of elf image could not be determined from the provided programmer.");
|
||||
}
|
||||
}
|
||||
else if (ByteOperations.FindPattern(Binary, Offset, (uint)LongHeaderPattern.Length, LongHeaderPattern, LongHeaderMask, null) == null)
|
||||
{
|
||||
HeaderType = QualcommPartitionHeaderType.Short;
|
||||
ImageOffset = Offset;
|
||||
HeaderOffset = ImageOffset + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderType = QualcommPartitionHeaderType.Long;
|
||||
ImageOffset = Offset;
|
||||
HeaderOffset = ImageOffset + (uint)LongHeaderPattern.Length;
|
||||
}
|
||||
|
||||
uint Version = ByteOperations.ReadUInt32(Binary, ImageOffset + 0X04);
|
||||
|
||||
if (ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00) != 0)
|
||||
{
|
||||
ImageOffset = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X00);
|
||||
}
|
||||
else if (HeaderType == QualcommPartitionHeaderType.Short)
|
||||
{
|
||||
ImageOffset += 0x28;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageOffset += 0x50;
|
||||
}
|
||||
|
||||
ImageAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X04);
|
||||
ImageSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X08);
|
||||
CodeSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X0C);
|
||||
SignatureAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X10);
|
||||
SignatureSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X14);
|
||||
CertificatesAddress = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X18);
|
||||
CertificatesSize = ByteOperations.ReadUInt32(Binary, HeaderOffset + 0X1C);
|
||||
|
||||
if (SignatureAddress == 0xFFFFFFFF)
|
||||
{
|
||||
SignatureAddress = ImageAddress + CodeSize;
|
||||
}
|
||||
|
||||
if (CertificatesAddress == 0xFFFFFFFF)
|
||||
{
|
||||
CertificatesAddress = SignatureAddress + SignatureSize;
|
||||
}
|
||||
|
||||
// Headers newer than version 5 need more padding here
|
||||
if (Version > 5)
|
||||
{
|
||||
ImageOffset += 0x80;
|
||||
}
|
||||
|
||||
SignatureOffset = ImageOffset + CodeSize;
|
||||
CertificatesOffset = ImageOffset + CodeSize + SignatureSize;
|
||||
|
||||
// Keeping just in case
|
||||
// SignatureOffset = SignatureAddress - ImageAddress + ImageOffset;
|
||||
// CertificatesOffset = ImageSize - CertificatesSize + ImageOffset;
|
||||
|
||||
uint CurrentCertificateOffset = CertificatesOffset;
|
||||
uint CertificateSize = 0;
|
||||
while (CurrentCertificateOffset < (CertificatesOffset + CertificatesSize))
|
||||
{
|
||||
if ((Binary[CurrentCertificateOffset] == 0x30) && (Binary[CurrentCertificateOffset + 1] == 0x82))
|
||||
{
|
||||
CertificateSize = (uint)(Binary[CurrentCertificateOffset + 2] * 0x100) + Binary[CurrentCertificateOffset + 3] + 4; // Big endian!
|
||||
|
||||
if ((CurrentCertificateOffset + CertificateSize) == (CertificatesOffset + CertificatesSize))
|
||||
{
|
||||
// This is the last certificate. So this is the root key.
|
||||
RootKeyHash = SHA256.HashData(Binary.AsSpan((int)CurrentCertificateOffset, (int)CertificateSize));
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
|
||||
#endif
|
||||
}
|
||||
#if DEBUG
|
||||
else
|
||||
{
|
||||
System.Diagnostics.Debug.Print("Cert: " + Converter.ConvertHexToString(SHA256.HashData(Binary.AsSpan((int)CurrentCertificateOffset, (int)CertificateSize)), ""));
|
||||
}
|
||||
#endif
|
||||
CurrentCertificateOffset += CertificateSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((RootKeyHash == null) && (CurrentCertificateOffset > CertificatesOffset))
|
||||
{
|
||||
CurrentCertificateOffset -= CertificateSize;
|
||||
|
||||
// This is the last certificate. So this is the root key.
|
||||
RootKeyHash = SHA256.HashData(Binary.AsSpan((int)CurrentCertificateOffset, (int)CertificateSize));
|
||||
|
||||
#if DEBUG
|
||||
System.Diagnostics.Debug.Print("RKH: " + Converter.ConvertHexToString(RootKeyHash, ""));
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,361 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal delegate void ReadyHandler();
|
||||
|
||||
internal class QualcommSahara
|
||||
{
|
||||
private readonly QualcommSerial Serial;
|
||||
|
||||
public QualcommSahara(QualcommSerial Serial)
|
||||
{
|
||||
Serial.EncodeCommands = false;
|
||||
Serial.DecodeResponses = false;
|
||||
this.Serial = Serial;
|
||||
}
|
||||
|
||||
private static byte[] BuildCommandPacket(QualcommSaharaCommand SaharaCommand, byte[] CommandBuffer = null)
|
||||
{
|
||||
UInt32 CommandID = (uint)SaharaCommand;
|
||||
UInt32 CommandBufferLength = 0;
|
||||
if (CommandBuffer != null)
|
||||
{
|
||||
CommandBufferLength = (UInt32)CommandBuffer.Length;
|
||||
}
|
||||
UInt32 Length = 0x8u + CommandBufferLength;
|
||||
|
||||
byte[] Packet = new byte[Length];
|
||||
ByteOperations.WriteUInt32(Packet, 0x00, CommandID);
|
||||
ByteOperations.WriteUInt32(Packet, 0x04, Length);
|
||||
|
||||
if (CommandBuffer != null && CommandBufferLength != 0)
|
||||
{
|
||||
Buffer.BlockCopy(CommandBuffer, 0, Packet, 0x08, CommandBuffer.Length);
|
||||
}
|
||||
|
||||
return Packet;
|
||||
}
|
||||
|
||||
private static byte[] BuildHelloResponsePacket(QualcommSaharaMode SaharaMode, UInt32 ProtocolVersion = 2, UInt32 SupportedVersion = 1, UInt32 MaxPacketLength = 0 /* 0: Status OK */)
|
||||
{
|
||||
UInt32 Mode = (uint)SaharaMode;
|
||||
|
||||
// Hello packet:
|
||||
// xxxxxxxx = Protocol version
|
||||
// xxxxxxxx = Supported version
|
||||
// xxxxxxxx = Max packet length
|
||||
// xxxxxxxx = Expected mode
|
||||
// 6 dwords reserved space
|
||||
byte[] Hello = new byte[0x28];
|
||||
ByteOperations.WriteUInt32(Hello, 0x00, ProtocolVersion);
|
||||
ByteOperations.WriteUInt32(Hello, 0x04, SupportedVersion);
|
||||
ByteOperations.WriteUInt32(Hello, 0x08, MaxPacketLength);
|
||||
ByteOperations.WriteUInt32(Hello, 0x0C, Mode);
|
||||
ByteOperations.WriteUInt32(Hello, 0x10, 0);
|
||||
ByteOperations.WriteUInt32(Hello, 0x14, 0);
|
||||
ByteOperations.WriteUInt32(Hello, 0x18, 0);
|
||||
ByteOperations.WriteUInt32(Hello, 0x1C, 0);
|
||||
ByteOperations.WriteUInt32(Hello, 0x20, 0);
|
||||
ByteOperations.WriteUInt32(Hello, 0x24, 0);
|
||||
|
||||
return BuildCommandPacket(QualcommSaharaCommand.HelloResponse, Hello);
|
||||
}
|
||||
|
||||
private static byte[] BuildExecuteRequestPacket(UInt32 RequestID)
|
||||
{
|
||||
byte[] Execute = new byte[0x04];
|
||||
ByteOperations.WriteUInt32(Execute, 0x00, RequestID);
|
||||
return BuildCommandPacket(QualcommSaharaCommand.ExecuteRequest, Execute);
|
||||
}
|
||||
|
||||
private static byte[] BuildExecuteDataPacket(UInt32 RequestID)
|
||||
{
|
||||
byte[] Execute = new byte[0x04];
|
||||
ByteOperations.WriteUInt32(Execute, 0x00, RequestID);
|
||||
return BuildCommandPacket(QualcommSaharaCommand.ExecuteData, Execute);
|
||||
}
|
||||
|
||||
public byte[][] GetRKHs()
|
||||
{
|
||||
Serial.SendData(BuildExecuteRequestPacket(0x3));
|
||||
|
||||
byte[] ReadDataRequest = Serial.GetResponse(null);
|
||||
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
|
||||
|
||||
if (ResponseID != 0xE)
|
||||
{
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
uint RKHLength = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
|
||||
|
||||
Serial.SendData(BuildExecuteDataPacket(0x3));
|
||||
|
||||
byte[] Response = Serial.GetResponse(null, Length: (int)RKHLength);
|
||||
|
||||
List<byte[]> RootKeyHashes = new();
|
||||
for (int i = 0; i < RKHLength / 0x20; i++)
|
||||
{
|
||||
RootKeyHashes.Add(Response[(i * 0x20)..((i + 1) * 0x20)]);
|
||||
}
|
||||
|
||||
return [.. RootKeyHashes];
|
||||
}
|
||||
|
||||
public byte[] GetRKH()
|
||||
{
|
||||
int Step = 0;
|
||||
UInt32 Offset = 0;
|
||||
UInt32 Length = 0;
|
||||
|
||||
try
|
||||
{
|
||||
Step = 1;
|
||||
byte[] Hello = Serial.GetResponse([0x01, 0x00, 0x00, 0x00]);
|
||||
|
||||
// Incoming Hello packet:
|
||||
// 00000001 = Hello command id
|
||||
// xxxxxxxx = Length
|
||||
// xxxxxxxx = Protocol version
|
||||
// xxxxxxxx = Supported version
|
||||
// xxxxxxxx = Max packet length
|
||||
// xxxxxxxx = Expected mode
|
||||
// 6 dwords reserved space
|
||||
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
|
||||
|
||||
Step = 2;
|
||||
byte[] HelloResponse = BuildHelloResponsePacket(QualcommSaharaMode.Command);
|
||||
Serial.SendData(HelloResponse);
|
||||
|
||||
Step = 3;
|
||||
byte[] ReadDataRequest = Serial.GetResponse(null);
|
||||
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
|
||||
|
||||
if (ResponseID != 0xB)
|
||||
{
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
Step = 4;
|
||||
byte[][] RKHs = GetRKHs();
|
||||
return RKHs[0];
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8"));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool SendImage(string Path)
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
LogFile.Log("Sending programmer: " + Path, LogType.FileOnly);
|
||||
|
||||
int Step = 0;
|
||||
UInt32 Offset = 0;
|
||||
UInt32 Length = 0;
|
||||
|
||||
byte[] ImageBuffer = null;
|
||||
try
|
||||
{
|
||||
Step = 1;
|
||||
byte[] Hello = Serial.GetResponse([0x01, 0x00, 0x00, 0x00]);
|
||||
|
||||
// Incoming Hello packet:
|
||||
// 00000001 = Hello command id
|
||||
// xxxxxxxx = Length
|
||||
// xxxxxxxx = Protocol version
|
||||
// xxxxxxxx = Supported version
|
||||
// xxxxxxxx = Max packet length
|
||||
// xxxxxxxx = Expected mode
|
||||
// 6 dwords reserved space
|
||||
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
|
||||
|
||||
Step = 2;
|
||||
byte[] HelloResponse = BuildHelloResponsePacket(QualcommSaharaMode.ImageTransferPending);
|
||||
Serial.SendData(HelloResponse);
|
||||
|
||||
Step = 3;
|
||||
using FileStream FileStream = new(Path, FileMode.Open, FileAccess.Read);
|
||||
while (true)
|
||||
{
|
||||
Step = 4;
|
||||
byte[] ReadDataRequest = Serial.GetResponse(null);
|
||||
UInt32 ResponseID = ByteOperations.ReadUInt32(ReadDataRequest, 0);
|
||||
if (ResponseID == 4)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ResponseID != 3)
|
||||
{
|
||||
Step = 5;
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
Offset = ByteOperations.ReadUInt32(ReadDataRequest, 0x0C);
|
||||
Length = ByteOperations.ReadUInt32(ReadDataRequest, 0x10);
|
||||
if ((ImageBuffer == null) || (ImageBuffer.Length != Length))
|
||||
{
|
||||
ImageBuffer = new byte[Length];
|
||||
}
|
||||
|
||||
if (FileStream.Position != Offset)
|
||||
{
|
||||
FileStream.Seek(Offset, SeekOrigin.Begin);
|
||||
}
|
||||
|
||||
Step = 6;
|
||||
FileStream.Read(ImageBuffer, 0, (int)Length);
|
||||
|
||||
Step = 7;
|
||||
Serial.SendData(ImageBuffer);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex, LogType.FileAndConsole, Step.ToString() + " 0x" + Offset.ToString("X8") + " 0x" + Length.ToString("X8"));
|
||||
Result = false;
|
||||
}
|
||||
|
||||
if (Result)
|
||||
{
|
||||
LogFile.Log("Programmer loaded into phone memory", LogType.FileOnly);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public bool Handshake()
|
||||
{
|
||||
bool Result = true;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] Hello = Serial.GetResponse([0x01, 0x00, 0x00, 0x00]);
|
||||
|
||||
// Incoming Hello packet:
|
||||
// 00000001 = Hello command id
|
||||
// xxxxxxxx = Length
|
||||
// xxxxxxxx = Protocol version
|
||||
// xxxxxxxx = Supported version
|
||||
// xxxxxxxx = Max packet length
|
||||
// xxxxxxxx = Expected mode
|
||||
// 6 dwords reserved space
|
||||
LogFile.Log("Protocol: 0x" + ByteOperations.ReadUInt32(Hello, 0x08).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Supported: 0x" + ByteOperations.ReadUInt32(Hello, 0x0C).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("MaxLength: 0x" + ByteOperations.ReadUInt32(Hello, 0x10).ToString("X8"), LogType.FileOnly);
|
||||
LogFile.Log("Mode: 0x" + ByteOperations.ReadUInt32(Hello, 0x14).ToString("X8"), LogType.FileOnly);
|
||||
|
||||
byte[] HelloResponse = BuildHelloResponsePacket(QualcommSaharaMode.ImageTransferPending);
|
||||
|
||||
byte[] Ready = Serial.SendCommand(HelloResponse, [0x03, 0x00, 0x00, 0x00]);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Result = false;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void ResetSahara()
|
||||
{
|
||||
Serial.SendCommand(BuildCommandPacket(QualcommSaharaCommand.ResetRequest), [0x08, 0x00, 0x00, 0x00]);
|
||||
}
|
||||
|
||||
public void SwitchMode(QualcommSaharaMode Mode)
|
||||
{
|
||||
byte[] SwitchMode = new byte[0x04];
|
||||
ByteOperations.WriteUInt32(SwitchMode, 0x00, (UInt32)Mode);
|
||||
byte[] SwitchModeCommand = BuildCommandPacket(QualcommSaharaCommand.SwitchMode, SwitchMode);
|
||||
|
||||
byte[] ResponsePattern = null;
|
||||
switch (Mode)
|
||||
{
|
||||
case QualcommSaharaMode.ImageTransferPending:
|
||||
ResponsePattern = [0x04, 0x00, 0x00, 0x00];
|
||||
break;
|
||||
case QualcommSaharaMode.MemoryDebug:
|
||||
ResponsePattern = [0x09, 0x00, 0x00, 0x00];
|
||||
break;
|
||||
case QualcommSaharaMode.Command:
|
||||
ResponsePattern = [0x0B, 0x00, 0x00, 0x00];
|
||||
break;
|
||||
}
|
||||
Serial.SendCommand(SwitchModeCommand, ResponsePattern);
|
||||
}
|
||||
|
||||
public void StartProgrammer()
|
||||
{
|
||||
LogFile.Log("Starting programmer", LogType.FileAndConsole);
|
||||
byte[] DoneCommand = BuildCommandPacket(QualcommSaharaCommand.DoneRequest);
|
||||
bool Started = false;
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
count++;
|
||||
try
|
||||
{
|
||||
byte[] DoneResponse = Serial.SendCommand(DoneCommand, [0x06, 0x00, 0x00, 0x00]);
|
||||
Started = true;
|
||||
}
|
||||
catch (BadConnectionException)
|
||||
{
|
||||
LogFile.Log("Problem while starting programmer. Attempting again.", LogType.FileAndConsole);
|
||||
}
|
||||
} while (!Started && count < 3);
|
||||
if (count >= 3 && !Started)
|
||||
{
|
||||
LogFile.Log("Maximum number of attempts to start the programmer exceeded.", LogType.FileAndConsole);
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
LogFile.Log("Programmer being launched on phone", LogType.FileOnly);
|
||||
}
|
||||
|
||||
public async Task<bool> LoadProgrammer(string ProgrammerPath)
|
||||
{
|
||||
bool SendImageResult = await Task.Run(() => SendImage(ProgrammerPath));
|
||||
if (!SendImageResult)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
await Task.Run(() => StartProgrammer());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// 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
|
||||
{
|
||||
internal enum QualcommSaharaCommand : uint
|
||||
{
|
||||
HelloRequest = 0x01,
|
||||
HelloResponse = 0x02,
|
||||
ReadData = 0x03,
|
||||
EndTransfer = 0x04,
|
||||
DoneRequest = 0x05,
|
||||
DoneResponse = 0x06,
|
||||
ResetRequest = 0x07,
|
||||
ResetResponse = 0x08,
|
||||
MemoryDebug = 0x09,
|
||||
MemoryRead = 0x0A,
|
||||
CommandReady = 0x0B,
|
||||
SwitchMode = 0x0C,
|
||||
ExecuteRequest = 0x0D,
|
||||
ExecuteResponse = 0x0E,
|
||||
ExecuteData = 0x0F,
|
||||
MemoryDebug64 = 0x10,
|
||||
MemoryRead64 = 0x11,
|
||||
MemoryReadData64 = 0x12,
|
||||
ResetStateMachineIdentifier = 0x13
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal enum QualcommSaharaMode : uint
|
||||
{
|
||||
ImageTransferPending = 0x00,
|
||||
ImagetransferComplete = 0x01,
|
||||
MemoryDebug = 0x02,
|
||||
Command = 0x03
|
||||
}
|
||||
}
|
||||
@@ -1,379 +1,379 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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 System.IO.Ports;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class QualcommSerial : IDisposable
|
||||
{
|
||||
private bool Disposed = false;
|
||||
private readonly SerialPort Port = null;
|
||||
private readonly USBDevice USBDevice = null;
|
||||
private readonly CRC16 CRC16;
|
||||
|
||||
public bool EncodeCommands = true;
|
||||
public bool DecodeResponses = true;
|
||||
|
||||
public QualcommSerial(string DevicePath)
|
||||
{
|
||||
CRC16 = new CRC16(0x1189, 0xFFFF, 0xFFFF);
|
||||
|
||||
string[] DevicePathElements = DevicePath.Split(new char[] { '#' });
|
||||
if (string.Equals(DevicePathElements[3], "{86E0D1E0-8089-11D0-9CE4-08003E301F73}", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
string PortName = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\" + DevicePathElements[1] + @"\" + DevicePathElements[2] + @"\Device Parameters", "PortName", null);
|
||||
if (PortName != null)
|
||||
{
|
||||
Port = new SerialPort(PortName, 115200)
|
||||
{
|
||||
ReadTimeout = 1000,
|
||||
WriteTimeout = 1000
|
||||
};
|
||||
Port.Open();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.USBDevice = new USBDevice(DevicePath);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
public void SendData(byte[] Data)
|
||||
{
|
||||
byte[] FormattedData = EncodeCommands ? FormatCommand(Data) : Data;
|
||||
Port?.Write(FormattedData, 0, FormattedData.Length);
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.OutputPipe.Write(FormattedData);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SendCommand(byte[] Command, byte[] ResponsePattern)
|
||||
{
|
||||
byte[] FormattedCommand = EncodeCommands ? FormatCommand(Command) : Command;
|
||||
Port?.Write(FormattedCommand, 0, FormattedCommand.Length);
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.OutputPipe.Write(FormattedCommand);
|
||||
}
|
||||
|
||||
return GetResponse(ResponsePattern);
|
||||
}
|
||||
|
||||
internal byte[] GetResponse(byte[] ResponsePattern)
|
||||
{
|
||||
byte[] ResponseBuffer = new byte[0x2000];
|
||||
int Length = 0;
|
||||
bool IsIncomplete = false;
|
||||
|
||||
do
|
||||
{
|
||||
IsIncomplete = false;
|
||||
|
||||
try
|
||||
{
|
||||
int BytesRead = 0;
|
||||
|
||||
if (Port != null)
|
||||
{
|
||||
BytesRead = Port.Read(ResponseBuffer, Length, ResponseBuffer.Length - Length);
|
||||
}
|
||||
|
||||
if (USBDevice != null)
|
||||
{
|
||||
BytesRead = USBDevice.InputPipe.Read(ResponseBuffer);
|
||||
}
|
||||
|
||||
if (BytesRead == 0)
|
||||
{
|
||||
LogFile.Log("Emergency mode of phone is ignoring us", LogType.FileAndConsole);
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
Length += BytesRead;
|
||||
byte[] DecodedResponse;
|
||||
if (DecodeResponses)
|
||||
{
|
||||
DecodedResponse = DecodeResponse(ResponseBuffer, (UInt32)Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
DecodedResponse = new byte[Length];
|
||||
Buffer.BlockCopy(ResponseBuffer, 0, DecodedResponse, 0, Length);
|
||||
}
|
||||
|
||||
if (ResponsePattern != null)
|
||||
{
|
||||
for (int i = 0; i < ResponsePattern.Length; i++)
|
||||
{
|
||||
if (DecodedResponse[i] != ResponsePattern[i])
|
||||
{
|
||||
byte[] LogResponse = new byte[DecodedResponse.Length < 0x10 ? DecodedResponse.Length : 0x10];
|
||||
LogFile.Log("Qualcomm serial response: " + Converter.ConvertHexToString(LogResponse, ""), LogType.FileOnly);
|
||||
LogFile.Log("Expected: " + Converter.ConvertHexToString(ResponsePattern, ""), LogType.FileOnly);
|
||||
throw new BadMessageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DecodedResponse;
|
||||
}
|
||||
catch (IncompleteMessageException)
|
||||
{
|
||||
IsIncomplete = true;
|
||||
}
|
||||
catch { } // Will be rethrown as BadConnectionException
|
||||
}
|
||||
while (IsIncomplete);
|
||||
|
||||
Port?.DiscardInBuffer();
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.InputPipe.Flush();
|
||||
}
|
||||
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
private byte[] FormatCommand(byte[] Command)
|
||||
{
|
||||
if ((Command == null) || (Command.Length == 0))
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
byte[] Decoded = new byte[(Command.Length * 2) + 4];
|
||||
int Length = 0;
|
||||
|
||||
Decoded[Length++] = 0x7E;
|
||||
|
||||
for (int i = 0; i < Command.Length; i++)
|
||||
{
|
||||
if ((Command[i] == 0x7D) || (Command[i] == 0x7E))
|
||||
{
|
||||
Decoded[Length++] = 0x7D;
|
||||
Decoded[Length++] = (byte)(Command[i] ^ 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decoded[Length++] = Command[i];
|
||||
}
|
||||
}
|
||||
|
||||
UInt16 Checksum = CRC16.CalculateChecksum(Command);
|
||||
if (((byte)(Checksum & 0xFF) == 0x7D) || ((byte)(Checksum & 0xFF) == 0x7E))
|
||||
{
|
||||
Decoded[Length++] = 0x7D;
|
||||
Decoded[Length++] = (byte)((Checksum & 0xFF) ^ 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decoded[Length++] = (byte)(Checksum & 0xFF);
|
||||
}
|
||||
|
||||
if (((byte)(Checksum >> 8) == 0x7D) || ((byte)(Checksum >> 8) == 0x7E))
|
||||
{
|
||||
Decoded[Length++] = 0x7D;
|
||||
Decoded[Length++] = (byte)((Checksum >> 8) ^ 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decoded[Length++] = (byte)(Checksum >> 8);
|
||||
}
|
||||
|
||||
Decoded[Length++] = 0x7E;
|
||||
|
||||
if (Length > 0)
|
||||
{
|
||||
byte[] Result = new byte[Length];
|
||||
Buffer.BlockCopy(Decoded, 0, Result, 0, Length);
|
||||
return Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] DecodeResponse(byte[] Response, UInt32 Length)
|
||||
{
|
||||
if ((Response == null) || (Response.Length == 0) || (Response[0] != 0x7E))
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
UInt32 SourceLength = Length;
|
||||
Length = 0;
|
||||
UInt32 SourcePos = 1;
|
||||
|
||||
byte[] Message = new byte[SourceLength];
|
||||
|
||||
while (SourcePos < SourceLength)
|
||||
{
|
||||
if (Response[SourcePos] == 0x7E)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Message[Length++] = Response[SourcePos] == 0x7D ? (byte)(Response[++SourcePos] ^ 0x20) : Response[SourcePos];
|
||||
|
||||
SourcePos++;
|
||||
}
|
||||
|
||||
if (SourcePos == SourceLength)
|
||||
{
|
||||
throw new IncompleteMessageException();
|
||||
}
|
||||
|
||||
if (Length < 3)
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
byte[] TrimmedMessage = new byte[Length - 2];
|
||||
Buffer.BlockCopy(Message, 0, TrimmedMessage, 0, (int)(Length - 2));
|
||||
|
||||
UInt16 Checksum = CRC16.CalculateChecksum(TrimmedMessage);
|
||||
if (((byte)(Checksum & 0xFF) != Message[Length - 2]) || ((byte)(Checksum >> 8) != Message[Length - 1]))
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
return TrimmedMessage;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~QualcommSerial()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Port?.Close();
|
||||
USBDevice?.Dispose();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// Other disposables
|
||||
}
|
||||
|
||||
// Clean unmanaged resources here.
|
||||
Close();
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
internal void SetTimeOut(int v)
|
||||
{
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.ControlPipeTimeout = v;
|
||||
}
|
||||
|
||||
if (Port != null)
|
||||
{
|
||||
Port.ReadTimeout = v;
|
||||
Port.WriteTimeout = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class IncompleteMessageException : Exception { public IncompleteMessageException() { } public IncompleteMessageException(string message) : base(message) { } public IncompleteMessageException(string message, Exception innerException) : base(message, innerException) { } }
|
||||
public class BadMessageException : Exception { public BadMessageException() { } public BadMessageException(string message) : base(message) { } public BadMessageException(string message, Exception innerException) : base(message, innerException) { } }
|
||||
public class BadConnectionException : Exception { public BadConnectionException() { } public BadConnectionException(string message) : base(message) { } public BadConnectionException(string message, Exception innerException) : base(message, innerException) { } }
|
||||
|
||||
public class CRC16
|
||||
{
|
||||
private readonly UInt16[] ChecksumTable =
|
||||
new UInt16[] {
|
||||
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||
};
|
||||
|
||||
private readonly UInt16 Seed, FinalXor;
|
||||
|
||||
public CRC16(UInt16 Polynomial, UInt16 Seed, UInt16 FinalXor)
|
||||
{
|
||||
this.Seed = Seed;
|
||||
this.FinalXor = FinalXor;
|
||||
}
|
||||
|
||||
public UInt16 CalculateChecksum(byte[] Bytes)
|
||||
{
|
||||
UInt16 Crc = Seed;
|
||||
for (int i = 0; i < Bytes.Length; ++i)
|
||||
{
|
||||
Crc = (UInt16)((Crc >> 8) ^ ChecksumTable[(byte)(Crc ^ Bytes[i])]); // Qualcomm implementation
|
||||
}
|
||||
return (UInt16)(Crc ^ FinalXor);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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 System.IO.Ports;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class QualcommSerial : IDisposable
|
||||
{
|
||||
private bool Disposed = false;
|
||||
private readonly SerialPort Port = null;
|
||||
private readonly USBDevice USBDevice = null;
|
||||
private readonly CRC16 CRC16;
|
||||
|
||||
public bool EncodeCommands = true;
|
||||
public bool DecodeResponses = true;
|
||||
|
||||
public QualcommSerial(string DevicePath)
|
||||
{
|
||||
CRC16 = new CRC16(0x1189, 0xFFFF, 0xFFFF);
|
||||
|
||||
string[] DevicePathElements = DevicePath.Split(['#']);
|
||||
if (string.Equals(DevicePathElements[3], "{86E0D1E0-8089-11D0-9CE4-08003E301F73}", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
string PortName = (string)Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\" + DevicePathElements[1] + @"\" + DevicePathElements[2] + @"\Device Parameters", "PortName", null);
|
||||
if (PortName != null)
|
||||
{
|
||||
Port = new SerialPort(PortName, 115200)
|
||||
{
|
||||
ReadTimeout = 1000,
|
||||
WriteTimeout = 1000
|
||||
};
|
||||
Port.Open();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.USBDevice = new USBDevice(DevicePath);
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
public void SendData(byte[] Data)
|
||||
{
|
||||
byte[] FormattedData = EncodeCommands ? FormatCommand(Data) : Data;
|
||||
Port?.Write(FormattedData, 0, FormattedData.Length);
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.OutputPipe.Write(FormattedData);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] SendCommand(byte[] Command, byte[] ResponsePattern)
|
||||
{
|
||||
byte[] FormattedCommand = EncodeCommands ? FormatCommand(Command) : Command;
|
||||
Port?.Write(FormattedCommand, 0, FormattedCommand.Length);
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.OutputPipe.Write(FormattedCommand);
|
||||
}
|
||||
|
||||
return GetResponse(ResponsePattern);
|
||||
}
|
||||
|
||||
internal byte[] GetResponse(byte[] ResponsePattern, int Length = 0x2000)
|
||||
{
|
||||
byte[] ResponseBuffer = new byte[Length];
|
||||
Length = 0;
|
||||
bool IsIncomplete = false;
|
||||
|
||||
do
|
||||
{
|
||||
IsIncomplete = false;
|
||||
|
||||
try
|
||||
{
|
||||
int BytesRead = 0;
|
||||
|
||||
if (Port != null)
|
||||
{
|
||||
BytesRead = Port.Read(ResponseBuffer, Length, ResponseBuffer.Length - Length);
|
||||
}
|
||||
|
||||
if (USBDevice != null)
|
||||
{
|
||||
BytesRead = USBDevice.InputPipe.Read(ResponseBuffer);
|
||||
}
|
||||
|
||||
if (BytesRead == 0)
|
||||
{
|
||||
LogFile.Log("Emergency mode of phone is ignoring us", LogType.FileAndConsole);
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
Length += BytesRead;
|
||||
byte[] DecodedResponse;
|
||||
if (DecodeResponses)
|
||||
{
|
||||
DecodedResponse = DecodeResponse(ResponseBuffer, (UInt32)Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
DecodedResponse = new byte[Length];
|
||||
Buffer.BlockCopy(ResponseBuffer, 0, DecodedResponse, 0, Length);
|
||||
}
|
||||
|
||||
if (ResponsePattern != null)
|
||||
{
|
||||
for (int i = 0; i < ResponsePattern.Length; i++)
|
||||
{
|
||||
if (DecodedResponse[i] != ResponsePattern[i])
|
||||
{
|
||||
byte[] LogResponse = new byte[DecodedResponse.Length < 0x10 ? DecodedResponse.Length : 0x10];
|
||||
LogFile.Log("Qualcomm serial response: " + Converter.ConvertHexToString(LogResponse, ""), LogType.FileOnly);
|
||||
LogFile.Log("Expected: " + Converter.ConvertHexToString(ResponsePattern, ""), LogType.FileOnly);
|
||||
throw new BadMessageException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DecodedResponse;
|
||||
}
|
||||
catch (IncompleteMessageException)
|
||||
{
|
||||
IsIncomplete = true;
|
||||
}
|
||||
catch { } // Will be rethrown as BadConnectionException
|
||||
}
|
||||
while (IsIncomplete);
|
||||
|
||||
Port?.DiscardInBuffer();
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.InputPipe.Flush();
|
||||
}
|
||||
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
private byte[] FormatCommand(byte[] Command)
|
||||
{
|
||||
if ((Command == null) || (Command.Length == 0))
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
byte[] Decoded = new byte[(Command.Length * 2) + 4];
|
||||
int Length = 0;
|
||||
|
||||
Decoded[Length++] = 0x7E;
|
||||
|
||||
for (int i = 0; i < Command.Length; i++)
|
||||
{
|
||||
if ((Command[i] == 0x7D) || (Command[i] == 0x7E))
|
||||
{
|
||||
Decoded[Length++] = 0x7D;
|
||||
Decoded[Length++] = (byte)(Command[i] ^ 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decoded[Length++] = Command[i];
|
||||
}
|
||||
}
|
||||
|
||||
UInt16 Checksum = CRC16.CalculateChecksum(Command);
|
||||
if (((byte)(Checksum & 0xFF) == 0x7D) || ((byte)(Checksum & 0xFF) == 0x7E))
|
||||
{
|
||||
Decoded[Length++] = 0x7D;
|
||||
Decoded[Length++] = (byte)((Checksum & 0xFF) ^ 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decoded[Length++] = (byte)(Checksum & 0xFF);
|
||||
}
|
||||
|
||||
if (((byte)(Checksum >> 8) == 0x7D) || ((byte)(Checksum >> 8) == 0x7E))
|
||||
{
|
||||
Decoded[Length++] = 0x7D;
|
||||
Decoded[Length++] = (byte)((Checksum >> 8) ^ 0x20);
|
||||
}
|
||||
else
|
||||
{
|
||||
Decoded[Length++] = (byte)(Checksum >> 8);
|
||||
}
|
||||
|
||||
Decoded[Length++] = 0x7E;
|
||||
|
||||
if (Length > 0)
|
||||
{
|
||||
byte[] Result = new byte[Length];
|
||||
Buffer.BlockCopy(Decoded, 0, Result, 0, Length);
|
||||
return Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] DecodeResponse(byte[] Response, UInt32 Length)
|
||||
{
|
||||
if ((Response == null) || (Response.Length == 0) || (Response[0] != 0x7E))
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
UInt32 SourceLength = Length;
|
||||
Length = 0;
|
||||
UInt32 SourcePos = 1;
|
||||
|
||||
byte[] Message = new byte[SourceLength];
|
||||
|
||||
while (SourcePos < SourceLength)
|
||||
{
|
||||
if (Response[SourcePos] == 0x7E)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Message[Length++] = Response[SourcePos] == 0x7D ? (byte)(Response[++SourcePos] ^ 0x20) : Response[SourcePos];
|
||||
|
||||
SourcePos++;
|
||||
}
|
||||
|
||||
if (SourcePos == SourceLength)
|
||||
{
|
||||
throw new IncompleteMessageException();
|
||||
}
|
||||
|
||||
if (Length < 3)
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
byte[] TrimmedMessage = new byte[Length - 2];
|
||||
Buffer.BlockCopy(Message, 0, TrimmedMessage, 0, (int)(Length - 2));
|
||||
|
||||
UInt16 Checksum = CRC16.CalculateChecksum(TrimmedMessage);
|
||||
if (((byte)(Checksum & 0xFF) != Message[Length - 2]) || ((byte)(Checksum >> 8) != Message[Length - 1]))
|
||||
{
|
||||
throw new BadMessageException();
|
||||
}
|
||||
|
||||
return TrimmedMessage;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~QualcommSerial()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Port?.Close();
|
||||
USBDevice?.Dispose();
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (disposing)
|
||||
{
|
||||
// Other disposables
|
||||
}
|
||||
|
||||
// Clean unmanaged resources here.
|
||||
Close();
|
||||
|
||||
Disposed = true;
|
||||
}
|
||||
|
||||
internal void SetTimeOut(int v)
|
||||
{
|
||||
if (USBDevice != null)
|
||||
{
|
||||
USBDevice.ControlPipeTimeout = v;
|
||||
}
|
||||
|
||||
if (Port != null)
|
||||
{
|
||||
Port.ReadTimeout = v;
|
||||
Port.WriteTimeout = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class IncompleteMessageException : Exception { public IncompleteMessageException() { } public IncompleteMessageException(string message) : base(message) { } public IncompleteMessageException(string message, Exception innerException) : base(message, innerException) { } }
|
||||
public class BadMessageException : Exception { public BadMessageException() { } public BadMessageException(string message) : base(message) { } public BadMessageException(string message, Exception innerException) : base(message, innerException) { } }
|
||||
public class BadConnectionException : Exception { public BadConnectionException() { } public BadConnectionException(string message) : base(message) { } public BadConnectionException(string message, Exception innerException) : base(message, innerException) { } }
|
||||
|
||||
public class CRC16
|
||||
{
|
||||
private readonly UInt16[] ChecksumTable =
|
||||
[
|
||||
0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
|
||||
0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
|
||||
0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
|
||||
0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
|
||||
0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
|
||||
0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
|
||||
0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
|
||||
0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
|
||||
0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
|
||||
0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
|
||||
0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
|
||||
0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
|
||||
0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
|
||||
0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
|
||||
0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
|
||||
0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
|
||||
0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
|
||||
0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
|
||||
0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
|
||||
0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
|
||||
0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
|
||||
0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
|
||||
0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
|
||||
0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
|
||||
0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
|
||||
0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
|
||||
0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
|
||||
0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
|
||||
0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
|
||||
0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
|
||||
0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
|
||||
0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
|
||||
];
|
||||
|
||||
private readonly UInt16 Seed, FinalXor;
|
||||
|
||||
public CRC16(UInt16 Polynomial, UInt16 Seed, UInt16 FinalXor)
|
||||
{
|
||||
this.Seed = Seed;
|
||||
this.FinalXor = FinalXor;
|
||||
}
|
||||
|
||||
public UInt16 CalculateChecksum(byte[] Bytes)
|
||||
{
|
||||
UInt16 Crc = Seed;
|
||||
for (int i = 0; i < Bytes.Length; ++i)
|
||||
{
|
||||
Crc = (UInt16)((Crc >> 8) ^ ChecksumTable[(byte)(Crc ^ Bytes[i])]); // Qualcomm implementation
|
||||
}
|
||||
return (UInt16)(Crc ^ FinalXor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,119 +1,119 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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
|
||||
{
|
||||
internal class SBL1 : QualcommPartition
|
||||
{
|
||||
internal SBL1(byte[] Binary) : base(Binary, 0x2800) { }
|
||||
|
||||
internal byte[] GenerateExtraSector(byte[] PartitionHeader)
|
||||
{
|
||||
UInt32? Offset = ByteOperations.FindPattern(Binary,
|
||||
new byte[] {
|
||||
0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
}, null, null);
|
||||
if (Offset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 PartitionLoaderTableOffset = (UInt32)Offset;
|
||||
|
||||
byte[] FoundPattern = new byte[0x10];
|
||||
Offset = ByteOperations.FindPattern(Binary,
|
||||
new byte[] {
|
||||
0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
},
|
||||
new byte[] {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
},
|
||||
FoundPattern);
|
||||
if (Offset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 SharedMemoryAddress = ByteOperations.ReadUInt32(FoundPattern, 0x0C);
|
||||
UInt32 GlobalIsSecurityEnabledAddress = SharedMemoryAddress + 0x28;
|
||||
|
||||
Offset = ByteOperations.FindPattern(Binary,
|
||||
new byte[] {
|
||||
0x01, 0xFF, 0xA0, 0xE3, 0xFF, 0xFF, 0xA0, 0xE1, 0x1C, 0xD0, 0x8D, 0xE2, 0xF0, 0x4F, 0xBD, 0xE8,
|
||||
0x1E, 0xFF, 0x2F, 0xE1
|
||||
},
|
||||
new byte[] {
|
||||
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
},
|
||||
null);
|
||||
if (Offset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 ReturnAddress = (UInt32)Offset - ImageOffset + ImageAddress;
|
||||
|
||||
byte[] Sector = new byte[0x200];
|
||||
Array.Clear(Sector, 0, 0x200);
|
||||
|
||||
byte[] Content = new byte[] {
|
||||
0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0xBD, 0x02, 0x00,
|
||||
0xD8, 0x01, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE3, 0x3C, 0x10, 0x9F, 0xE5,
|
||||
0x00, 0x00, 0xC1, 0xE5, 0x38, 0x00, 0x9F, 0xE5, 0x38, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5,
|
||||
0x34, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x30, 0x00, 0x9F, 0xE5, 0x20, 0x10, 0x9F, 0xE5,
|
||||
0x2C, 0x30, 0x9F, 0xE5, 0x00, 0x20, 0x90, 0xE5, 0x00, 0x20, 0x81, 0xE5, 0x04, 0x00, 0x80, 0xE2,
|
||||
0x04, 0x10, 0x81, 0xE2, 0x03, 0x00, 0x50, 0xE1, 0xF9, 0xFF, 0xFF, 0xBA, 0x14, 0xF0, 0x9F, 0xE5,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x90, 0xBF, 0x02, 0x00, 0xD0, 0xBF, 0x02, 0x00,
|
||||
0xA0, 0xBD, 0x02, 0x00, 0xA0, 0xBE, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
byte[] PartitionTypeGuid = new byte[] {
|
||||
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74
|
||||
};
|
||||
|
||||
Buffer.BlockCopy(Content, 0, Sector, 0, Content.Length);
|
||||
|
||||
// Overwrite first part of partition-header with model-specific header
|
||||
Buffer.BlockCopy(PartitionHeader, 0, Sector, 0, PartitionHeader.Length);
|
||||
|
||||
ByteOperations.WriteUInt32(Sector, 0x70, GlobalIsSecurityEnabledAddress);
|
||||
ByteOperations.WriteUInt32(Sector, 0x88, ReturnAddress);
|
||||
|
||||
Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xA0, 0x50);
|
||||
ByteOperations.WriteUInt32(Sector, 0xA0 + 0x30, 0);
|
||||
|
||||
Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xF0, 0x50);
|
||||
ByteOperations.WriteUInt32(Sector, 0xF0 + 0x2C, 0);
|
||||
ByteOperations.WriteUInt32(Sector, 0xF0 + 0x38, 0x210F0);
|
||||
|
||||
Buffer.BlockCopy(PartitionTypeGuid, 0, Sector, 0x190, 0x10);
|
||||
|
||||
ByteOperations.WriteUInt32(Sector, 0x1FC, 0x0002BD28);
|
||||
|
||||
return Sector;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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
|
||||
{
|
||||
internal class SBL1 : QualcommPartition
|
||||
{
|
||||
internal SBL1(byte[] Binary) : base(Binary, 0x2800) { }
|
||||
|
||||
internal byte[] GenerateExtraSector(byte[] PartitionHeader)
|
||||
{
|
||||
UInt32? Offset = ByteOperations.FindPattern(Binary,
|
||||
[
|
||||
0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
], null, null);
|
||||
if (Offset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 PartitionLoaderTableOffset = (UInt32)Offset;
|
||||
|
||||
byte[] FoundPattern = new byte[0x10];
|
||||
Offset = ByteOperations.FindPattern(Binary,
|
||||
[
|
||||
0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
],
|
||||
[
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF
|
||||
],
|
||||
FoundPattern);
|
||||
if (Offset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 SharedMemoryAddress = ByteOperations.ReadUInt32(FoundPattern, 0x0C);
|
||||
UInt32 GlobalIsSecurityEnabledAddress = SharedMemoryAddress + 0x28;
|
||||
|
||||
Offset = ByteOperations.FindPattern(Binary,
|
||||
[
|
||||
0x01, 0xFF, 0xA0, 0xE3, 0xFF, 0xFF, 0xA0, 0xE1, 0x1C, 0xD0, 0x8D, 0xE2, 0xF0, 0x4F, 0xBD, 0xE8,
|
||||
0x1E, 0xFF, 0x2F, 0xE1
|
||||
],
|
||||
[
|
||||
0x00, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
],
|
||||
null);
|
||||
if (Offset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
UInt32 ReturnAddress = (UInt32)Offset - ImageOffset + ImageAddress;
|
||||
|
||||
byte[] Sector = new byte[0x200];
|
||||
Array.Clear(Sector, 0, 0x200);
|
||||
|
||||
byte[] Content = [
|
||||
0x16, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0xBD, 0x02, 0x00,
|
||||
0xD8, 0x01, 0x00, 0x00, 0xD8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0xE3, 0x3C, 0x10, 0x9F, 0xE5,
|
||||
0x00, 0x00, 0xC1, 0xE5, 0x38, 0x00, 0x9F, 0xE5, 0x38, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5,
|
||||
0x34, 0x10, 0x9F, 0xE5, 0x00, 0x00, 0x81, 0xE5, 0x30, 0x00, 0x9F, 0xE5, 0x20, 0x10, 0x9F, 0xE5,
|
||||
0x2C, 0x30, 0x9F, 0xE5, 0x00, 0x20, 0x90, 0xE5, 0x00, 0x20, 0x81, 0xE5, 0x04, 0x00, 0x80, 0xE2,
|
||||
0x04, 0x10, 0x81, 0xE2, 0x03, 0x00, 0x50, 0xE1, 0xF9, 0xFF, 0xFF, 0xBA, 0x14, 0xF0, 0x9F, 0xE5,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0x00, 0x90, 0xBF, 0x02, 0x00, 0xD0, 0xBF, 0x02, 0x00,
|
||||
0xA0, 0xBD, 0x02, 0x00, 0xA0, 0xBE, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
];
|
||||
|
||||
byte[] PartitionTypeGuid = [
|
||||
0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74, 0x74
|
||||
];
|
||||
|
||||
Buffer.BlockCopy(Content, 0, Sector, 0, Content.Length);
|
||||
|
||||
// Overwrite first part of partition-header with model-specific header
|
||||
Buffer.BlockCopy(PartitionHeader, 0, Sector, 0, PartitionHeader.Length);
|
||||
|
||||
ByteOperations.WriteUInt32(Sector, 0x70, GlobalIsSecurityEnabledAddress);
|
||||
ByteOperations.WriteUInt32(Sector, 0x88, ReturnAddress);
|
||||
|
||||
Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xA0, 0x50);
|
||||
ByteOperations.WriteUInt32(Sector, 0xA0 + 0x30, 0);
|
||||
|
||||
Buffer.BlockCopy(Binary, (int)PartitionLoaderTableOffset, Sector, 0xF0, 0x50);
|
||||
ByteOperations.WriteUInt32(Sector, 0xF0 + 0x2C, 0);
|
||||
ByteOperations.WriteUInt32(Sector, 0xF0 + 0x38, 0x210F0);
|
||||
|
||||
Buffer.BlockCopy(PartitionTypeGuid, 0, Sector, 0x190, 0x10);
|
||||
|
||||
ByteOperations.WriteUInt32(Sector, 0x1FC, 0x0002BD28);
|
||||
|
||||
return Sector;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,56 +1,56 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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
|
||||
{
|
||||
internal class SBL2
|
||||
{
|
||||
internal byte[] Binary;
|
||||
|
||||
internal SBL2(byte[] Binary)
|
||||
{
|
||||
this.Binary = Binary;
|
||||
}
|
||||
|
||||
// Magic!
|
||||
internal byte[] Patch()
|
||||
{
|
||||
UInt32? PatchOffset = ByteOperations.FindPattern(Binary,
|
||||
new byte[] {
|
||||
0xFF, 0xFF, 0xFF, 0xE3, 0x01, 0x0E, 0x42, 0xE3, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1
|
||||
},
|
||||
new byte[] {
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
},
|
||||
null);
|
||||
|
||||
if (PatchOffset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 8, 4);
|
||||
|
||||
return Binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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
|
||||
{
|
||||
internal class SBL2
|
||||
{
|
||||
internal byte[] Binary;
|
||||
|
||||
internal SBL2(byte[] Binary)
|
||||
{
|
||||
this.Binary = Binary;
|
||||
}
|
||||
|
||||
// Magic!
|
||||
internal byte[] Patch()
|
||||
{
|
||||
UInt32? PatchOffset = ByteOperations.FindPattern(Binary,
|
||||
[
|
||||
0xFF, 0xFF, 0xFF, 0xE3, 0x01, 0x0E, 0x42, 0xE3, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1
|
||||
],
|
||||
[
|
||||
0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
],
|
||||
null);
|
||||
|
||||
if (PatchOffset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 8, 4);
|
||||
|
||||
return Binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +1,88 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class SBL3
|
||||
{
|
||||
internal byte[] Binary;
|
||||
|
||||
internal SBL3(byte[] Binary)
|
||||
{
|
||||
this.Binary = Binary;
|
||||
}
|
||||
|
||||
internal SBL3(string FileName)
|
||||
{
|
||||
Binary = null;
|
||||
|
||||
// First try to parse as FFU
|
||||
try
|
||||
{
|
||||
if (FFU.IsFFU(FileName))
|
||||
{
|
||||
FFU FFUFile = new(FileName);
|
||||
Binary = FFUFile.GetPartition("SBL3");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// If not succeeded, then try to parse it as raw image
|
||||
if (Binary == null)
|
||||
{
|
||||
byte[] SBL3Pattern = new byte[] { 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
byte[] SBL3Mask = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||
|
||||
UInt32? Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out byte[] SBL3Header);
|
||||
|
||||
if (Offset != null)
|
||||
{
|
||||
UInt32 Length = ByteOperations.ReadUInt32(SBL3Header, 0x10) + 0x28; // SBL3 Image Size + Header Size
|
||||
Binary = new byte[Length];
|
||||
|
||||
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
|
||||
Stream.Seek((long)Offset, SeekOrigin.Begin);
|
||||
Stream.Read(Binary, 0, (int)Length);
|
||||
Stream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Magic!
|
||||
internal byte[] Patch()
|
||||
{
|
||||
UInt32? PatchOffset = ByteOperations.FindPattern(Binary,
|
||||
new byte[] { 0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1 },
|
||||
null, null);
|
||||
|
||||
if (PatchOffset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 4, 4);
|
||||
|
||||
return Binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.IO;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class SBL3
|
||||
{
|
||||
internal byte[] Binary;
|
||||
|
||||
internal SBL3(byte[] Binary)
|
||||
{
|
||||
this.Binary = Binary;
|
||||
}
|
||||
|
||||
internal SBL3(string FileName)
|
||||
{
|
||||
Binary = null;
|
||||
|
||||
// First try to parse as FFU
|
||||
try
|
||||
{
|
||||
if (FFU.IsFFU(FileName))
|
||||
{
|
||||
FFU FFUFile = new(FileName);
|
||||
Binary = FFUFile.GetPartition("SBL3");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
// If not succeeded, then try to parse it as raw image
|
||||
if (Binary == null)
|
||||
{
|
||||
byte[] SBL3Pattern = [0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF];
|
||||
byte[] SBL3Mask = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF];
|
||||
|
||||
UInt32? Offset = ByteOperations.FindPatternInFile(FileName, SBL3Pattern, SBL3Mask, out byte[] SBL3Header);
|
||||
|
||||
if (Offset != null)
|
||||
{
|
||||
UInt32 Length = ByteOperations.ReadUInt32(SBL3Header, 0x10) + 0x28; // SBL3 Image Size + Header Size
|
||||
Binary = new byte[Length];
|
||||
|
||||
FileStream Stream = new(FileName, FileMode.Open, FileAccess.Read);
|
||||
Stream.Seek((long)Offset, SeekOrigin.Begin);
|
||||
Stream.Read(Binary, 0, (int)Length);
|
||||
Stream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Magic!
|
||||
internal byte[] Patch()
|
||||
{
|
||||
UInt32? PatchOffset = ByteOperations.FindPattern(Binary,
|
||||
[0x04, 0x00, 0x9F, 0xE5, 0x28, 0x00, 0xD0, 0xE5, 0x1E, 0xFF, 0x2F, 0xE1],
|
||||
null, null);
|
||||
|
||||
if (PatchOffset == null)
|
||||
{
|
||||
throw new BadImageFormatException();
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0xA0, 0xE3 }, 0, Binary, (int)PatchOffset + 4, 4);
|
||||
|
||||
return Binary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
@@ -1,51 +1,51 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("WPinternals")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WPinternals")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018-2019")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("2.9.*")]
|
||||
// [assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("WPinternals")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("WPinternals")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2018-2023")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.0.*")]
|
||||
// [assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,63 +1,63 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WPinternals.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WPinternals.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WPinternals.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WPinternals.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,117 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
@@ -1,26 +1,26 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WPinternals.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.5.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WPinternals.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.5.0.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
@@ -1,68 +1,68 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.Collections.Generic;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class Terminal
|
||||
{
|
||||
public static TerminalResponse Parse(byte[] Buffer, int Offset)
|
||||
{
|
||||
TerminalResponse Response = new();
|
||||
|
||||
// Get root node
|
||||
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))
|
||||
{
|
||||
// Get subnodes
|
||||
while (Index < End)
|
||||
{
|
||||
NodeNumber = BitConverter.ToInt32(Buffer, Index);
|
||||
NodeSize = BitConverter.ToInt32(Buffer, Index + 4);
|
||||
byte[] Raw = new byte[NodeSize];
|
||||
Array.Copy(Buffer, Index + 8, Raw, 0, NodeSize);
|
||||
Response.RawEntries.Add(NodeNumber, Raw);
|
||||
Index += NodeSize + 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse subnodes
|
||||
Response.RawEntries.TryGetValue(3, out Response.PublicId);
|
||||
Response.RawEntries.TryGetValue(7, out Response.RootKeyHash);
|
||||
|
||||
return Response;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TerminalResponse
|
||||
{
|
||||
public Dictionary<int, byte[]> RawEntries = new();
|
||||
public byte[] PublicId = null;
|
||||
public byte[] RootKeyHash = null;
|
||||
}
|
||||
}
|
||||
// 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.Collections.Generic;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class Terminal
|
||||
{
|
||||
public static TerminalResponse Parse(byte[] Buffer, int Offset)
|
||||
{
|
||||
TerminalResponse Response = new();
|
||||
|
||||
// Get root node
|
||||
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))
|
||||
{
|
||||
// Get subnodes
|
||||
while (Index < End)
|
||||
{
|
||||
NodeNumber = BitConverter.ToInt32(Buffer, Index);
|
||||
NodeSize = BitConverter.ToInt32(Buffer, Index + 4);
|
||||
byte[] Raw = new byte[NodeSize];
|
||||
Array.Copy(Buffer, Index + 8, Raw, 0, NodeSize);
|
||||
Response.RawEntries.Add(NodeNumber, Raw);
|
||||
Index += NodeSize + 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse subnodes
|
||||
Response.RawEntries.TryGetValue(3, out Response.PublicId);
|
||||
Response.RawEntries.TryGetValue(7, out Response.RootKeyHash);
|
||||
|
||||
return Response;
|
||||
}
|
||||
}
|
||||
|
||||
internal class TerminalResponse
|
||||
{
|
||||
public Dictionary<int, byte[]> RawEntries = new();
|
||||
public byte[] PublicId = null;
|
||||
public byte[] RootKeyHash = null;
|
||||
}
|
||||
}
|
||||
@@ -1,295 +1,296 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class TestCode
|
||||
{
|
||||
internal static async Task Test(System.Threading.SynchronizationContext UIContext)
|
||||
{
|
||||
// To avoid warnings when there is no code here.
|
||||
await Task.Run(() => { });
|
||||
|
||||
// PhoneNotifierViewModel Notifier = new PhoneNotifierViewModel();
|
||||
// Notifier.Start();
|
||||
// await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
// MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
}
|
||||
|
||||
internal static async Task RecoverBadGPT(string GPTPath, string LoadersPath)
|
||||
{
|
||||
byte[] GPT = File.ReadAllBytes(GPTPath);
|
||||
|
||||
PhoneNotifierViewModel PhoneNotifier = new();
|
||||
PhoneNotifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Qualcomm_Download);
|
||||
|
||||
byte[] RootKeyHash = null;
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
QualcommDownload Download2 = new((QualcommSerial)PhoneNotifier.CurrentModel);
|
||||
RootKeyHash = Download2.GetRKH();
|
||||
}
|
||||
|
||||
List<QualcommPartition> PossibleLoaders = null;
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
try
|
||||
{
|
||||
PossibleLoaders = QualcommLoaders.GetPossibleLoadersForRootKeyHash(LoadersPath, RootKeyHash);
|
||||
if (PossibleLoaders.Count == 0)
|
||||
{
|
||||
throw new Exception("Error: No matching loaders found for RootKeyHash.");
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
throw new Exception("Error: Unexpected error during scanning for loaders.");
|
||||
}
|
||||
}
|
||||
|
||||
QualcommSerial Serial = (QualcommSerial)PhoneNotifier.CurrentModel;
|
||||
QualcommDownload Download = new(Serial);
|
||||
if (Download.IsAlive())
|
||||
{
|
||||
int Attempt = 1;
|
||||
bool Result = false;
|
||||
foreach (QualcommPartition Loader in PossibleLoaders)
|
||||
{
|
||||
LogFile.Log("Attempt " + Attempt.ToString(), LogType.ConsoleOnly);
|
||||
|
||||
try
|
||||
{
|
||||
Download.SendToPhoneMemory(0x2A000000, Loader.Binary);
|
||||
Download.StartBootloader(0x2A000000);
|
||||
Result = true;
|
||||
LogFile.Log("Loader sent successfully", LogType.ConsoleOnly);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (Result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Attempt++;
|
||||
}
|
||||
Serial.Close();
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
LogFile.Log("Loader failed", LogType.ConsoleOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Failed to communicate to Qualcomm Emergency Download mode", LogType.ConsoleOnly);
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
await PhoneNotifier.WaitForArrival();
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
throw new WPinternalsException("Phone failed to switch to emergency flash mode.");
|
||||
}
|
||||
|
||||
// Flash bootloader
|
||||
QualcommSerial Serial2 = (QualcommSerial)PhoneNotifier.CurrentModel;
|
||||
Serial2.EncodeCommands = false;
|
||||
|
||||
QualcommFlasher Flasher = new(Serial2);
|
||||
|
||||
Flasher.Hello();
|
||||
Flasher.SetSecurityMode(0);
|
||||
Flasher.OpenPartition(0x21);
|
||||
|
||||
LogFile.Log("Partition opened.", LogType.ConsoleOnly);
|
||||
|
||||
LogFile.Log("Flash GPT at 0x" + ((UInt32)0x200).ToString("X8"), LogType.ConsoleOnly);
|
||||
Flasher.Flash(0x200, GPT, 0, 0x41FF); // Bad bounds-check in the flash-loader prohibits to write the last byte.
|
||||
|
||||
Flasher.ClosePartition();
|
||||
|
||||
LogFile.Log("Partition closed. Flashing ready. Rebooting.");
|
||||
|
||||
Flasher.Reboot();
|
||||
|
||||
Flasher.CloseSerial();
|
||||
}
|
||||
|
||||
internal static async Task RewriteGPT(string GPTPath)
|
||||
{
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
Notifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
|
||||
LogFile.Log("Writing GPT to the device.", LogType.ConsoleOnly);
|
||||
MassStorage.WriteSectors(1, GPTPath);
|
||||
}
|
||||
|
||||
internal static async Task RewriteMBRGPT()
|
||||
{
|
||||
FFU FFU = new(@"E:\Device Backups\Alpha\9200_1230.0025.9200.9825\RX100_9825.ffu");
|
||||
const string GPTPath = @"E:\Device Backups\Alpha\9200_1230.0025.9200.9825\CorrectGPT.bin";
|
||||
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
Notifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
|
||||
byte[] MBR = FFU.GetSectors(0, 1);
|
||||
LogFile.Log("Writing MBR to the device.", LogType.ConsoleOnly);
|
||||
MassStorage.WriteSectors(0, MBR);
|
||||
|
||||
LogFile.Log("Writing GPT to the device.", LogType.ConsoleOnly);
|
||||
MassStorage.WriteSectors(1, GPTPath);
|
||||
}
|
||||
|
||||
internal static async Task RewriteParts(string PartPath)
|
||||
{
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
Notifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
|
||||
foreach (var part in Directory.EnumerateFiles(PartPath))
|
||||
{
|
||||
var partname = part.Split('\\').Last().Replace(".img", "");
|
||||
try
|
||||
{
|
||||
LogFile.Log($"Writing {partname} to the device.", LogType.ConsoleOnly);
|
||||
|
||||
LogFile.Log("", LogType.ConsoleOnly);
|
||||
|
||||
MassStorage.RestorePartition(part, partname, (v, t) => LogFile.Log("Progress: " + v + "%", LogType.ConsoleOnly));
|
||||
LogFile.Log("", LogType.ConsoleOnly);
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogFile.Log("", LogType.ConsoleOnly);
|
||||
LogFile.Log($"Failed writing {partname} to the device.", LogType.ConsoleOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void PatchImg(string dump)
|
||||
{
|
||||
using var fil = File.Open(dump, FileMode.Open);
|
||||
byte[] gptbuffer = new byte[0x4200];
|
||||
|
||||
fil.Seek(0x200, SeekOrigin.Begin);
|
||||
fil.Read(gptbuffer, 0, 0x4200);
|
||||
|
||||
uint BackupLBA = ByteOperations.ReadUInt32(gptbuffer, 0x20);
|
||||
uint LastUsableLBA = ByteOperations.ReadUInt32(gptbuffer, 0x30);
|
||||
|
||||
LogFile.Log("Previous BackupLBA: " + BackupLBA, LogType.ConsoleOnly);
|
||||
LogFile.Log("Previous LastUsableLBA: " + LastUsableLBA, LogType.ConsoleOnly);
|
||||
|
||||
const uint NewBackupLBA = 62078975u;
|
||||
const uint NewLastUsableLBA = 62078942u;
|
||||
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x20, NewBackupLBA);
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x30, NewLastUsableLBA);
|
||||
|
||||
uint HeaderSize = ByteOperations.ReadUInt32(gptbuffer, 0x0C);
|
||||
uint PrevCRC = ByteOperations.ReadUInt32(gptbuffer, 0x10);
|
||||
|
||||
LogFile.Log("Previous CRC: " + PrevCRC, LogType.ConsoleOnly);
|
||||
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x10, 0);
|
||||
uint NewCRC = ByteOperations.CRC32(gptbuffer, 0, HeaderSize);
|
||||
|
||||
LogFile.Log("New CRC: " + NewCRC, LogType.ConsoleOnly);
|
||||
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x10, NewCRC);
|
||||
|
||||
LogFile.Log("Writing", LogType.ConsoleOnly);
|
||||
|
||||
fil.Seek(0x200, SeekOrigin.Begin);
|
||||
fil.Write(gptbuffer, 0, 0x4200);
|
||||
|
||||
LogFile.Log("Done!", LogType.ConsoleOnly);
|
||||
}
|
||||
|
||||
internal static async Task TestProgrammer(System.Threading.SynchronizationContext UIContext, string ProgrammerPath)
|
||||
{
|
||||
LogFile.BeginAction("TestProgrammer");
|
||||
try
|
||||
{
|
||||
LogFile.Log("Starting Firehose Test", LogType.FileAndConsole);
|
||||
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
LogFile.Log("Phone found in emergency mode", LogType.FileAndConsole);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Phone needs to be switched to emergency mode.", LogType.FileAndConsole);
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Qualcomm_Download);
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
throw new WPinternalsException("Switching mode failed.", "Could not switch the phone to Qualcomm Emergency 9008.");
|
||||
}
|
||||
|
||||
LogFile.Log("Phone is in emergency mode.", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
// Send and start programmer
|
||||
QualcommSerial Serial = (QualcommSerial)Notifier.CurrentModel;
|
||||
QualcommSahara Sahara = new(Serial);
|
||||
|
||||
if (await Sahara.Reset(ProgrammerPath))
|
||||
{
|
||||
LogFile.Log("Emergency programmer test succeeded", LogType.FileAndConsole);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Emergency programmer test failed", LogType.FileAndConsole);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogFile.EndAction("TestProgrammer");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal static class TestCode
|
||||
{
|
||||
internal static async Task Test(System.Threading.SynchronizationContext UIContext)
|
||||
{
|
||||
// To avoid warnings when there is no code here.
|
||||
await Task.Run(() => { });
|
||||
|
||||
// PhoneNotifierViewModel Notifier = new PhoneNotifierViewModel();
|
||||
// Notifier.Start();
|
||||
// await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
// MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
}
|
||||
|
||||
internal static async Task RecoverBadGPT(string GPTPath, string LoadersPath)
|
||||
{
|
||||
byte[] GPT = File.ReadAllBytes(GPTPath);
|
||||
|
||||
PhoneNotifierViewModel PhoneNotifier = new();
|
||||
PhoneNotifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(PhoneNotifier, PhoneInterfaces.Qualcomm_Download);
|
||||
|
||||
byte[] RootKeyHash = null;
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
QualcommDownload Download2 = new((QualcommSerial)PhoneNotifier.CurrentModel);
|
||||
RootKeyHash = Download2.GetRKH();
|
||||
}
|
||||
|
||||
List<QualcommPartition> PossibleLoaders = null;
|
||||
if (PhoneNotifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
try
|
||||
{
|
||||
PossibleLoaders = QualcommLoaders.GetPossibleLoadersForRootKeyHash(LoadersPath, RootKeyHash);
|
||||
if (PossibleLoaders.Count == 0)
|
||||
{
|
||||
throw new Exception("Error: No matching loaders found for RootKeyHash.");
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
throw new Exception("Error: Unexpected error during scanning for loaders.");
|
||||
}
|
||||
}
|
||||
|
||||
QualcommSerial Serial = (QualcommSerial)PhoneNotifier.CurrentModel;
|
||||
QualcommDownload Download = new(Serial);
|
||||
if (Download.IsAlive())
|
||||
{
|
||||
int Attempt = 1;
|
||||
bool Result = false;
|
||||
foreach (QualcommPartition Loader in PossibleLoaders)
|
||||
{
|
||||
LogFile.Log("Attempt " + Attempt.ToString(), LogType.ConsoleOnly);
|
||||
|
||||
try
|
||||
{
|
||||
Download.SendToPhoneMemory(0x2A000000, Loader.Binary);
|
||||
Download.StartBootloader(0x2A000000);
|
||||
Result = true;
|
||||
LogFile.Log("Loader sent successfully", LogType.ConsoleOnly);
|
||||
}
|
||||
catch { }
|
||||
|
||||
if (Result)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Attempt++;
|
||||
}
|
||||
Serial.Close();
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
LogFile.Log("Loader failed", LogType.ConsoleOnly);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Failed to communicate to Qualcomm Emergency Download mode", LogType.ConsoleOnly);
|
||||
throw new BadConnectionException();
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
await PhoneNotifier.WaitForArrival();
|
||||
}
|
||||
|
||||
if (PhoneNotifier.CurrentInterface != PhoneInterfaces.Qualcomm_Flash)
|
||||
{
|
||||
throw new WPinternalsException("Phone failed to switch to emergency flash mode.");
|
||||
}
|
||||
|
||||
// Flash bootloader
|
||||
QualcommSerial Serial2 = (QualcommSerial)PhoneNotifier.CurrentModel;
|
||||
Serial2.EncodeCommands = false;
|
||||
|
||||
QualcommFlasher Flasher = new(Serial2);
|
||||
|
||||
Flasher.Hello();
|
||||
Flasher.SetSecurityMode(0);
|
||||
Flasher.OpenPartition(0x21);
|
||||
|
||||
LogFile.Log("Partition opened.", LogType.ConsoleOnly);
|
||||
|
||||
LogFile.Log("Flash GPT at 0x" + ((UInt32)0x200).ToString("X8"), LogType.ConsoleOnly);
|
||||
Flasher.Flash(0x200, GPT, 0, 0x41FF); // Bad bounds-check in the flash-loader prohibits to write the last byte.
|
||||
|
||||
Flasher.ClosePartition();
|
||||
|
||||
LogFile.Log("Partition closed. Flashing ready. Rebooting.");
|
||||
|
||||
Flasher.Reboot();
|
||||
|
||||
Flasher.CloseSerial();
|
||||
}
|
||||
|
||||
internal static async Task RewriteGPT(string GPTPath)
|
||||
{
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
Notifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
|
||||
LogFile.Log("Writing GPT to the device.", LogType.ConsoleOnly);
|
||||
MassStorage.WriteSectors(1, GPTPath);
|
||||
}
|
||||
|
||||
internal static async Task RewriteMBRGPT()
|
||||
{
|
||||
FFU FFU = new(@"E:\Device Backups\Alpha\9200_1230.0025.9200.9825\RX100_9825.ffu");
|
||||
const string GPTPath = @"E:\Device Backups\Alpha\9200_1230.0025.9200.9825\CorrectGPT.bin";
|
||||
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
Notifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
|
||||
byte[] MBR = FFU.GetSectors(0, 1);
|
||||
LogFile.Log("Writing MBR to the device.", LogType.ConsoleOnly);
|
||||
MassStorage.WriteSectors(0, MBR);
|
||||
|
||||
LogFile.Log("Writing GPT to the device.", LogType.ConsoleOnly);
|
||||
MassStorage.WriteSectors(1, GPTPath);
|
||||
}
|
||||
|
||||
internal static async Task RewriteParts(string PartPath)
|
||||
{
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
Notifier.Start();
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_MassStorage);
|
||||
MassStorage MassStorage = (MassStorage)Notifier.CurrentModel;
|
||||
|
||||
foreach (var part in Directory.EnumerateFiles(PartPath))
|
||||
{
|
||||
var partname = part.Split('\\').Last().Replace(".img", "");
|
||||
try
|
||||
{
|
||||
LogFile.Log($"Writing {partname} to the device.", LogType.ConsoleOnly);
|
||||
|
||||
LogFile.Log("", LogType.ConsoleOnly);
|
||||
|
||||
MassStorage.RestorePartition(part, partname, (v, t) => LogFile.Log("Progress: " + v + "%", LogType.ConsoleOnly));
|
||||
LogFile.Log("", LogType.ConsoleOnly);
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogFile.Log("", LogType.ConsoleOnly);
|
||||
LogFile.Log($"Failed writing {partname} to the device.", LogType.ConsoleOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void PatchImg(string dump)
|
||||
{
|
||||
using var fil = File.Open(dump, FileMode.Open);
|
||||
byte[] gptbuffer = new byte[0x4200];
|
||||
|
||||
fil.Seek(0x200, SeekOrigin.Begin);
|
||||
fil.Read(gptbuffer, 0, 0x4200);
|
||||
|
||||
uint BackupLBA = ByteOperations.ReadUInt32(gptbuffer, 0x20);
|
||||
uint LastUsableLBA = ByteOperations.ReadUInt32(gptbuffer, 0x30);
|
||||
|
||||
LogFile.Log("Previous BackupLBA: " + BackupLBA, LogType.ConsoleOnly);
|
||||
LogFile.Log("Previous LastUsableLBA: " + LastUsableLBA, LogType.ConsoleOnly);
|
||||
|
||||
const uint NewBackupLBA = 62078975u;
|
||||
const uint NewLastUsableLBA = 62078942u;
|
||||
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x20, NewBackupLBA);
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x30, NewLastUsableLBA);
|
||||
|
||||
uint HeaderSize = ByteOperations.ReadUInt32(gptbuffer, 0x0C);
|
||||
uint PrevCRC = ByteOperations.ReadUInt32(gptbuffer, 0x10);
|
||||
|
||||
LogFile.Log("Previous CRC: " + PrevCRC, LogType.ConsoleOnly);
|
||||
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x10, 0);
|
||||
uint NewCRC = ByteOperations.CRC32(gptbuffer, 0, HeaderSize);
|
||||
|
||||
LogFile.Log("New CRC: " + NewCRC, LogType.ConsoleOnly);
|
||||
|
||||
ByteOperations.WriteUInt32(gptbuffer, 0x10, NewCRC);
|
||||
|
||||
LogFile.Log("Writing", LogType.ConsoleOnly);
|
||||
|
||||
fil.Seek(0x200, SeekOrigin.Begin);
|
||||
fil.Write(gptbuffer, 0, 0x4200);
|
||||
|
||||
LogFile.Log("Done!", LogType.ConsoleOnly);
|
||||
}
|
||||
|
||||
internal static async Task TestProgrammer(System.Threading.SynchronizationContext UIContext, string ProgrammerPath)
|
||||
{
|
||||
LogFile.BeginAction("TestProgrammer");
|
||||
try
|
||||
{
|
||||
LogFile.Log("Starting Firehose Test", LogType.FileAndConsole);
|
||||
|
||||
PhoneNotifierViewModel Notifier = new();
|
||||
UIContext.Send(s => Notifier.Start(), null);
|
||||
if (Notifier.CurrentInterface == PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
LogFile.Log("Phone found in emergency mode", LogType.FileAndConsole);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Phone needs to be switched to emergency mode.", LogType.FileAndConsole);
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Lumia_Flash);
|
||||
PhoneInfo Info = ((NokiaFlashModel)Notifier.CurrentModel).ReadPhoneInfo();
|
||||
Info.Log(LogType.ConsoleOnly);
|
||||
await SwitchModeViewModel.SwitchTo(Notifier, PhoneInterfaces.Qualcomm_Download);
|
||||
if (Notifier.CurrentInterface != PhoneInterfaces.Qualcomm_Download)
|
||||
{
|
||||
throw new WPinternalsException("Switching mode failed.", "Could not switch the phone to Qualcomm Emergency 9008.");
|
||||
}
|
||||
|
||||
LogFile.Log("Phone is in emergency mode.", LogType.FileAndConsole);
|
||||
}
|
||||
|
||||
// Send and start programmer
|
||||
QualcommSerial Serial = (QualcommSerial)Notifier.CurrentModel;
|
||||
QualcommSahara Sahara = new(Serial);
|
||||
QualcommFirehose Firehose = new(Serial);
|
||||
|
||||
if (await Sahara.LoadProgrammer(ProgrammerPath) && await Firehose.Reset())
|
||||
{
|
||||
LogFile.Log("Emergency programmer test succeeded", LogType.FileAndConsole);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.Log("Emergency programmer test failed", LogType.FileAndConsole);
|
||||
}
|
||||
}
|
||||
catch (Exception Ex)
|
||||
{
|
||||
LogFile.LogException(Ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LogFile.EndAction("TestProgrammer");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +1,59 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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
|
||||
{
|
||||
internal class AboutViewModel : ContextViewModel
|
||||
{
|
||||
internal AboutViewModel() : base() { }
|
||||
|
||||
public int MajorVersion
|
||||
// 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
|
||||
{
|
||||
internal class AboutViewModel : ContextViewModel
|
||||
{
|
||||
internal AboutViewModel() : base() { }
|
||||
|
||||
public int MajorVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Major;
|
||||
}
|
||||
}
|
||||
|
||||
public int MinorVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Minor;
|
||||
}
|
||||
}
|
||||
|
||||
public int BuildVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Major;
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Build;
|
||||
}
|
||||
}
|
||||
|
||||
public int MinorVersion
|
||||
}
|
||||
|
||||
public int RevisionVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Minor;
|
||||
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.Revision;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,237 +1,237 @@
|
||||
// Copyright (c) 2018, Rene Lergner - wpinternals.net - @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.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class BackupTargetSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action<string, string, string> BackupCallback;
|
||||
private readonly Action<string> BackupArchiveCallback;
|
||||
private readonly Action<string> BackupArchiveProvisioningCallback;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
|
||||
internal BackupTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action<string> BackupArchiveCallback, Action<string, string, string> BackupCallback, Action<string> BackupArchiveProvisioningCallback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.BackupCallback = BackupCallback;
|
||||
this.BackupArchiveCallback = BackupArchiveCallback;
|
||||
this.BackupArchiveProvisioningCallback = BackupArchiveProvisioningCallback;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
|
||||
this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
this.PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private string _ArchivePath;
|
||||
public string ArchivePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ArchivePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _ArchivePath)
|
||||
{
|
||||
_ArchivePath = value;
|
||||
OnPropertyChanged(nameof(ArchivePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _EFIESPPath;
|
||||
public string EFIESPPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _EFIESPPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _EFIESPPath)
|
||||
{
|
||||
_EFIESPPath = value;
|
||||
OnPropertyChanged(nameof(EFIESPPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MainOSPath;
|
||||
public string MainOSPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MainOSPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MainOSPath)
|
||||
{
|
||||
_MainOSPath = value;
|
||||
OnPropertyChanged(nameof(MainOSPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _DataPath;
|
||||
public string DataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DataPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _DataPath)
|
||||
{
|
||||
_DataPath = value;
|
||||
OnPropertyChanged(nameof(DataPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _ArchiveProvisioningPath;
|
||||
public string ArchiveProvisioningPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ArchiveProvisioningPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _ArchiveProvisioningPath)
|
||||
{
|
||||
_ArchiveProvisioningPath = value;
|
||||
OnPropertyChanged(nameof(ArchiveProvisioningPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneDisconnected;
|
||||
public bool IsPhoneDisconnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneDisconnected;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneDisconnected)
|
||||
{
|
||||
_IsPhoneDisconnected = value;
|
||||
OnPropertyChanged(nameof(IsPhoneDisconnected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInMassStorage;
|
||||
public bool IsPhoneInMassStorage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInMassStorage;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInMassStorage)
|
||||
{
|
||||
_IsPhoneInMassStorage = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInMassStorage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInOtherMode;
|
||||
public bool IsPhoneInOtherMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInOtherMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInOtherMode)
|
||||
{
|
||||
_IsPhoneInOtherMode = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInOtherMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _BackupArchiveCommand;
|
||||
public DelegateCommand BackupArchiveCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupArchiveCommand ??= new DelegateCommand(() => BackupArchiveCallback(ArchivePath), () => (ArchivePath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _BackupCommand;
|
||||
public DelegateCommand BackupCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupCommand ??= new DelegateCommand(() => BackupCallback(EFIESPPath, MainOSPath, DataPath), () => ((EFIESPPath != null) || (MainOSPath != null) || (DataPath != null)) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _BackupArchiveProvisioningCommand;
|
||||
public DelegateCommand BackupArchiveProvisioningCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupArchiveProvisioningCommand ??= new DelegateCommand(() => BackupArchiveProvisioningCallback(ArchiveProvisioningPath), () => (ArchiveProvisioningPath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
~BackupTargetSelectionViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
IsPhoneDisconnected = PhoneNotifier.CurrentInterface == null;
|
||||
IsPhoneInMassStorage = PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_MassStorage;
|
||||
IsPhoneInOtherMode = !IsPhoneDisconnected && !IsPhoneInMassStorage;
|
||||
BackupCommand.RaiseCanExecuteChanged();
|
||||
BackupArchiveCommand.RaiseCanExecuteChanged();
|
||||
BackupArchiveProvisioningCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
// 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.Threading;
|
||||
|
||||
namespace WPinternals
|
||||
{
|
||||
internal class BackupTargetSelectionViewModel : ContextViewModel
|
||||
{
|
||||
private readonly PhoneNotifierViewModel PhoneNotifier;
|
||||
private readonly Action<string, string, string> BackupCallback;
|
||||
private readonly Action<string> BackupArchiveCallback;
|
||||
private readonly Action<string> BackupArchiveProvisioningCallback;
|
||||
internal Action SwitchToUnlockBoot;
|
||||
|
||||
internal BackupTargetSelectionViewModel(PhoneNotifierViewModel PhoneNotifier, Action SwitchToUnlockBoot, Action<string> BackupArchiveCallback, Action<string, string, string> BackupCallback, Action<string> BackupArchiveProvisioningCallback)
|
||||
: base()
|
||||
{
|
||||
this.PhoneNotifier = PhoneNotifier;
|
||||
this.BackupCallback = BackupCallback;
|
||||
this.BackupArchiveCallback = BackupArchiveCallback;
|
||||
this.BackupArchiveProvisioningCallback = BackupArchiveProvisioningCallback;
|
||||
this.SwitchToUnlockBoot = SwitchToUnlockBoot;
|
||||
|
||||
this.PhoneNotifier.NewDeviceArrived += NewDeviceArrived;
|
||||
this.PhoneNotifier.DeviceRemoved += DeviceRemoved;
|
||||
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private string _ArchivePath;
|
||||
public string ArchivePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ArchivePath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _ArchivePath)
|
||||
{
|
||||
_ArchivePath = value;
|
||||
OnPropertyChanged(nameof(ArchivePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _EFIESPPath;
|
||||
public string EFIESPPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _EFIESPPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _EFIESPPath)
|
||||
{
|
||||
_EFIESPPath = value;
|
||||
OnPropertyChanged(nameof(EFIESPPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _MainOSPath;
|
||||
public string MainOSPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _MainOSPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _MainOSPath)
|
||||
{
|
||||
_MainOSPath = value;
|
||||
OnPropertyChanged(nameof(MainOSPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _DataPath;
|
||||
public string DataPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _DataPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _DataPath)
|
||||
{
|
||||
_DataPath = value;
|
||||
OnPropertyChanged(nameof(DataPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _ArchiveProvisioningPath;
|
||||
public string ArchiveProvisioningPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _ArchiveProvisioningPath;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _ArchiveProvisioningPath)
|
||||
{
|
||||
_ArchiveProvisioningPath = value;
|
||||
OnPropertyChanged(nameof(ArchiveProvisioningPath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneDisconnected;
|
||||
public bool IsPhoneDisconnected
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneDisconnected;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneDisconnected)
|
||||
{
|
||||
_IsPhoneDisconnected = value;
|
||||
OnPropertyChanged(nameof(IsPhoneDisconnected));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInMassStorage;
|
||||
public bool IsPhoneInMassStorage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInMassStorage;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInMassStorage)
|
||||
{
|
||||
_IsPhoneInMassStorage = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInMassStorage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _IsPhoneInOtherMode;
|
||||
public bool IsPhoneInOtherMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return _IsPhoneInOtherMode;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != _IsPhoneInOtherMode)
|
||||
{
|
||||
_IsPhoneInOtherMode = value;
|
||||
OnPropertyChanged(nameof(IsPhoneInOtherMode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _BackupArchiveCommand;
|
||||
public DelegateCommand BackupArchiveCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupArchiveCommand ??= new DelegateCommand(() => BackupArchiveCallback(ArchivePath), () => (ArchivePath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _BackupCommand;
|
||||
public DelegateCommand BackupCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupCommand ??= new DelegateCommand(() => BackupCallback(EFIESPPath, MainOSPath, DataPath), () => ((EFIESPPath != null) || (MainOSPath != null) || (DataPath != null)) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
private DelegateCommand _BackupArchiveProvisioningCommand;
|
||||
public DelegateCommand BackupArchiveProvisioningCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return _BackupArchiveProvisioningCommand ??= new DelegateCommand(() => BackupArchiveProvisioningCallback(ArchiveProvisioningPath), () => (ArchiveProvisioningPath != null) && (PhoneNotifier.CurrentInterface != null));
|
||||
}
|
||||
}
|
||||
|
||||
~BackupTargetSelectionViewModel()
|
||||
{
|
||||
PhoneNotifier.NewDeviceArrived -= NewDeviceArrived;
|
||||
}
|
||||
|
||||
private void NewDeviceArrived(ArrivalEventArgs Args)
|
||||
{
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
private void DeviceRemoved()
|
||||
{
|
||||
new Thread(() => EvaluateViewState()).Start();
|
||||
}
|
||||
|
||||
internal override void EvaluateViewState()
|
||||
{
|
||||
IsPhoneDisconnected = PhoneNotifier.CurrentInterface == null;
|
||||
IsPhoneInMassStorage = PhoneNotifier.CurrentInterface == PhoneInterfaces.Lumia_MassStorage;
|
||||
IsPhoneInOtherMode = !IsPhoneDisconnected && !IsPhoneInMassStorage;
|
||||
BackupCommand.RaiseCanExecuteChanged();
|
||||
BackupArchiveCommand.RaiseCanExecuteChanged();
|
||||
BackupArchiveProvisioningCommand.RaiseCanExecuteChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||